sos_database/entity/
server.rs

1use crate::Result;
2use async_sqlite::rusqlite::{
3    Connection, Error as SqlError, OptionalExtension, Row,
4};
5use sos_core::{Origin, UtcDateTime};
6use sql_query_builder as sql;
7use std::ops::Deref;
8use url::Url;
9
10/// Server row from the database.
11#[doc(hidden)]
12#[derive(Debug, Default)]
13pub struct ServerRow {
14    pub row_id: i64,
15    created_at: String,
16    modified_at: String,
17    name: String,
18    url: String,
19}
20
21impl<'a> TryFrom<&Row<'a>> for ServerRow {
22    type Error = SqlError;
23    fn try_from(row: &Row<'a>) -> std::result::Result<Self, Self::Error> {
24        Ok(ServerRow {
25            row_id: row.get(0)?,
26            created_at: row.get(1)?,
27            modified_at: row.get(2)?,
28            name: row.get(3)?,
29            url: row.get(4)?,
30        })
31    }
32}
33
34impl TryFrom<ServerRow> for Origin {
35    type Error = crate::Error;
36    fn try_from(row: ServerRow) -> std::result::Result<Self, Self::Error> {
37        Ok(Origin::new(row.name, row.url.parse()?))
38    }
39}
40
41impl TryFrom<Origin> for ServerRow {
42    type Error = crate::Error;
43    fn try_from(value: Origin) -> std::result::Result<Self, Self::Error> {
44        Ok(Self {
45            created_at: UtcDateTime::default().to_rfc3339()?,
46            modified_at: UtcDateTime::default().to_rfc3339()?,
47            name: value.name().to_string(),
48            url: value.url().to_string(),
49            ..Default::default()
50        })
51    }
52}
53
54/// Server entity.
55pub struct ServerEntity<'conn, C>
56where
57    C: Deref<Target = Connection>,
58{
59    conn: &'conn C,
60}
61
62impl<'conn, C> ServerEntity<'conn, C>
63where
64    C: Deref<Target = Connection>,
65{
66    /// Create a new server entity.
67    pub fn new(conn: &'conn C) -> Self {
68        Self { conn }
69    }
70
71    fn find_server_select(&self, select_one: bool) -> sql::Select {
72        let mut query = sql::Select::new()
73            .select(
74                r#"
75                    server_id,
76                    created_at,
77                    modified_at,
78                    name,
79                    url
80                "#,
81            )
82            .from("servers")
83            .where_clause("account_id=?1");
84        if select_one {
85            query = query.where_and("url=?2");
86        }
87        query
88    }
89
90    /// Find a server in the database.
91    pub fn find_one(
92        &self,
93        account_id: i64,
94        url: &Url,
95    ) -> std::result::Result<ServerRow, SqlError> {
96        let mut stmt = self
97            .conn
98            .prepare_cached(&self.find_server_select(true).as_string())?;
99        stmt.query_row((account_id, url.to_string()), |row| {
100            row.try_into()
101        })
102    }
103
104    /// Find an optional server in the database.
105    pub fn find_optional(
106        &self,
107        account_id: i64,
108        url: &Url,
109    ) -> std::result::Result<Option<ServerRow>, SqlError> {
110        let mut stmt = self
111            .conn
112            .prepare_cached(&self.find_server_select(true).as_string())?;
113        stmt
114            .query_row((account_id, url.to_string()), |row| {
115                row.try_into()
116            })
117            .optional()
118    }
119
120    /// Load servers for an account.
121    pub fn load_servers(&self, account_id: i64) -> Result<Vec<ServerRow>> {
122        let query = self.find_server_select(false);
123        let mut stmt = self.conn.prepare_cached(&query.as_string())?;
124
125        fn convert_row(row: &Row<'_>) -> Result<ServerRow> {
126            Ok(row.try_into()?)
127        }
128
129        let rows = stmt.query_and_then([account_id], |row| {
130            convert_row(row)
131        })?;
132        let mut servers = Vec::new();
133        for row in rows {
134            servers.push(row?);
135        }
136        Ok(servers)
137    }
138
139    /// Delete server origin from the database.
140    pub fn delete_server(
141        &self,
142        server_id: i64,
143    ) -> std::result::Result<(), SqlError> {
144        let query = sql::Delete::new()
145            .delete_from("servers")
146            .where_clause("server_id = ?1");
147        let mut stmt = self.conn.prepare_cached(&query.as_string())?;
148        stmt.execute([server_id])?;
149        Ok(())
150    }
151
152    /// Create server origin in the database.
153    pub fn insert_server(
154        &self,
155        account_id: i64,
156        server: &ServerRow,
157    ) -> std::result::Result<(), SqlError> {
158        let query = sql::Insert::new()
159            .insert_into(
160                "servers (account_id, created_at, modified_at, name, url)",
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            &server.created_at,
167            &server.modified_at,
168            &server.name,
169            &server.url,
170        ))?;
171
172        Ok(())
173    }
174
175    /// Create server origins in the database.
176    pub fn insert_servers(
177        &self,
178        account_id: i64,
179        servers: &[ServerRow],
180    ) -> std::result::Result<(), SqlError> {
181        for server in servers {
182            self.insert_server(account_id, server)?;
183        }
184        Ok(())
185    }
186}