pub mod kline;
pub mod word_trend;
use chrono::{DateTime, Utc};
use derive_getters::Getters;
use serde::{Deserialize, Serialize};
use std::hash::Hash;
use std::{fmt, marker::PhantomData};
use crate::provider::interval::Interval;
pub trait Data:
Serialize + for<'a> Deserialize<'a> + fmt::Debug + Clone + PartialEq + 'static + Sync + Send
{
fn basics(&self) -> &DataBasics;
fn mut_basics(&mut self) -> &mut DataBasics;
fn set_basics(&mut self, basics: DataBasics) {
*self.mut_basics() = basics;
}
type Specifier: DataSpecifier;
}
pub trait DataSpecifier:
fmt::Debug + PartialEq + Clone + Eq + Hash + 'static + Sync + Send
{
fn name(&self) -> String;
}
#[derive(Debug, Clone, Getters, PartialEq)]
pub struct DataQuery<D: Data> {
specifier: D::Specifier,
interval: Interval,
begin: DateTime<Utc>,
end: DateTime<Utc>,
_marker: PhantomData<D>,
}
impl<D: Data> DataQuery<D> {
pub fn new(
specific: D::Specifier,
interval: Interval,
begin: DateTime<Utc>,
end: DateTime<Utc>,
) -> Self {
let (below_start, _) = interval.get_time_bounds(begin).unwrap();
let (below_end, above_end) = interval.get_time_bounds(end).unwrap();
let final_end = if below_end == end { end } else { above_end };
Self {
specifier: specific,
interval,
begin: below_start,
end: final_end,
_marker: PhantomData,
}
}
}
#[derive(Debug, Serialize, Deserialize, Getters, Clone, PartialEq, Eq, Hash, Default)]
pub struct DataBasics {
pub begin: DateTime<Utc>,
pub end: DateTime<Utc>,
pub update_date: DateTime<Utc>,
pub source: String,
}
#[cfg(test)]
pub mod test {
use chrono::{DateTime, Utc};
use crate::{
core::{CoreError, CoreResult},
provider::{
DataBasics, Interval,
data::{Data, DataSpecifier},
},
};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Default)]
pub struct TestData {
pub content: String,
pub basics: DataBasics,
}
impl TestData {
pub fn new(content: String, basics: DataBasics) -> Self {
Self { content, basics }
}
}
#[derive(Debug, Clone, PartialEq, Default, Eq, Hash)]
pub struct TestDataSpecifier(pub String);
impl DataSpecifier for TestDataSpecifier {
fn name(&self) -> String {
"test".to_string()
}
}
impl Data for TestData {
fn basics(&self) -> &DataBasics {
&self.basics
}
fn mut_basics(&mut self) -> &mut DataBasics {
&mut self.basics
}
type Specifier = TestDataSpecifier;
}
pub fn data_vec_over<D: Data>(
interval: Interval,
mut start: DateTime<Utc>,
end: DateTime<Utc>,
data: D,
source: String,
) -> CoreResult<Vec<D>> {
if interval > Interval::OneDay {
return Err(CoreError::param_error("interval not implemented"));
}
let mut vec = vec![];
loop {
let next_end = start + interval.time_delta();
if next_end > end {
break;
}
let basics = DataBasics {
begin: start,
end: next_end,
update_date: Utc::now(),
source: source.clone(),
};
let mut new_data = data.clone();
new_data.set_basics(basics);
vec.push(new_data);
start = next_end;
}
Ok(vec)
}
}
#[cfg(test)]
mod tests {
use chrono::{TimeZone as _, Utc};
use crate::provider::{
data::{
DataQuery,
test::{TestData, TestDataSpecifier},
},
interval::Interval,
};
#[test]
fn create_query() {
let query = DataQuery::<TestData>::new(
TestDataSpecifier::default(),
Interval::OneMinute,
Utc.with_ymd_and_hms(2022, 1, 1, 0, 0, 59).unwrap(),
Utc.with_ymd_and_hms(2022, 1, 1, 0, 1, 1).unwrap(),
);
assert_eq!(query.interval, Interval::OneMinute);
assert_eq!(
query.begin,
Utc.with_ymd_and_hms(2022, 1, 1, 0, 0, 0).unwrap()
);
assert_eq!(
query.end,
Utc.with_ymd_and_hms(2022, 1, 1, 0, 2, 0).unwrap()
);
}
}