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(
84 &self,
85 account_id: Option<i64>,
86 select_one: bool,
87 ) -> sql::Select {
88 let mut query = sql::Select::new()
89 .select(
90 r#"
91 preference_id,
92 created_at,
93 modified_at,
94 key,
95 json_data
96 "#,
97 )
98 .from("preferences");
99
100 if account_id.is_some() {
101 query = query.where_clause("account_id=?1");
102 if select_one {
103 query = query.where_and("key=?2");
104 }
105 } else {
106 query = query.where_clause("account_id IS NULL");
107 if select_one {
108 query = query.where_and("key=?1");
109 }
110 }
111 query
112 }
113
114 pub fn find_optional(
116 &self,
117 account_id: Option<i64>,
118 key: &str,
119 ) -> std::result::Result<Option<PreferenceRow>, SqlError> {
120 let query = self.find_preference_select(account_id, true);
121 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
122 if let Some(account_id) = account_id {
123 stmt.query_row((account_id, key), |row| row.try_into())
124 .optional()
125 } else {
126 stmt.query_row((key,), |row| row.try_into()).optional()
127 }
128 }
129
130 pub fn load_preferences(
135 &self,
136 account_id: Option<i64>,
137 ) -> Result<Vec<PreferenceRow>> {
138 let query = self.find_preference_select(account_id, false);
139 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
140
141 fn convert_row(row: &Row<'_>) -> Result<PreferenceRow> {
142 Ok(row.try_into()?)
143 }
144
145 let rows = if let Some(account_id) = account_id {
146 stmt.query_and_then([account_id], convert_row)?
147 } else {
148 stmt.query_and_then([], convert_row)?
149 };
150 let mut preferences = Vec::new();
151 for row in rows {
152 preferences.push(row?);
153 }
154
155 Ok(preferences)
156 }
157
158 pub fn insert_preference(
163 &self,
164 account_id: Option<i64>,
165 row: &PreferenceRow,
166 ) -> std::result::Result<(), SqlError> {
167 let query = sql::Insert::new()
168 .insert_into(
169 r#"
170 preferences
171 (
172 account_id,
173 created_at,
174 modified_at,
175 key,
176 json_data
177 )
178 "#,
179 )
180 .values("(?1, ?2, ?3, ?4, ?5)");
181 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
182 stmt.execute((
183 account_id,
184 &row.created_at,
185 &row.modified_at,
186 &row.key,
187 &row.json_data,
188 ))?;
189 Ok(())
190 }
191
192 pub fn insert_preferences(
197 &self,
198 account_id: Option<i64>,
199 rows: &[PreferenceRow],
200 ) -> std::result::Result<(), SqlError> {
201 for row in rows {
202 self.insert_preference(account_id, row)?;
203 }
204 Ok(())
205 }
206
207 pub fn update_preference(
212 &self,
213 account_id: Option<i64>,
214 row: &PreferenceRow,
215 ) -> std::result::Result<(), SqlError> {
216 let mut query = sql::Update::new()
217 .update("preferences")
218 .set("json_data = ?1, modified_at = ?2");
219 if account_id.is_some() {
220 query =
221 query.where_clause("account_id = ?3").where_and("key = ?4");
222 } else {
223 query = query
224 .where_clause("account_id IS NULL")
225 .where_and("key = ?3");
226 }
227 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
228 if let Some(account_id) = account_id {
229 stmt.execute((
230 &row.json_data,
231 &row.modified_at,
232 account_id,
233 &row.key,
234 ))?;
235 } else {
236 stmt.execute((&row.json_data, &row.modified_at, &row.key))?;
237 }
238 Ok(())
239 }
240
241 pub fn upsert_preference(
246 &self,
247 account_id: Option<i64>,
248 row: &PreferenceRow,
249 ) -> std::result::Result<(), SqlError> {
250 let pref_row = self.find_optional(account_id, &row.key)?;
251 match pref_row {
252 Some(_) => {
253 self.update_preference(account_id, row)?;
254 }
255 None => self.insert_preference(account_id, row)?,
256 }
257 Ok(())
258 }
259
260 pub fn delete_preference(
262 &self,
263 account_id: Option<i64>,
264 key: &str,
265 ) -> std::result::Result<(), SqlError> {
266 let mut query = sql::Delete::new().delete_from("preferences");
267 if account_id.is_some() {
268 query =
269 query.where_clause("account_id = ?1").where_and("key = ?2");
270 } else {
271 query = query
272 .where_clause("account_id IS NULL")
273 .where_and("key = ?1");
274 }
275 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
276 if let Some(account_id) = account_id {
277 stmt.execute((account_id, key))?;
278 } else {
279 stmt.execute((key,))?;
280 }
281 Ok(())
282 }
283
284 pub fn delete_all_preferences(
286 &self,
287 account_id: Option<i64>,
288 ) -> std::result::Result<(), SqlError> {
289 let mut query = sql::Delete::new().delete_from("preferences");
290
291 if account_id.is_some() {
292 query = query.where_clause("account_id = ?1");
293 } else {
294 query = query.where_clause("account_id IS NULL");
295 }
296
297 let mut stmt = self.conn.prepare_cached(&query.as_string())?;
298 if let Some(account_id) = account_id {
299 stmt.execute([account_id])?;
300 } else {
301 stmt.execute([])?;
302 }
303 Ok(())
304 }
305}