persistence.rs

 1use anyhow::Result;
 2use std::path::PathBuf;
 3
 4use db::{define_connection, query, sqlez::statement::Statement, sqlez_macros::sql};
 5use workspace::{ItemId, WorkspaceDb, WorkspaceId};
 6
 7define_connection! {
 8    pub static ref TERMINAL_DB: TerminalDb<WorkspaceDb> =
 9        &[sql!(
10            CREATE TABLE terminals (
11                workspace_id INTEGER,
12                item_id INTEGER UNIQUE,
13                working_directory BLOB,
14                PRIMARY KEY(workspace_id, item_id),
15                FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
16                ON DELETE CASCADE
17            ) STRICT;
18        ),
19        // Remove the unique constraint on the item_id table
20        // SQLite doesn't have a way of doing this automatically, so
21        // we have to do this silly copying.
22        sql!(
23            CREATE TABLE terminals2 (
24                workspace_id INTEGER,
25                item_id INTEGER,
26                working_directory BLOB,
27                PRIMARY KEY(workspace_id, item_id),
28                FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id)
29                ON DELETE CASCADE
30            ) STRICT;
31
32            INSERT INTO terminals2 (workspace_id, item_id, working_directory)
33            SELECT workspace_id, item_id, working_directory FROM terminals;
34
35            DROP TABLE terminals;
36
37            ALTER TABLE terminals2 RENAME TO terminals;
38        )];
39}
40
41impl TerminalDb {
42    query! {
43       pub async fn update_workspace_id(
44            new_id: WorkspaceId,
45            old_id: WorkspaceId,
46            item_id: ItemId
47        ) -> Result<()> {
48            UPDATE terminals
49            SET workspace_id = ?
50            WHERE workspace_id = ? AND item_id = ?
51        }
52    }
53
54    query! {
55        pub async fn save_working_directory(
56            item_id: ItemId,
57            workspace_id: WorkspaceId,
58            working_directory: PathBuf
59        ) -> Result<()> {
60            INSERT OR REPLACE INTO terminals(item_id, workspace_id, working_directory)
61            VALUES (?, ?, ?)
62        }
63    }
64
65    query! {
66        pub fn get_working_directory(item_id: ItemId, workspace_id: WorkspaceId) -> Result<Option<PathBuf>> {
67            SELECT working_directory
68            FROM terminals
69            WHERE item_id = ? AND workspace_id = ?
70        }
71    }
72
73    pub async fn delete_unloaded_items(
74        &self,
75        workspace: WorkspaceId,
76        alive_items: Vec<ItemId>,
77    ) -> Result<()> {
78        let placeholders = alive_items
79            .iter()
80            .map(|_| "?")
81            .collect::<Vec<&str>>()
82            .join(", ");
83
84        let query = format!(
85            "DELETE FROM terminals WHERE workspace_id = ? AND item_id NOT IN ({placeholders})"
86        );
87
88        self.write(move |conn| {
89            let mut statement = Statement::prepare(conn, query)?;
90            let mut next_index = statement.bind(&workspace, 1)?;
91            for id in alive_items {
92                next_index = statement.bind(&id, next_index)?;
93            }
94            statement.exec()
95        })
96        .await
97    }
98}