1use crate::{Error, Result};
2use async_sqlite::rusqlite::{
3 Connection, Error as SqlError, OptionalExtension, Row,
4};
5use sos_core::UtcDateTime;
6use sos_preferences::Preference;
7use sql_query_builder as sql;
8use std::ops::Deref;
9
10#[doc(hidden)]
12#[derive(Debug, Default)]
13pub struct PreferenceRow {
14 pub row_id: i64,
15 created_at: String,
16 modified_at: String,
17 key: String,
18 json_data: String,
19}
20
21impl PreferenceRow {
22 pub fn new_insert(key: &str, value: &Preference) -> Result<Self> {
24 Ok(Self {
25 created_at: UtcDateTime::default().to_rfc3339()?,
26 modified_at: UtcDateTime::default().to_rfc3339()?,
27 key: key.to_owned(),
28 json_data: serde_json::to_string(value)?,
29 ..Default::default()
30 })
31 }
32
33 pub fn new_update(key: &str, value: &Preference) -> Result<Self> {
35 Ok(Self {
36 modified_at: UtcDateTime::default().to_rfc3339()?,
37 key: key.to_owned(),
38 json_data: serde_json::to_string(value)?,
39 ..Default::default()
40 })
41 }
42}
43
44impl<'a> TryFrom<&Row<'a>> for PreferenceRow {
45 type Error = SqlError;
46 fn try_from(row: &Row<'a>) -> std::result::Result<Self, Self::Error> {
47 Ok(PreferenceRow {
48 row_id: row.get(0)?,
49 created_at: row.get(1)?,
50 modified_at: row.get(2)?,
51 key: row.get(3)?,
52 json_data: row.get(4)?,
53 })
54 }
55}
56
57impl TryFrom<PreferenceRow> for (String, Preference) {
58 type Error = Error;
59
60 fn try_from(value: PreferenceRow) -> Result<Self> {
61 let pref: Preference = serde_json::from_str(&value.json_data)?;
62 Ok((value.key, pref))
63 }
64}
65
66pub struct PreferenceEntity<'conn, C>
68where
69 C: Deref<Target = Connection>,
70{
71 conn: &'conn C,
72}
73
74impl<'conn, C> PreferenceEntity<'conn, C>
75where
76 C: Deref<Target = Connection>,
77{
78 pub fn new(conn: &'conn C) -> Self {
80 Self { conn }
81 }
82
83 fn find_preference_select(&self, select_one: bool) -> sql::Select {
84 let mut query = sql::Select::new()
85 .select(
86 r#"
87 preference_id,
88 created_at,
89 modified_at,
90 key,
91 json_data
92 "#,
93 )
94 .from("preferences")
95 .where_clause("account_id=?1");
96 if select_one {
97 query = query.where_and("key=?2");
98 }
99 query
100 }
101
102 pub fn find_optional(
104 &self,
105 account_id: Option<i64>,
106 key: &str,
107 ) -> std::result::Result<Option<PreferenceRow>, SqlError> {
108 let query = self.find_preference_select(true);
109 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
110 Ok(stmt
111 .query_row((account_id, key), |row| Ok(row.try_into()?))
112 .optional()?)
113 }
114
115 pub fn load_preferences(
120 &self,
121 account_id: Option<i64>,
122 ) -> Result<Vec<PreferenceRow>> {
123 let query = self.find_preference_select(false);
124 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
125
126 fn convert_row(row: &Row<'_>) -> Result<PreferenceRow> {
127 Ok(row.try_into()?)
128 }
129
130 let rows = stmt.query_and_then([account_id], |row| {
131 Ok::<_, crate::Error>(convert_row(row)?)
132 })?;
133 let mut preferences = Vec::new();
134 for row in rows {
135 preferences.push(row?);
136 }
137 Ok(preferences)
138 }
139
140 pub fn insert_preference(
145 &self,
146 account_id: Option<i64>,
147 row: &PreferenceRow,
148 ) -> std::result::Result<(), SqlError> {
149 let query = sql::Insert::new()
150 .insert_into(
151 r#"
152 preferences
153 (
154 account_id,
155 created_at,
156 modified_at,
157 key,
158 json_data
159 )
160 "#,
161 )
162 .values("(?1, ?2, ?3, ?4, ?5)");
163 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
164 stmt.execute((
165 account_id,
166 &row.created_at,
167 &row.modified_at,
168 &row.key,
169 &row.json_data,
170 ))?;
171 Ok(())
172 }
173
174 pub fn insert_preferences(
179 &self,
180 account_id: Option<i64>,
181 rows: &[PreferenceRow],
182 ) -> std::result::Result<(), SqlError> {
183 for row in rows {
184 self.insert_preference(account_id, row)?;
185 }
186 Ok(())
187 }
188
189 pub fn update_preference(
194 &self,
195 account_id: Option<i64>,
196 row: &PreferenceRow,
197 ) -> std::result::Result<(), SqlError> {
198 let query = sql::Update::new()
199 .update("preferences")
200 .set("json_data = ?1, modified_at = ?2")
201 .where_clause("account_id = ?3")
202 .where_and("key = ?4");
203 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
204 stmt.execute((
205 &row.json_data,
206 &row.modified_at,
207 account_id,
208 &row.key,
209 ))?;
210 Ok(())
211 }
212
213 pub fn upsert_preference(
218 &self,
219 account_id: Option<i64>,
220 row: &PreferenceRow,
221 ) -> std::result::Result<(), SqlError> {
222 let pref_row = self.find_optional(account_id, &row.key)?;
223 match pref_row {
224 Some(_) => {
225 self.update_preference(account_id, row)?;
226 }
227 None => self.insert_preference(account_id, row)?,
228 }
229 Ok(())
230 }
231
232 pub fn delete_preference(
234 &self,
235 account_id: Option<i64>,
236 key: &str,
237 ) -> std::result::Result<(), SqlError> {
238 let query = sql::Delete::new()
239 .delete_from("preferences")
240 .where_clause("account_id = ?1")
241 .where_and("key = ?2");
242 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
243 stmt.execute((account_id, key))?;
244 Ok(())
245 }
246
247 pub fn delete_all_preferences(
249 &self,
250 account_id: Option<i64>,
251 ) -> std::result::Result<(), SqlError> {
252 let query = sql::Delete::new()
253 .delete_from("preferences")
254 .where_clause("account_id = ?1");
255 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
256 stmt.execute([account_id])?;
257 Ok(())
258 }
259}