# dataseries [![License:MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![build](https://github.com/cboudereau/dataseries/workflows/build-rs/badge.svg?branch=main&event=push)](https://github.com/cboudereau/dataseries/actions/workflows/build-rs.yml?query=event%3Apush+branch%3Amain) [![codecov](https://codecov.io/gh/cboudereau/dataseries/branch/main/graph/badge.svg?token=UFSTKQG9FY&flag=rust)](https://app.codecov.io/gh/cboudereau/dataseries/tree/main/rust) [![docs.rs](https://docs.rs/dataseries/badge.svg)](https://docs.rs/dataseries) [![crates.io](https://img.shields.io/crates/v/dataseries.svg)](https://crates.io/crates/dataseries) [![crates.io (recent)](https://img.shields.io/crates/dr/dataseries)](https://crates.io/crates/dataseries) data-series functions support for data-series and time-series. ## functions ### union Continuous time series union between 2 series. Left and right data can be absent (left and right only cases). ``` 1 3 10 20 Left: |-----|-----|------------------|- 130 120 95 160 12 15 Right: |------|-------- 105 110 1 3 10 12 15 20 Expected: |-----|-----|----|------|------|- 130,∅ 120,∅ 95,∅ 95,105 95,110 160,110 ``` ### examples #### simple A simple example of ```union``` between 2 timeseries #### intersection An intersection implementation using the ```union``` function. ### eventual consistency and conflict resolution The ```crdt``` example provides an example of the conflict-free replicated data type resolution based on data-series ```union```. The ```VersionedValue``` defines the version (here a timestamp) to solve the conflict by taking the maximum version. The maximum is defined through the trait ```Ord``` and used inside the given function used by ```union```. The below example uses TimestampMicros to version the data and solve conflict by taking the highest version of a value. ```rust fn datapoint(timestamp_micros: TimestampMicros, date: Date, data: T) -> DataPoint>> where T: std::marker::Copy, { DataPoint::new(date, Some(VersionedValue::new(timestamp_micros, data))) } /// Interval can be encoded by using 2 Datapoints with a [`None`] last datapoint value to mark the end of each interval fn end(date: Date) -> DataPoint>> { DataPoint::new(date, None) } let s1 = dataseries::of_iter(vec![ datapoint(TimestampMicros::new(1), date(2023, 1, 3), 50), end(date(2023, 1, 10)), ]); let s2 = dataseries::of_iter(vec![ datapoint(TimestampMicros::new(2), date(2023, 1, 4), 100), end(date(2023, 1, 5)), datapoint(TimestampMicros::new(2), date(2023, 1, 7), 110), end(date(2023, 1, 9)), ]); // Solves conflict by taking always the maximum version let actual = s1 .union(s2, |x| match x { dataseries::UnionResult::LeftOnly(x) | dataseries::UnionResult::RightOnly(x) => x, dataseries::UnionResult::Union { left, right } => std::cmp::max(left, right), }) .collect::>(); let expected = vec![ datapoint(TimestampMicros::new(1), date(2023, 1, 3), 50), datapoint(TimestampMicros::new(2), date(2023, 1, 4), 100), datapoint(TimestampMicros::new(1), date(2023, 1, 5), 50), datapoint(TimestampMicros::new(2), date(2023, 1, 7), 110), datapoint(TimestampMicros::new(1), date(2023, 1, 9), 50), end(date(2023, 1, 10)), ]; ```