From 3c1b747f641c29ec4de6111b911b608f80862dbb Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 1 Nov 2022 17:26:03 -0700 Subject: [PATCH] WIP almost compiling with sqlez --- crates/db/src/kvp.rs | 6 +- crates/db/src/workspace.rs | 65 +++++++++------------- crates/sqlez/src/bindable.rs | 22 ++++++++ crates/sqlez/src/connection.rs | 14 ++++- crates/sqlez/src/migrations.rs | 6 +- crates/sqlez/src/savepoint.rs | 8 +-- crates/sqlez/src/statement.rs | 11 ++-- crates/sqlez/src/thread_safe_connection.rs | 2 + 8 files changed, 77 insertions(+), 57 deletions(-) diff --git a/crates/db/src/kvp.rs b/crates/db/src/kvp.rs index 6db99831f7..a692d73d88 100644 --- a/crates/db/src/kvp.rs +++ b/crates/db/src/kvp.rs @@ -17,21 +17,21 @@ impl Db { pub fn read_kvp(&self, key: &str) -> Result> { self.0 .prepare("SELECT value FROM kv_store WHERE key = (?)")? - .bind(key)? + .with_bindings(key)? .maybe_row() } pub fn write_kvp(&self, key: &str, value: &str) -> Result<()> { self.0 .prepare("INSERT OR REPLACE INTO kv_store(key, value) VALUES (?, ?)")? - .bind((key, value))? + .with_bindings((key, value))? .exec() } pub fn delete_kvp(&self, key: &str) -> Result<()> { self.0 .prepare("DELETE FROM kv_store WHERE key = (?)")? - .bind(key)? + .with_bindings(key)? .exec() } } diff --git a/crates/db/src/workspace.rs b/crates/db/src/workspace.rs index 16ff0e78c0..126a34676e 100644 --- a/crates/db/src/workspace.rs +++ b/crates/db/src/workspace.rs @@ -23,17 +23,17 @@ use super::Db; pub(crate) const WORKSPACES_MIGRATION: Migration = Migration::new( "workspace", &[indoc! {" - CREATE TABLE workspaces( - workspace_id INTEGER PRIMARY KEY, - timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL - ) STRICT; - - CREATE TABLE worktree_roots( - worktree_root BLOB NOT NULL, - workspace_id INTEGER NOT NULL, - FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE - PRIMARY KEY(worktree_root, workspace_id) - ) STRICT;"}], + CREATE TABLE workspaces( + workspace_id INTEGER PRIMARY KEY, + timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL + ) STRICT; + + CREATE TABLE worktree_roots( + worktree_root BLOB NOT NULL, + workspace_id INTEGER NOT NULL, + FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE + PRIMARY KEY(worktree_root, workspace_id) + ) STRICT;"}], ); #[derive(Debug, PartialEq, Eq, Copy, Clone, Default)] @@ -159,9 +159,9 @@ impl Db { /// Returns the previous workspace ids sorted by last modified along with their opened worktree roots pub fn recent_workspaces(&self, limit: usize) -> Vec<(WorkspaceId, Vec>)> { - let res = self.with_savepoint("recent_workspaces", |conn| { + self.with_savepoint("recent_workspaces", |conn| { let ids = conn.prepare("SELECT workspace_id FROM workspaces ORDER BY last_opened_timestamp DESC LIMIT ?")? - .bind(limit)? + .with_bindings(limit)? .rows::()? .iter() .map(|row| WorkspaceId(*row)); @@ -170,7 +170,7 @@ impl Db { let stmt = conn.prepare("SELECT worktree_root FROM worktree_roots WHERE workspace_id = ?")?; for workspace_id in ids { - let roots = stmt.bind(workspace_id.0)? + let roots = stmt.with_bindings(workspace_id.0)? .rows::>()? .iter() .map(|row| { @@ -180,17 +180,11 @@ impl Db { result.push((workspace_id, roots)) } - Ok(result) - }); - - match res { - Ok(result) => result, - Err(err) => { - log::error!("Failed to get recent workspaces, err: {}", err); - Vec::new() - } - } + }).unwrap_or_else(|err| { + log::error!("Failed to get recent workspaces, err: {}", err); + Vec::new() + }) } } @@ -210,14 +204,14 @@ where connection.prepare( "DELETE FROM workspaces WHERE workspace_id = ?", )? - .bind(preexisting_id.0)? + .with_bindings(preexisting_id.0)? .exec()?; } } connection .prepare("DELETE FROM worktree_roots WHERE workspace_id = ?")? - .bind(workspace_id.0)? + .with_bindings(workspace_id.0)? .exec()?; for root in worktree_roots { @@ -226,12 +220,12 @@ where // let path = root.as_ref().to_string_lossy().to_string(); connection.prepare("INSERT INTO worktree_roots(workspace_id, worktree_root) VALUES (?, ?)")? - .bind((workspace_id.0, path))? + .with_bindings((workspace_id.0, path))? .exec()?; } connection.prepare("UPDATE workspaces SET last_opened_timestamp = CURRENT_TIMESTAMP WHERE workspace_id = ?")? - .bind(workspace_id.0)? + .with_bindings(workspace_id.0)? .exec()?; Ok(()) @@ -330,16 +324,11 @@ where // Make sure we bound the parameters correctly debug_assert!(worktree_roots.len() as i32 + 1 == stmt.parameter_count()); - for i in 0..worktree_roots.len() { - let path = &worktree_roots[i].as_ref().as_os_str().as_bytes(); - // If you need to debug this, here's the string parsing: - // let path = &worktree_roots[i].as_ref().to_string_lossy().to_string() - stmt.bind_value(*path, i as i32 + 1); - } - // No -1, because SQLite is 1 based - stmt.bind_value(worktree_roots.len(), worktree_roots.len() as i32 + 1)?; - - stmt.maybe_row() + let root_bytes: Vec<&[u8]> = worktree_roots.iter() + .map(|root| root.as_ref().as_os_str().as_bytes()).collect(); + + stmt.with_bindings((root_bytes, root_bytes.len()))? + .maybe_row() .map(|row| row.map(|id| WorkspaceId(id))) } diff --git a/crates/sqlez/src/bindable.rs b/crates/sqlez/src/bindable.rs index ca3ba401cf..9b8308f70c 100644 --- a/crates/sqlez/src/bindable.rs +++ b/crates/sqlez/src/bindable.rs @@ -207,3 +207,25 @@ impl Column for [T; COUNT] { Ok((array, current_index)) } } + +impl Bind for Vec { + fn bind(&self, statement: &Statement, start_index: i32) -> Result { + let mut current_index = start_index; + for binding in self.iter() { + current_index = binding.bind(statement, current_index)? + } + + Ok(current_index) + } +} + +impl Bind for &[T] { + fn bind(&self, statement: &Statement, start_index: i32) -> Result { + let mut current_index = start_index; + for binding in *self { + current_index = binding.bind(statement, current_index)? + } + + Ok(current_index) + } +} diff --git a/crates/sqlez/src/connection.rs b/crates/sqlez/src/connection.rs index be52978495..1fd814c580 100644 --- a/crates/sqlez/src/connection.rs +++ b/crates/sqlez/src/connection.rs @@ -149,7 +149,7 @@ mod test { connection .prepare("INSERT INTO text (text) VALUES (?);") .unwrap() - .bind(text) + .with_bindings(text) .unwrap() .exec() .unwrap(); @@ -185,8 +185,16 @@ mod test { .prepare("INSERT INTO test (text, integer, blob) VALUES (?, ?, ?)") .unwrap(); - insert.bind(tuple1.clone()).unwrap().exec().unwrap(); - insert.bind(tuple2.clone()).unwrap().exec().unwrap(); + insert + .with_bindings(tuple1.clone()) + .unwrap() + .exec() + .unwrap(); + insert + .with_bindings(tuple2.clone()) + .unwrap() + .exec() + .unwrap(); assert_eq!( connection diff --git a/crates/sqlez/src/migrations.rs b/crates/sqlez/src/migrations.rs index 3c0771c0fe..9f3bd333ca 100644 --- a/crates/sqlez/src/migrations.rs +++ b/crates/sqlez/src/migrations.rs @@ -47,7 +47,7 @@ impl Migration { WHERE domain = ? ORDER BY step "})? - .bind(self.domain)? + .with_bindings(self.domain)? .rows::<(String, usize, String)>()?; let mut store_completed_migration = connection @@ -72,7 +72,7 @@ impl Migration { connection.exec(migration)?; store_completed_migration - .bind((self.domain, index, *migration))? + .with_bindings((self.domain, index, *migration))? .exec()?; } @@ -163,7 +163,7 @@ mod test { .unwrap(); store_completed_migration - .bind((domain, i, i.to_string())) + .with_bindings((domain, i, i.to_string())) .unwrap() .exec() .unwrap(); diff --git a/crates/sqlez/src/savepoint.rs b/crates/sqlez/src/savepoint.rs index 50f28c7390..9589037e77 100644 --- a/crates/sqlez/src/savepoint.rs +++ b/crates/sqlez/src/savepoint.rs @@ -76,14 +76,14 @@ mod tests { connection.with_savepoint("first", |save1| { save1 .prepare("INSERT INTO text(text, idx) VALUES (?, ?)")? - .bind((save1_text, 1))? + .with_bindings((save1_text, 1))? .exec()?; assert!(save1 .with_savepoint("second", |save2| -> Result, anyhow::Error> { save2 .prepare("INSERT INTO text(text, idx) VALUES (?, ?)")? - .bind((save2_text, 2))? + .with_bindings((save2_text, 2))? .exec()?; assert_eq!( @@ -108,7 +108,7 @@ mod tests { save1.with_savepoint_rollback::<(), _>("second", |save2| { save2 .prepare("INSERT INTO text(text, idx) VALUES (?, ?)")? - .bind((save2_text, 2))? + .with_bindings((save2_text, 2))? .exec()?; assert_eq!( @@ -131,7 +131,7 @@ mod tests { save1.with_savepoint_rollback("second", |save2| { save2 .prepare("INSERT INTO text(text, idx) VALUES (?, ?)")? - .bind((save2_text, 2))? + .with_bindings((save2_text, 2))? .exec()?; assert_eq!( diff --git a/crates/sqlez/src/statement.rs b/crates/sqlez/src/statement.rs index ac57847774..06a090c417 100644 --- a/crates/sqlez/src/statement.rs +++ b/crates/sqlez/src/statement.rs @@ -179,10 +179,9 @@ impl<'a> Statement<'a> { Ok(str::from_utf8(slice)?) } - pub fn bind_value(&self, value: T, idx: i32) -> Result<()> { - debug_assert!(idx > 0); - value.bind(self, idx)?; - Ok(()) + pub fn bind(&self, value: T, index: i32) -> Result { + debug_assert!(index > 0); + value.bind(self, index) } pub fn column(&mut self) -> Result { @@ -203,8 +202,8 @@ impl<'a> Statement<'a> { } } - pub fn bind(&mut self, bindings: impl Bind) -> Result<&mut Self> { - self.bind_value(bindings, 1)?; + pub fn with_bindings(&mut self, bindings: impl Bind) -> Result<&mut Self> { + self.bind(bindings, 1)?; Ok(self) } diff --git a/crates/sqlez/src/thread_safe_connection.rs b/crates/sqlez/src/thread_safe_connection.rs index 53d49464be..f4f759cd6c 100644 --- a/crates/sqlez/src/thread_safe_connection.rs +++ b/crates/sqlez/src/thread_safe_connection.rs @@ -31,6 +31,8 @@ impl ThreadSafeConnection { self } + /// Migrations have to be run per connection because we fallback to memory + /// so this needs pub fn with_migrations(mut self, migrations: &'static [Migration]) -> Self { self.migrations = Some(migrations); self