2023-02-11 17:59:15 +00:00
|
|
|
/*
|
|
|
|
Copyright 2020-2023, Savanni D'Gerinel <savanni@luminescent-dreams.com>
|
|
|
|
|
|
|
|
This file is part of the Luminescent Dreams Tools.
|
|
|
|
|
|
|
|
Luminescent Dreams Tools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
Luminescent Dreams Tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with Lumeto. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2022-04-20 13:01:39 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate serde_derive;
|
|
|
|
|
|
|
|
extern crate chrono;
|
|
|
|
extern crate chrono_tz;
|
|
|
|
extern crate dimensioned;
|
|
|
|
extern crate emseries;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2023-12-26 20:37:53 +00:00
|
|
|
use chrono::{format::Fixed, prelude::*};
|
2022-04-20 13:01:39 +00:00
|
|
|
use chrono_tz::Etc::UTC;
|
2023-10-05 15:19:55 +00:00
|
|
|
use dimensioned::si::{Kilogram, Meter, Second, M, S};
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
use emseries::*;
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
struct Distance(Meter<f64>);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
struct Duration(Second<f64>);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
struct BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: DateTime<FixedOffset>,
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance,
|
|
|
|
duration: Duration,
|
|
|
|
comments: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Recordable for BikeTrip {
|
2023-05-25 03:59:06 +00:00
|
|
|
fn timestamp(&self) -> Timestamp {
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(self.datetime.clone())
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
fn tags(&self) -> Vec<String> {
|
|
|
|
Vec::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk_trips() -> [BikeTrip; 5] {
|
|
|
|
[
|
|
|
|
BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: UTC
|
|
|
|
.with_ymd_and_hms(2011, 10, 29, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance(58741.055 * M),
|
|
|
|
duration: Duration(11040.0 * S),
|
|
|
|
comments: String::from("long time ago"),
|
|
|
|
},
|
|
|
|
BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: UTC
|
|
|
|
.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance(17702.0 * M),
|
|
|
|
duration: Duration(2880.0 * S),
|
|
|
|
comments: String::from("day 2"),
|
|
|
|
},
|
|
|
|
BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: UTC
|
|
|
|
.with_ymd_and_hms(2011, 11, 02, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance(41842.945 * M),
|
|
|
|
duration: Duration(7020.0 * S),
|
|
|
|
comments: String::from("Do Some Distance!"),
|
|
|
|
},
|
|
|
|
BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: UTC
|
|
|
|
.with_ymd_and_hms(2011, 11, 04, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance(34600.895 * M),
|
|
|
|
duration: Duration(5580.0 * S),
|
|
|
|
comments: String::from("I did a lot of distance back then"),
|
|
|
|
},
|
|
|
|
BikeTrip {
|
2023-12-26 20:37:53 +00:00
|
|
|
datetime: UTC
|
|
|
|
.with_ymd_and_hms(2011, 11, 05, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
2022-04-20 13:01:39 +00:00
|
|
|
distance: Distance(6437.376 * M),
|
|
|
|
duration: Duration(960.0 * S),
|
|
|
|
comments: String::from("day 5"),
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_test<T>(test: T) -> ()
|
|
|
|
where
|
|
|
|
T: FnOnce(tempfile::TempPath),
|
|
|
|
{
|
|
|
|
let tmp_file = tempfile::NamedTempFile::new().expect("temporary path created");
|
|
|
|
let tmp_path = tmp_file.into_temp_path();
|
|
|
|
test(tmp_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run<T>(test: T) -> ()
|
|
|
|
where
|
|
|
|
T: FnOnce(Series<BikeTrip>),
|
|
|
|
{
|
|
|
|
let tmp_file = tempfile::NamedTempFile::new().expect("temporary path created");
|
|
|
|
let tmp_path = tmp_file.into_temp_path();
|
2023-12-07 04:32:33 +00:00
|
|
|
let ts: Series<BikeTrip> =
|
|
|
|
Series::open(&tmp_path).expect("the time series should open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
test(ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_add_and_retrieve_entries() {
|
|
|
|
run(|mut series| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
let uuid = series
|
|
|
|
.put(trips[0].clone())
|
|
|
|
.expect("expect a successful put");
|
|
|
|
let record_res = series.get(&uuid);
|
|
|
|
|
|
|
|
for trip in &trips[1..=4] {
|
|
|
|
series.put(trip.clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
|
|
|
|
match record_res {
|
|
|
|
None => assert!(false, "There should have been a value here"),
|
|
|
|
Some(tr) => {
|
|
|
|
assert_eq!(
|
|
|
|
tr.timestamp(),
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 29, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap())
|
|
|
|
)
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(tr.data.duration, Duration(11040.0 * S));
|
|
|
|
assert_eq!(tr.data.comments, String::from("long time ago"));
|
|
|
|
assert_eq!(tr.data, trips[0]);
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_search_for_an_entry_with_exact_time() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
for trip in &trips[0..=4] {
|
|
|
|
ts.put(trip.clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
|
2023-12-27 21:13:47 +00:00
|
|
|
let v: Vec<&Record<BikeTrip>> = ts
|
2023-12-26 20:37:53 +00:00
|
|
|
.search(exact_time(Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
)))
|
2022-04-20 13:01:39 +00:00
|
|
|
.collect();
|
|
|
|
assert_eq!(v.len(), 1);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(v[0].data, trips[1]);
|
2022-04-20 13:01:39 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_get_entries_in_time_range() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
for trip in &trips[0..=4] {
|
|
|
|
ts.put(trip.clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
|
2023-12-27 21:13:47 +00:00
|
|
|
let v: Vec<&Record<BikeTrip>> = ts.search_sorted(
|
2022-04-20 13:01:39 +00:00
|
|
|
time_range(
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 11, 04, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
|
|
|
),
|
2023-12-27 21:13:47 +00:00
|
|
|
|l, r| l.timestamp().cmp(&r.timestamp()),
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
|
|
|
assert_eq!(v.len(), 3);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(v[0].data, trips[1]);
|
|
|
|
assert_eq!(v[1].data, trips[2]);
|
|
|
|
assert_eq!(v[2].data, trips[3]);
|
2022-04-20 13:01:39 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn persists_and_reads_an_entry() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
for trip in &trips[0..=4] {
|
|
|
|
ts.put(trip.clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2023-12-27 21:13:47 +00:00
|
|
|
let v: Vec<&Record<BikeTrip>> = ts.search_sorted(
|
2022-04-20 13:01:39 +00:00
|
|
|
time_range(
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 11, 04, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
|
|
|
),
|
2023-12-27 21:13:47 +00:00
|
|
|
|l, r| l.timestamp().cmp(&r.timestamp()),
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
|
|
|
assert_eq!(v.len(), 3);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(v[0].data, trips[1]);
|
|
|
|
assert_eq!(v[1].data, trips[2]);
|
|
|
|
assert_eq!(v[2].data, trips[3]);
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_write_to_existing_file() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
for trip in &trips[0..=2] {
|
|
|
|
ts.put(trip.clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2023-12-27 21:13:47 +00:00
|
|
|
let v: Vec<&Record<BikeTrip>> = ts.search_sorted(
|
2022-04-20 13:01:39 +00:00
|
|
|
time_range(
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 11, 04, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
)
|
|
|
|
.into(),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
|
|
|
),
|
2023-12-27 21:13:47 +00:00
|
|
|
|l, r| l.timestamp().cmp(&r.timestamp()),
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
|
|
|
assert_eq!(v.len(), 2);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(v[0].data, trips[1]);
|
|
|
|
assert_eq!(v[1].data, trips[2]);
|
2022-04-20 13:01:39 +00:00
|
|
|
ts.put(trips[3].clone()).expect("expect a successful put");
|
|
|
|
ts.put(trips[4].clone()).expect("expect a successful put");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2023-12-27 21:13:47 +00:00
|
|
|
let v: Vec<&Record<BikeTrip>> = ts.search_sorted(
|
2022-04-20 13:01:39 +00:00
|
|
|
time_range(
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 10, 31, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 11, 05, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
),
|
2022-04-20 13:01:39 +00:00
|
|
|
true,
|
|
|
|
),
|
2023-12-27 21:13:47 +00:00
|
|
|
|l, r| l.timestamp().cmp(&r.timestamp()),
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
|
|
|
assert_eq!(v.len(), 4);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(v[0].data, trips[1]);
|
|
|
|
assert_eq!(v[1].data, trips[2]);
|
|
|
|
assert_eq!(v[2].data, trips[3]);
|
|
|
|
assert_eq!(v[3].data, trips[4]);
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_overwrite_existing_entry() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
ts.put(trips[0].clone()).expect("expect a successful put");
|
|
|
|
ts.put(trips[1].clone()).expect("expect a successful put");
|
|
|
|
let trip_id = ts.put(trips[2].clone()).expect("expect a successful put");
|
|
|
|
|
|
|
|
match ts.get(&trip_id) {
|
|
|
|
None => assert!(false, "record not found"),
|
|
|
|
Some(mut trip) => {
|
2023-12-27 21:13:47 +00:00
|
|
|
trip.data.distance = Distance(50000.0 * M);
|
|
|
|
ts.update(trip).expect("expect record to update");
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match ts.get(&trip_id) {
|
|
|
|
None => assert!(false, "record not found"),
|
|
|
|
Some(trip) => {
|
|
|
|
assert_eq!(
|
2023-12-27 21:13:47 +00:00
|
|
|
trip.data.datetime,
|
2023-12-26 20:37:53 +00:00
|
|
|
UTC.with_ymd_and_hms(2011, 11, 02, 0, 0, 0).unwrap()
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(trip.data.distance, Distance(50000.0 * M));
|
|
|
|
assert_eq!(trip.data.duration, Duration(7020.0 * S));
|
|
|
|
assert_eq!(trip.data.comments, String::from("Do Some Distance!"));
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn record_overwrites_get_persisted() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
|
|
|
ts.put(trips[0].clone()).expect("expect a successful put");
|
|
|
|
ts.put(trips[1].clone()).expect("expect a successful put");
|
|
|
|
let trip_id = ts.put(trips[2].clone()).expect("expect a successful put");
|
|
|
|
|
|
|
|
match ts.get(&trip_id) {
|
|
|
|
None => assert!(false, "record not found"),
|
|
|
|
Some(mut trip) => {
|
2023-12-27 21:13:47 +00:00
|
|
|
trip.data.distance = Distance(50000.0 * M);
|
|
|
|
ts.update(trip).expect("expect record to update");
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
|
2023-12-27 21:13:47 +00:00
|
|
|
let trips: Vec<&Record<BikeTrip>> = ts.records().collect();
|
2022-04-20 13:01:39 +00:00
|
|
|
assert_eq!(trips.len(), 3);
|
|
|
|
|
2023-12-27 21:13:47 +00:00
|
|
|
let trips: Vec<&Record<BikeTrip>> = ts
|
2023-12-26 20:37:53 +00:00
|
|
|
.search(exact_time(Timestamp::DateTime(
|
|
|
|
UTC.with_ymd_and_hms(2011, 11, 02, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap()),
|
|
|
|
)))
|
2022-04-20 13:01:39 +00:00
|
|
|
.collect();
|
|
|
|
assert_eq!(trips.len(), 1);
|
|
|
|
assert_eq!(
|
2023-12-27 21:13:47 +00:00
|
|
|
trips[0].data.datetime,
|
2023-12-26 20:37:53 +00:00
|
|
|
UTC.with_ymd_and_hms(2011, 11, 02, 0, 0, 0)
|
|
|
|
.unwrap()
|
|
|
|
.with_timezone(&FixedOffset::east_opt(0).unwrap())
|
2022-04-20 13:01:39 +00:00
|
|
|
);
|
2023-12-27 21:13:47 +00:00
|
|
|
assert_eq!(trips[0].data.distance, Distance(50000.0 * M));
|
|
|
|
assert_eq!(trips[0].data.duration, Duration(7020.0 * S));
|
|
|
|
assert_eq!(trips[0].data.comments, String::from("Do Some Distance!"));
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
pub fn can_delete_an_entry() {
|
|
|
|
run_test(|path| {
|
|
|
|
let trips = mk_trips();
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let mut ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2022-04-20 13:01:39 +00:00
|
|
|
let trip_id = ts.put(trips[0].clone()).expect("expect a successful put");
|
|
|
|
ts.put(trips[1].clone()).expect("expect a successful put");
|
|
|
|
ts.put(trips[2].clone()).expect("expect a successful put");
|
|
|
|
ts.delete(&trip_id).expect("successful delete");
|
|
|
|
|
2023-12-27 21:13:47 +00:00
|
|
|
let recs: Vec<&Record<BikeTrip>> = ts.records().collect();
|
2022-04-20 13:01:39 +00:00
|
|
|
assert_eq!(recs.len(), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2023-12-07 04:32:33 +00:00
|
|
|
let ts: Series<BikeTrip> =
|
|
|
|
Series::open(&path).expect("expect the time series to open correctly");
|
2023-12-27 21:13:47 +00:00
|
|
|
let recs: Vec<&Record<BikeTrip>> = ts.records().collect();
|
2022-04-20 13:01:39 +00:00
|
|
|
assert_eq!(recs.len(), 2);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
pub struct Weight(Kilogram<f64>);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
|
|
|
|
pub struct WeightRecord {
|
2023-05-25 03:59:06 +00:00
|
|
|
pub date: chrono::NaiveDate,
|
2022-04-20 13:01:39 +00:00
|
|
|
pub weight: Weight,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Recordable for WeightRecord {
|
2023-05-25 03:59:06 +00:00
|
|
|
fn timestamp(&self) -> Timestamp {
|
2023-12-26 20:37:53 +00:00
|
|
|
Timestamp::Date(self.date)
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn tags(&self) -> Vec<String> {
|
|
|
|
Vec::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-25 03:59:06 +00:00
|
|
|
/*
|
2022-04-20 13:01:39 +00:00
|
|
|
#[test]
|
|
|
|
pub fn legacy_file_load() {
|
|
|
|
let ts: Series<WeightRecord> =
|
|
|
|
Series::open("fixtures/weight.json").expect("legacy series should open correctly");
|
|
|
|
|
|
|
|
let uid = "3330c5b0-783f-4919-b2c4-8169c38f65ff"
|
|
|
|
.parse()
|
|
|
|
.expect("something is wrong with this ID");
|
|
|
|
let rec = ts.get(&uid);
|
|
|
|
match rec {
|
|
|
|
None => assert!(false, "no record found"),
|
|
|
|
Some(rec) => assert_eq!(rec.weight, Weight(77.79109 * KG)),
|
|
|
|
}
|
|
|
|
}
|
2023-05-25 03:59:06 +00:00
|
|
|
*/
|
2022-04-20 13:01:39 +00:00
|
|
|
}
|