Compare commits

..

No commits in common. "1d6155d9e55a1c185725c499a454e72e3af36c8c" and "3db870d79084b8b6e8dba898524cfe5d5988dbc5" have entirely different histories.

1 changed files with 64 additions and 99 deletions

View File

@ -30,6 +30,7 @@ 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>),
} }
@ -44,15 +45,6 @@ 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 }),
@ -118,14 +110,6 @@ 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,
@ -219,66 +203,52 @@ impl DayDetailViewModel {
let id = workout.id.clone(); let id = workout.id.clone();
let data = workout.data.clone(); let data = workout.data.clone();
let mut record_set = self.records.write().unwrap(); self.records
if let Some(record_state) = record_set.get(&id).clone() { .write()
let updated_state = match **record_state { .unwrap()
TraxRecord::BikeRide(_) => { .entry(id)
Some(record_state.clone().with_value(TraxRecord::BikeRide(data))) .and_modify(|r| match **r {
} TraxRecord::BikeRide(ref mut v) => *v = data,
TraxRecord::Row(_) => Some(record_state.clone().with_value(TraxRecord::Row(data))), TraxRecord::Row(ref mut v) => *v = data,
TraxRecord::Run(_) => Some(record_state.clone().with_value(TraxRecord::Run(data))), TraxRecord::Run(ref mut v) => *v = data,
TraxRecord::Swim(_) => { TraxRecord::Swim(ref mut v) => *v = data,
Some(record_state.clone().with_value(TraxRecord::Swim(data))) TraxRecord::Walk(ref mut v) => *v = 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( pub fn time_distance_records(&self, type_: RecordType) -> Vec<Record<TimeDistance>> {
&self, unimplemented!("time_distance_records")
type_: TimeDistanceWorkoutType,
) -> Vec<Record<TimeDistance>> {
self.records
.read()
.unwrap()
.iter()
.filter(|(_, record)| record.exists())
.filter(|(_, workout_state)| workout_state.is_time_distance_type(type_))
.filter_map(|(id, record_state)| match **record_state {
TraxRecord::BikeRide(ref workout)
| TraxRecord::Row(ref workout)
| TraxRecord::Run(ref workout)
| TraxRecord::Swim(ref workout)
| TraxRecord::Walk(ref workout) => Some(Record {
id: id.clone(),
data: workout.clone(),
}),
_ => None,
})
.collect()
} }
pub fn time_distance_summary( pub fn time_distance_summary(
&self, &self,
type_: TimeDistanceWorkoutType, type_: TimeDistanceWorkoutType,
) -> (si::Meter<f64>, si::Second<f64>) { ) -> (si::Meter<f64>, si::Second<f64>) {
self.time_distance_records(type_).into_iter().fold( self.records
(0. * si::M, 0. * si::S), .read()
|(distance, duration), workout| match (workout.data.distance, workout.data.duration) { .unwrap()
(Some(distance_), Some(duration_)) => (distance + distance_, duration + duration_), .iter()
(Some(distance_), None) => (distance + distance_, duration), .filter(|(_, workout_state)| workout_state.is_time_distance_type(type_))
(None, Some(duration_)) => (distance, duration + duration_), .filter_map(|(id, record_state)| match **record_state {
(None, None) => (distance, duration), TraxRecord::BikeRide(ref workout)
}, | TraxRecord::Row(ref workout)
) | TraxRecord::Run(ref workout)
| TraxRecord::Swim(ref workout)
| TraxRecord::Walk(ref workout) => Some(workout),
_ => None,
})
.fold((0. * si::M, 0. * si::S), |(distance, duration), workout| {
println!("folding workout: {:?}", workout);
match (workout.distance, workout.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>> {
@ -293,17 +263,7 @@ impl DayDetailViewModel {
} }
pub fn remove_record(&self, id: RecordId) { pub fn remove_record(&self, id: RecordId) {
let mut record_set = self.records.write().unwrap(); unimplemented!("remove_record")
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) {
@ -371,9 +331,7 @@ 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(r) => { RecordState::Deleted(_) => unimplemented!(),
let _ = self.provider.delete_record(r.id).await;
}
} }
} }
} }
@ -447,19 +405,11 @@ mod test {
} }
async fn update_record(&self, record: Record<TraxRecord>) -> Result<(), WriteError> { async fn update_record(&self, record: Record<TraxRecord>) -> Result<(), WriteError> {
println!("updated record: {:?}", record); Err(WriteError::NoDatabase)
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> {
self.deleted_records.write().unwrap().push(id.clone()); Err(WriteError::NoDatabase)
let _ = self.records.write().unwrap().remove(&id);
Ok(())
} }
} }
@ -504,6 +454,20 @@ 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 {
@ -602,16 +566,15 @@ 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(TimeDistanceWorkoutType::BikeRide) .time_distance_records(RecordType::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());
@ -620,7 +583,7 @@ mod test {
(15000. * si::M, 1800. * si::S) (15000. * si::M, 1800. * si::S)
); );
view_model.async_save().await; view_model.save();
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);
@ -628,6 +591,7 @@ 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!(
@ -645,10 +609,11 @@ 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(TimeDistanceWorkoutType::BikeRide) .time_distance_records(RecordType::BikeRide)
.first() .first()
.cloned() .cloned()
.unwrap(); .unwrap();
@ -658,7 +623,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.async_save().await; view_model.save();
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);