Compare commits
2 Commits
3db870d790
...
1d6155d9e5
Author | SHA1 | Date |
---|---|---|
Savanni D'Gerinel | 1d6155d9e5 | |
Savanni D'Gerinel | a8bf540517 |
|
@ -30,7 +30,6 @@ enum RecordState<T: Clone + Recordable> {
|
||||||
Original(Record<T>),
|
Original(Record<T>),
|
||||||
New(T),
|
New(T),
|
||||||
Updated(Record<T>),
|
Updated(Record<T>),
|
||||||
#[allow(unused)]
|
|
||||||
Deleted(Record<T>),
|
Deleted(Record<T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +44,15 @@ impl<T: Clone + emseries::Recordable> RecordState<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn exists(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
RecordState::Original(ref r) => true,
|
||||||
|
RecordState::New(ref r) => true,
|
||||||
|
RecordState::Updated(ref r) => true,
|
||||||
|
RecordState::Deleted(ref r) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn with_value(self, value: T) -> RecordState<T> {
|
fn with_value(self, value: T) -> RecordState<T> {
|
||||||
match self {
|
match self {
|
||||||
RecordState::Original(r) => RecordState::Updated(Record { data: value, ..r }),
|
RecordState::Original(r) => RecordState::Updated(Record { data: value, ..r }),
|
||||||
|
@ -110,6 +118,14 @@ impl DayDetailViewModel {
|
||||||
.partition(|r| r.data.is_weight());
|
.partition(|r| r.data.is_weight());
|
||||||
let (step_records, records): (Vec<Record<TraxRecord>>, Vec<Record<TraxRecord>>) =
|
let (step_records, records): (Vec<Record<TraxRecord>>, Vec<Record<TraxRecord>>) =
|
||||||
records.into_iter().partition(|r| r.data.is_steps());
|
records.into_iter().partition(|r| r.data.is_steps());
|
||||||
|
|
||||||
|
if weight_records.len() > 1 {
|
||||||
|
eprintln!("warning: multiple weight records found for {}. This is unsupported and the one presented is unpredictable.", date.format("%Y-%m-%d"));
|
||||||
|
}
|
||||||
|
if step_records.len() > 1 {
|
||||||
|
eprintln!("warning: multiple step records found for {}. This is unsupported and the one presented is unpredictable.", date.format("%Y-%m-%d"));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
provider: Arc::new(provider),
|
provider: Arc::new(provider),
|
||||||
date,
|
date,
|
||||||
|
@ -203,52 +219,66 @@ impl DayDetailViewModel {
|
||||||
let id = workout.id.clone();
|
let id = workout.id.clone();
|
||||||
let data = workout.data.clone();
|
let data = workout.data.clone();
|
||||||
|
|
||||||
self.records
|
let mut record_set = self.records.write().unwrap();
|
||||||
.write()
|
if let Some(record_state) = record_set.get(&id).clone() {
|
||||||
.unwrap()
|
let updated_state = match **record_state {
|
||||||
.entry(id)
|
TraxRecord::BikeRide(_) => {
|
||||||
.and_modify(|r| match **r {
|
Some(record_state.clone().with_value(TraxRecord::BikeRide(data)))
|
||||||
TraxRecord::BikeRide(ref mut v) => *v = data,
|
}
|
||||||
TraxRecord::Row(ref mut v) => *v = data,
|
TraxRecord::Row(_) => Some(record_state.clone().with_value(TraxRecord::Row(data))),
|
||||||
TraxRecord::Run(ref mut v) => *v = data,
|
TraxRecord::Run(_) => Some(record_state.clone().with_value(TraxRecord::Run(data))),
|
||||||
TraxRecord::Swim(ref mut v) => *v = data,
|
TraxRecord::Swim(_) => {
|
||||||
TraxRecord::Walk(ref mut v) => *v = data,
|
Some(record_state.clone().with_value(TraxRecord::Swim(data)))
|
||||||
_ => {}
|
}
|
||||||
});
|
TraxRecord::Walk(_) => {
|
||||||
|
Some(record_state.clone().with_value(TraxRecord::Walk(data)))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(updated_state) = updated_state {
|
||||||
|
record_set.insert(id, updated_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn time_distance_records(&self, type_: RecordType) -> Vec<Record<TimeDistance>> {
|
pub fn time_distance_records(
|
||||||
unimplemented!("time_distance_records")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn time_distance_summary(
|
|
||||||
&self,
|
&self,
|
||||||
type_: TimeDistanceWorkoutType,
|
type_: TimeDistanceWorkoutType,
|
||||||
) -> (si::Meter<f64>, si::Second<f64>) {
|
) -> Vec<Record<TimeDistance>> {
|
||||||
self.records
|
self.records
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|(_, record)| record.exists())
|
||||||
.filter(|(_, workout_state)| workout_state.is_time_distance_type(type_))
|
.filter(|(_, workout_state)| workout_state.is_time_distance_type(type_))
|
||||||
.filter_map(|(id, record_state)| match **record_state {
|
.filter_map(|(id, record_state)| match **record_state {
|
||||||
TraxRecord::BikeRide(ref workout)
|
TraxRecord::BikeRide(ref workout)
|
||||||
| TraxRecord::Row(ref workout)
|
| TraxRecord::Row(ref workout)
|
||||||
| TraxRecord::Run(ref workout)
|
| TraxRecord::Run(ref workout)
|
||||||
| TraxRecord::Swim(ref workout)
|
| TraxRecord::Swim(ref workout)
|
||||||
| TraxRecord::Walk(ref workout) => Some(workout),
|
| TraxRecord::Walk(ref workout) => Some(Record {
|
||||||
|
id: id.clone(),
|
||||||
|
data: workout.clone(),
|
||||||
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.fold((0. * si::M, 0. * si::S), |(distance, duration), workout| {
|
.collect()
|
||||||
println!("folding workout: {:?}", workout);
|
}
|
||||||
match (workout.distance, workout.duration) {
|
|
||||||
(Some(distance_), Some(duration_)) => {
|
pub fn time_distance_summary(
|
||||||
(distance + distance_, duration + duration_)
|
&self,
|
||||||
}
|
type_: TimeDistanceWorkoutType,
|
||||||
(Some(distance_), None) => (distance + distance_, duration),
|
) -> (si::Meter<f64>, si::Second<f64>) {
|
||||||
(None, Some(duration_)) => (distance, duration + duration_),
|
self.time_distance_records(type_).into_iter().fold(
|
||||||
(None, None) => (distance, duration),
|
(0. * si::M, 0. * si::S),
|
||||||
}
|
|(distance, duration), workout| match (workout.data.distance, workout.data.duration) {
|
||||||
})
|
(Some(distance_), Some(duration_)) => (distance + distance_, duration + duration_),
|
||||||
|
(Some(distance_), None) => (distance + distance_, duration),
|
||||||
|
(None, Some(duration_)) => (distance, duration + duration_),
|
||||||
|
(None, None) => (distance, duration),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_record(&self, id: &RecordId) -> Option<Record<TraxRecord>> {
|
fn get_record(&self, id: &RecordId) -> Option<Record<TraxRecord>> {
|
||||||
|
@ -263,7 +293,17 @@ impl DayDetailViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_record(&self, id: RecordId) {
|
pub fn remove_record(&self, id: RecordId) {
|
||||||
unimplemented!("remove_record")
|
let mut record_set = self.records.write().unwrap();
|
||||||
|
let updated_record = match record_set.remove(&id) {
|
||||||
|
Some(RecordState::Original(r)) => Some(RecordState::Deleted(r)),
|
||||||
|
Some(RecordState::New(_)) => None,
|
||||||
|
Some(RecordState::Updated(r)) => Some(RecordState::Deleted(r)),
|
||||||
|
Some(RecordState::Deleted(r)) => Some(RecordState::Deleted(r)),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
if let Some(updated_record) = updated_record {
|
||||||
|
record_set.insert(id, updated_record);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&self) {
|
pub fn save(&self) {
|
||||||
|
@ -331,7 +371,9 @@ impl DayDetailViewModel {
|
||||||
RecordState::Updated(r) => {
|
RecordState::Updated(r) => {
|
||||||
let _ = self.provider.update_record(r.clone()).await;
|
let _ = self.provider.update_record(r.clone()).await;
|
||||||
}
|
}
|
||||||
RecordState::Deleted(_) => unimplemented!(),
|
RecordState::Deleted(r) => {
|
||||||
|
let _ = self.provider.delete_record(r.id).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -405,11 +447,19 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_record(&self, record: Record<TraxRecord>) -> Result<(), WriteError> {
|
async fn update_record(&self, record: Record<TraxRecord>) -> Result<(), WriteError> {
|
||||||
Err(WriteError::NoDatabase)
|
println!("updated record: {:?}", record);
|
||||||
|
self.updated_records.write().unwrap().push(record.clone());
|
||||||
|
self.records
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.insert(record.id.clone(), record);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_record(&self, id: RecordId) -> Result<(), WriteError> {
|
async fn delete_record(&self, id: RecordId) -> Result<(), WriteError> {
|
||||||
Err(WriteError::NoDatabase)
|
self.deleted_records.write().unwrap().push(id.clone());
|
||||||
|
let _ = self.records.write().unwrap().remove(&id);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,20 +504,6 @@ mod test {
|
||||||
count: 2500,
|
count: 2500,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
Record {
|
|
||||||
id: RecordId::default(),
|
|
||||||
data: TraxRecord::Weight(ft_core::Weight {
|
|
||||||
date: oct_13.clone(),
|
|
||||||
weight: 91. * si::KG,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Record {
|
|
||||||
id: RecordId::default(),
|
|
||||||
data: TraxRecord::Steps(ft_core::Steps {
|
|
||||||
date: oct_13.clone(),
|
|
||||||
count: 2750,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Record {
|
Record {
|
||||||
id: RecordId::default(),
|
id: RecordId::default(),
|
||||||
data: TraxRecord::BikeRide(ft_core::TimeDistance {
|
data: TraxRecord::BikeRide(ft_core::TimeDistance {
|
||||||
|
@ -566,15 +602,16 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[ignore]
|
|
||||||
async fn it_can_update_an_existing_record() {
|
async fn it_can_update_an_existing_record() {
|
||||||
let (view_model, provider) = create_view_model().await;
|
let (view_model, provider) = create_view_model().await;
|
||||||
let mut workout = view_model
|
let mut workout = view_model
|
||||||
.time_distance_records(RecordType::BikeRide)
|
.time_distance_records(TimeDistanceWorkoutType::BikeRide)
|
||||||
.first()
|
.first()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
println!("found record: {:?}", workout);
|
||||||
|
|
||||||
workout.data.duration = Some(1800. * si::S);
|
workout.data.duration = Some(1800. * si::S);
|
||||||
view_model.update_time_distance(workout.clone());
|
view_model.update_time_distance(workout.clone());
|
||||||
|
|
||||||
|
@ -583,7 +620,7 @@ mod test {
|
||||||
(15000. * si::M, 1800. * si::S)
|
(15000. * si::M, 1800. * si::S)
|
||||||
);
|
);
|
||||||
|
|
||||||
view_model.save();
|
view_model.async_save().await;
|
||||||
|
|
||||||
assert_eq!(provider.put_records.read().unwrap().len(), 0);
|
assert_eq!(provider.put_records.read().unwrap().len(), 0);
|
||||||
assert_eq!(provider.updated_records.read().unwrap().len(), 1);
|
assert_eq!(provider.updated_records.read().unwrap().len(), 1);
|
||||||
|
@ -591,7 +628,6 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[ignore]
|
|
||||||
async fn it_can_remove_a_new_record() {
|
async fn it_can_remove_a_new_record() {
|
||||||
let (view_model, provider) = create_empty_view_model().await;
|
let (view_model, provider) = create_empty_view_model().await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -609,11 +645,10 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[ignore]
|
|
||||||
async fn it_can_delete_an_existing_record() {
|
async fn it_can_delete_an_existing_record() {
|
||||||
let (view_model, provider) = create_view_model().await;
|
let (view_model, provider) = create_view_model().await;
|
||||||
let mut workout = view_model
|
let mut workout = view_model
|
||||||
.time_distance_records(RecordType::BikeRide)
|
.time_distance_records(TimeDistanceWorkoutType::BikeRide)
|
||||||
.first()
|
.first()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -623,7 +658,7 @@ mod test {
|
||||||
view_model.time_distance_summary(TimeDistanceWorkoutType::BikeRide),
|
view_model.time_distance_summary(TimeDistanceWorkoutType::BikeRide),
|
||||||
(0. * si::M, 0. * si::S)
|
(0. * si::M, 0. * si::S)
|
||||||
);
|
);
|
||||||
view_model.save();
|
view_model.async_save().await;
|
||||||
|
|
||||||
assert_eq!(provider.put_records.read().unwrap().len(), 0);
|
assert_eq!(provider.put_records.read().unwrap().len(), 0);
|
||||||
assert_eq!(provider.updated_records.read().unwrap().len(), 0);
|
assert_eq!(provider.updated_records.read().unwrap().len(), 0);
|
||||||
|
|
Loading…
Reference in New Issue