The grown-ups' choices and the day's time, in household and time_spent.
7use crate::{DbError, Store};
The household document of one device (or of the service). Each setting is a row with its own time and each device's time on each day is a row of its own, so two devices never write the same row.
15impl SqliteHousehold { 16 pub fn new(store: Store) -> Self { 17 Self { store } 18 } 19} 20 21fn read_rows(store: &Store) -> Result<HouseholdRows, DbError> { 22 let conn = store.lock(); 23 let mut rows = HouseholdRows::default(); 24 { 25 let mut st = conn.prepare("SELECT name, value, stamp FROM household ORDER BY name")?; 26 let mut q = st.query([])?; 27 while let Some(r) = q.next()? { 28 let name: String = r.get(0)?; 29 let setting = Setting::from_name(&name).ok_or_else(|| DbError::Damaged(format!("a setting called {name:?}")))?; 30 rows.settings.push(SettingRow { setting, value: r.get(1)?, stamp: r.get::<_, i64>(2)? as u64 }); 31 } 32 } 33 // Only the latest day is the document's: older days are kept as history and are not read back. 34 let mut st = conn.prepare("SELECT device, day, used_ms, extra_minutes FROM time_spent WHERE day = (SELECT MAX(day) FROM time_spent) ORDER BY device")?; 35 let mut q = st.query([])?; 36 while let Some(r) = q.next()? { 37 rows.time.push(TimeRow { device: r.get(0)?, day: r.get::<_, i64>(1)? as u32, used_ms: r.get::<_, i64>(2)? as u64, extra_minutes: r.get::<_, i64>(3)? as u32 }); 38 } 39 Ok(rows) 40} 41 42impl HouseholdStore for SqliteHousehold { 43 fn load(&self) -> Result<Household, HouseholdStoreError> { 44 let rows = read_rows(&self.store).map_err(|e| { 45 error!("the household cannot be read: {e}"); 46 HouseholdStoreError(e.to_string()) 47 })?; 48 debug!("household loaded: {} setting(s), {} device day(s)", rows.settings.len(), rows.time.len()); 49 Household::from_rows(&rows).map_err(|e| { 50 error!("the household does not read back: {e}"); 51 HouseholdStoreError(e) 52 }) 53 } 54 55 fn save(&mut self, household: &Household) -> Result<(), HouseholdStoreError> { 56 let rows = household.to_rows(); 57 self.store 58 .transaction(|tx| { 59 for s in &rows.settings { 60 tx.execute( 61 "INSERT INTO household (name, value, stamp) VALUES (?1, ?2, ?3) 62 ON CONFLICT (name) DO UPDATE SET value = excluded.value, stamp = excluded.stamp", 63 params![s.setting.name(), s.value, s.stamp as i64], 64 )?; 65 } 66 // Counts only rise: a save from a copy that is behind cannot take time back. 67 for t in &rows.time { 68 tx.execute( 69 "INSERT INTO time_spent (device, day, used_ms, extra_minutes) VALUES (?1, ?2, ?3, ?4) 70 ON CONFLICT (device, day) DO UPDATE SET used_ms = MAX(used_ms, excluded.used_ms), 71 extra_minutes = MAX(extra_minutes, excluded.extra_minutes)", 72 params![t.device, t.day as i64, t.used_ms as i64, t.extra_minutes as i64], 73 )?; 74 } 75 Ok(()) 76 }) 77 .map_err(|e| { 78 error!("the household was not kept: {e}"); 79 HouseholdStoreError(e.to_string()) 80 }) 81 } 82}