Moved docks to a better position

Mikayla Maki created

Change summary

crates/db/examples/serialize-pane.rs |   2 
crates/db/src/items.rs               |   3 
crates/db/src/pane.rs                | 166 +++++++++--------------
crates/db/src/workspace.rs           | 207 ++++++++++++++++++++++-------
4 files changed, 225 insertions(+), 153 deletions(-)

Detailed changes

crates/db/examples/serialize-pane.rs 🔗

@@ -1,6 +1,6 @@
 use std::{fs::File, path::Path};
 
-use db::pane::{DockAnchor, SerializedDockPane};
+use db::{pane::SerializedDockPane, DockAnchor};
 
 const TEST_FILE: &'static str = "test-db.db";
 

crates/db/src/items.rs 🔗

@@ -67,8 +67,7 @@
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct ItemId {
-    workspace_id: usize,
-    item_id: usize,
+    pub item_id: usize,
 }
 
 // enum SerializedItemKind {

crates/db/src/pane.rs 🔗

@@ -1,4 +1,3 @@
-use anyhow::bail;
 use gpui::Axis;
 use indoc::indoc;
 use sqlez::{
@@ -8,7 +7,7 @@ use sqlez::{
 };
 use util::{iife, ResultExt};
 
-use crate::{items::ItemId, workspace::WorkspaceId};
+use crate::{items::ItemId, workspace::WorkspaceId, DockAnchor};
 
 use super::Db;
 
@@ -33,14 +32,15 @@ CREATE TABLE panes(
     FOREIGN KEY(group_id) REFERENCES pane_groups(group_id) ON DELETE CASCADE
 ) STRICT;
 
-CREATE TABLE dock_panes(
-    pane_id INTEGER PRIMARY KEY,
-    workspace_id INTEGER NOT NULL,
-    anchor_position TEXT NOT NULL, -- Enum: 'Bottom' / 'Right' / 'Expanded'
-    visible INTEGER NOT NULL, -- Boolean
-    FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE
-    FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE
-) STRICT;
+-- MOVE TO WORKSPACE TABLE
+// CREATE TABLE dock_panes(
+//     pane_id INTEGER PRIMARY KEY,
+//     workspace_id INTEGER NOT NULL,
+//     anchor_position TEXT NOT NULL, -- Enum: 'Bottom' / 'Right' / 'Expanded'
+//     visible INTEGER NOT NULL, -- Boolean
+//     FOREIGN KEY(workspace_id) REFERENCES workspaces(workspace_id) ON DELETE CASCADE
+//     FOREIGN KEY(pane_id) REFERENCES panes(pane_id) ON DELETE CASCADE
+// ) STRICT;
 
 CREATE TABLE items(
     item_id INTEGER NOT NULL, -- This is the item's view id, so this is not unique
@@ -77,36 +77,34 @@ pub struct PaneId {
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub struct PaneGroupId {
     workspace_id: WorkspaceId,
-    group_id: usize,
 }
 
 impl PaneGroupId {
     pub fn root(workspace_id: WorkspaceId) -> Self {
         Self {
             workspace_id,
-            group_id: 0,
+            // group_id: 0,
         }
     }
 }
 
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq, Default)]
 pub struct SerializedPaneGroup {
-    group_id: PaneGroupId,
     axis: Axis,
     children: Vec<PaneGroupChild>,
 }
 
 impl SerializedPaneGroup {
-    pub fn empty_root(workspace_id: WorkspaceId) -> Self {
+    pub fn empty_root(_workspace_id: WorkspaceId) -> Self {
         Self {
-            group_id: PaneGroupId::root(workspace_id),
+            // group_id: PaneGroupId::root(workspace_id),
             axis: Default::default(),
             children: Default::default(),
         }
     }
 }
 
-struct PaneGroupChildRow {
+struct _PaneGroupChildRow {
     child_pane_id: Option<usize>,
     child_group_id: Option<usize>,
     index: usize,
@@ -120,47 +118,11 @@ pub enum PaneGroupChild {
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct SerializedPane {
-    pane_id: PaneId,
-    children: Vec<ItemId>,
+    items: Vec<ItemId>,
 }
 
 //********* CURRENTLY IN USE TYPES: *********
 
-#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
-pub enum DockAnchor {
-    #[default]
-    Bottom,
-    Right,
-    Expanded,
-}
-
-impl Bind for DockAnchor {
-    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
-        match self {
-            DockAnchor::Bottom => "Bottom",
-            DockAnchor::Right => "Right",
-            DockAnchor::Expanded => "Expanded",
-        }
-        .bind(statement, start_index)
-    }
-}
-
-impl Column for DockAnchor {
-    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
-        String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
-            Ok((
-                match anchor_text.as_ref() {
-                    "Bottom" => DockAnchor::Bottom,
-                    "Right" => DockAnchor::Right,
-                    "Expanded" => DockAnchor::Expanded,
-                    _ => bail!("Stored dock anchor is incorrect"),
-                },
-                next_index,
-            ))
-        })
-    }
-}
-
 #[derive(Default, Debug, PartialEq, Eq)]
 pub struct SerializedDockPane {
     pub anchor_position: DockAnchor,
@@ -227,56 +189,64 @@ impl Column for DockRow {
 }
 
 impl Db {
-    pub fn get_pane_group(&self, pane_group_id: PaneGroupId) -> SerializedPaneGroup {
-        let axis = self.get_pane_group_axis(pane_group_id);
-        let mut children: Vec<(usize, PaneGroupChild)> = Vec::new();
-        for child_row in self.get_pane_group_children(pane_group_id) {
-            if let Some(child_pane_id) = child_row.child_pane_id {
-                children.push((
-                    child_row.index,
-                    PaneGroupChild::Pane(self.get_pane(PaneId {
-                        workspace_id: pane_group_id.workspace_id,
-                        pane_id: child_pane_id,
-                    })),
-                ));
-            } else if let Some(child_group_id) = child_row.child_group_id {
-                children.push((
-                    child_row.index,
-                    PaneGroupChild::Group(self.get_pane_group(PaneGroupId {
-                        workspace_id: pane_group_id.workspace_id,
-                        group_id: child_group_id,
-                    })),
-                ));
-            }
-        }
-        children.sort_by_key(|(index, _)| *index);
+    pub fn get_center_group(&self, _workspace: WorkspaceId) -> SerializedPaneGroup {
+        unimplemented!()
+    }
 
-        SerializedPaneGroup {
-            group_id: pane_group_id,
-            axis,
-            children: children.into_iter().map(|(_, child)| child).collect(),
-        }
+    pub fn get_pane_group(&self, _pane_group_id: PaneGroupId) -> SerializedPaneGroup {
+        unimplemented!()
+        // let axis = self.get_pane_group_axis(pane_group_id);
+        // let mut children: Vec<(usize, PaneGroupChild)> = Vec::new();
+        // for child_row in self.get_pane_group_children(pane_group_id) {
+        //     if let Some(child_pane_id) = child_row.child_pane_id {
+        //         children.push((
+        //             child_row.index,
+        //             PaneGroupChild::Pane(self.get_pane(PaneId {
+        //                 workspace_id: pane_group_id.workspace_id,
+        //                 pane_id: child_pane_id,
+        //             })),
+        //         ));
+        //     } else if let Some(child_group_id) = child_row.child_group_id {
+        //         children.push((
+        //             child_row.index,
+        //             PaneGroupChild::Group(self.get_pane_group(PaneGroupId {
+        //                 workspace_id: pane_group_id.workspace_id,
+        //                 group_id: child_group_id,
+        //             })),
+        //         ));
+        //     }
+        // }
+        // children.sort_by_key(|(index, _)| *index);
+
+        // SerializedPaneGroup {
+        //     group_id: pane_group_id,
+        //     axis,
+        //     children: children.into_iter().map(|(_, child)| child).collect(),
+        // }
     }
 
-    fn get_pane_group_children(
+    fn _get_pane_group_children(
         &self,
         _pane_group_id: PaneGroupId,
-    ) -> impl Iterator<Item = PaneGroupChildRow> {
+    ) -> impl Iterator<Item = _PaneGroupChildRow> {
         Vec::new().into_iter()
     }
 
-    fn get_pane_group_axis(&self, _pane_group_id: PaneGroupId) -> Axis {
+    fn _get_pane_group_axis(&self, _pane_group_id: PaneGroupId) -> Axis {
         unimplemented!();
     }
 
-    pub fn save_pane_splits(&self, _center_pane_group: SerializedPaneGroup) {
+    pub fn save_pane_splits(
+        &self,
+        _workspace: &WorkspaceId,
+        _center_pane_group: &SerializedPaneGroup,
+    ) {
         // Delete the center pane group for this workspace and any of its children
         // Generate new pane group IDs as we go through
         // insert them
-        // Items garbage collect themselves when dropped
     }
 
-    pub(crate) fn get_pane(&self, _pane_id: PaneId) -> SerializedPane {
+    pub(crate) fn _get_pane(&self, _pane_id: PaneId) -> SerializedPane {
         unimplemented!();
     }
 
@@ -305,9 +275,9 @@ impl Db {
 #[cfg(test)]
 mod tests {
 
-    use crate::{pane::SerializedPane, Db};
+    use crate::{items::ItemId, pane::SerializedPane, Db, DockAnchor};
 
-    use super::{DockAnchor, SerializedDockPane};
+    use super::{PaneGroupChild, SerializedDockPane, SerializedPaneGroup};
 
     #[test]
     fn test_basic_dock_pane() {
@@ -333,18 +303,18 @@ mod tests {
 
         let workspace = db.workspace_for_roots(&["/tmp"]);
 
-        let center_pane = SerializedPane {
-            pane_id: crate::pane::PaneId {
-                workspace_id: workspace.workspace_id,
-                pane_id: 1,
-            },
-            children: vec![],
+        // Pane group -> Pane -> 10 , 20
+        let center_pane = SerializedPaneGroup {
+            axis: gpui::Axis::Horizontal,
+            children: vec![PaneGroupChild::Pane(SerializedPane {
+                items: vec![ItemId { item_id: 10 }, ItemId { item_id: 20 }],
+            })],
         };
 
-        db.save_dock_pane(&workspace.workspace_id, &dock_pane);
+        db.save_pane_splits(&workspace.workspace_id, &center_pane);
 
         let new_workspace = db.workspace_for_roots(&["/tmp"]);
 
-        assert_eq!(new_workspace.dock_pane.unwrap(), dock_pane);
+        assert_eq!(new_workspace.center_group, center_pane);
     }
 }

crates/db/src/workspace.rs 🔗

@@ -1,4 +1,4 @@
-use anyhow::Result;
+use anyhow::{bail, Result};
 
 use std::{
     ffi::OsStr,
@@ -16,7 +16,7 @@ use sqlez::{
     statement::Statement,
 };
 
-use crate::pane::SerializedDockPane;
+use crate::pane::{SerializedDockPane, SerializedPaneGroup};
 
 use super::Db;
 
@@ -28,7 +28,11 @@ pub(crate) const WORKSPACES_MIGRATION: Migration = Migration::new(
     &[indoc! {"
         CREATE TABLE workspaces(
             workspace_id INTEGER PRIMARY KEY,
+            center_pane_group INTEGER NOT NULL,
+            dock_anchor TEXT NOT NULL, -- Enum: 'Bottom' / 'Right' / 'Expanded'
+            dock_visible INTEGER NOT NULL, -- Boolean
             timestamp TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
+            FOREIGN KEY(center_pane_group) REFERENCES pane_groups(group_id)
         ) STRICT;
         
         CREATE TABLE worktree_roots(
@@ -54,10 +58,71 @@ impl Column for WorkspaceId {
     }
 }
 
+#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
+pub enum DockAnchor {
+    #[default]
+    Bottom,
+    Right,
+    Expanded,
+}
+
+impl Bind for DockAnchor {
+    fn bind(&self, statement: &Statement, start_index: i32) -> anyhow::Result<i32> {
+        match self {
+            DockAnchor::Bottom => "Bottom",
+            DockAnchor::Right => "Right",
+            DockAnchor::Expanded => "Expanded",
+        }
+        .bind(statement, start_index)
+    }
+}
+
+impl Column for DockAnchor {
+    fn column(statement: &mut Statement, start_index: i32) -> anyhow::Result<(Self, i32)> {
+        String::column(statement, start_index).and_then(|(anchor_text, next_index)| {
+            Ok((
+                match anchor_text.as_ref() {
+                    "Bottom" => DockAnchor::Bottom,
+                    "Right" => DockAnchor::Right,
+                    "Expanded" => DockAnchor::Expanded,
+                    _ => bail!("Stored dock anchor is incorrect"),
+                },
+                next_index,
+            ))
+        })
+    }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+struct WorkspaceRow {
+    pub workspace_id: WorkspaceId,
+    pub dock_anchor: DockAnchor,
+    pub dock_visible: bool,
+}
+
+impl Column for WorkspaceRow {
+    fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
+        <(WorkspaceId, DockAnchor, bool) as Column>::column(statement, start_index).map(
+            |((id, anchor, visible), next_index)| {
+                (
+                    WorkspaceRow {
+                        workspace_id: id,
+                        dock_anchor: anchor,
+                        dock_visible: visible,
+                    },
+                    next_index,
+                )
+            },
+        )
+    }
+}
+
 #[derive(Default, Debug)]
 pub struct SerializedWorkspace {
     pub workspace_id: WorkspaceId,
-    // pub center_group: SerializedPaneGroup,
+    pub center_group: SerializedPaneGroup,
+    pub dock_anchor: DockAnchor,
+    pub dock_visible: bool,
     pub dock_pane: Option<SerializedDockPane>,
 }
 
@@ -70,15 +135,18 @@ impl Db {
     {
         // Find the workspace id which is uniquely identified by this set of paths
         // return it if found
-        let mut workspace_id = self.workspace_id(worktree_roots);
-        if workspace_id.is_none() && worktree_roots.len() == 0 {
-            workspace_id = self.last_workspace_id();
+        let mut workspace_row = self.workspace(worktree_roots);
+        if workspace_row.is_none() && worktree_roots.len() == 0 {
+            workspace_row = self.last_workspace_id();
         }
 
-        if let Some(workspace_id) = workspace_id {
+        if let Some(workspace_row) = workspace_row {
             SerializedWorkspace {
-                workspace_id,
-                dock_pane: self.get_dock_pane(workspace_id),
+                dock_pane: self.get_dock_pane(workspace_row.workspace_id),
+                center_group: self.get_center_group(workspace_row.workspace_id),
+                workspace_id: workspace_row.workspace_id,
+                dock_anchor: workspace_row.dock_anchor,
+                dock_visible: workspace_row.dock_visible,
             }
         } else {
             self.make_new_workspace(worktree_roots)
@@ -99,7 +167,7 @@ impl Db {
 
             Ok(SerializedWorkspace {
                 workspace_id,
-                dock_pane: None,
+                ..Default::default()
             })
         });
 
@@ -112,11 +180,11 @@ impl Db {
         }
     }
 
-    fn workspace_id<P>(&self, worktree_roots: &[P]) -> Option<WorkspaceId>
+    fn workspace<P>(&self, worktree_roots: &[P]) -> Option<WorkspaceRow>
     where
         P: AsRef<Path> + Debug,
     {
-        match get_workspace_id(worktree_roots, &self) {
+        match get_workspace(worktree_roots, &self) {
             Ok(workspace_id) => workspace_id,
             Err(err) => {
                 log::error!("Failed to get workspace_id: {}", err);
@@ -149,11 +217,10 @@ impl Db {
         }
     }
 
-    fn last_workspace_id(&self) -> Option<WorkspaceId> {
+    fn last_workspace_id(&self) -> Option<WorkspaceRow> {
         let res = self
-            .prepare("SELECT workspace_id FROM workspaces ORDER BY timestamp DESC LIMIT 1")
-            .and_then(|mut stmt| stmt.maybe_row())
-            .map(|row| row.map(|id| WorkspaceId(id)));
+            .prepare("SELECT workspace_id, dock FROM workspaces ORDER BY timestamp DESC LIMIT 1")
+            .and_then(|mut stmt| stmt.maybe_row::<WorkspaceRow>());
 
         match res {
             Ok(result) => result,
@@ -206,13 +273,13 @@ where
     P: AsRef<Path> + Debug,
 {
     // Lookup any old WorkspaceIds which have the same set of roots, and delete them.
-    let preexisting_id = get_workspace_id(worktree_roots, &connection)?;
-    if let Some(preexisting_id) = preexisting_id {
-        if preexisting_id != *workspace_id {
+    let preexisting_workspace = get_workspace(worktree_roots, &connection)?;
+    if let Some(preexisting_workspace) = preexisting_workspace {
+        if preexisting_workspace.workspace_id != *workspace_id {
             // Should also delete fields in other tables with cascading updates
             connection
                 .prepare("DELETE FROM workspaces WHERE workspace_id = ?")?
-                .with_bindings(preexisting_id.0)?
+                .with_bindings(preexisting_workspace.workspace_id.0)?
                 .exec()?;
         }
     }
@@ -241,7 +308,7 @@ where
     Ok(())
 }
 
-fn get_workspace_id<P>(worktree_roots: &[P], connection: &Connection) -> Result<Option<WorkspaceId>>
+fn get_workspace<P>(worktree_roots: &[P], connection: &Connection) -> Result<Option<WorkspaceRow>>
 where
     P: AsRef<Path> + Debug,
 {
@@ -315,7 +382,7 @@ where
     //       parameters by number.
     let query = format!(
         r#"
-            SELECT workspace_id 
+            SELECT workspace_id, dock_anchor, dock_visible
             FROM (SELECT count(workspace_id) as num_matching, workspace_id FROM worktree_roots
                   WHERE worktree_root in {array_bind} AND workspace_id NOT IN
                     (SELECT wt1.workspace_id FROM worktree_roots as wt1
@@ -331,6 +398,7 @@ where
     // This will only be called on start up and when root workspaces change, no need to waste memory
     // caching it.
     let mut stmt = connection.prepare(&query)?;
+
     // Make sure we bound the parameters correctly
     debug_assert!(worktree_roots.len() as i32 + 1 == stmt.parameter_count());
 
@@ -339,11 +407,10 @@ where
         .map(|root| root.as_ref().as_os_str().as_bytes())
         .collect();
 
-    let len = root_bytes.len();
+    let num_of_roots = root_bytes.len();
 
-    stmt.with_bindings((root_bytes, len))?
-        .maybe_row()
-        .map(|row| row.map(|id| WorkspaceId(id)))
+    stmt.with_bindings((root_bytes, num_of_roots))?
+        .maybe_row::<WorkspaceRow>()
 }
 
 #[cfg(test)]
@@ -401,14 +468,17 @@ mod tests {
     fn test_empty_worktrees() {
         let db = Db::open_in_memory("test_empty_worktrees");
 
-        assert_eq!(None, db.workspace_id::<String>(&[]));
+        assert_eq!(None, db.workspace::<String>(&[]));
 
         db.make_new_workspace::<String>(&[]); //ID 1
         db.make_new_workspace::<String>(&[]); //ID 2
         db.update_worktrees(&WorkspaceId(1), &["/tmp", "/tmp2"]);
 
         // Sanity check
-        assert_eq!(db.workspace_id(&["/tmp", "/tmp2"]), Some(WorkspaceId(1)));
+        assert_eq!(
+            db.workspace(&["/tmp", "/tmp2"]).unwrap().workspace_id,
+            WorkspaceId(1)
+        );
 
         db.update_worktrees::<String>(&WorkspaceId(1), &[]);
 
@@ -416,9 +486,9 @@ mod tests {
         // call would be semantically correct (as those are the workspaces that
         // don't have roots) but I'd prefer that this API to either return exactly one
         // workspace, and None otherwise
-        assert_eq!(db.workspace_id::<String>(&[]), None,);
+        assert_eq!(db.workspace::<String>(&[]), None,);
 
-        assert_eq!(db.last_workspace_id(), Some(WorkspaceId(1)));
+        assert_eq!(db.last_workspace_id().unwrap().workspace_id, WorkspaceId(1));
 
         assert_eq!(
             db.recent_workspaces(2),
@@ -445,23 +515,42 @@ mod tests {
             db.update_worktrees(workspace_id, entries);
         }
 
-        assert_eq!(Some(WorkspaceId(1)), db.workspace_id(&["/tmp1"]));
-        assert_eq!(db.workspace_id(&["/tmp1", "/tmp2"]), Some(WorkspaceId(2)));
         assert_eq!(
-            db.workspace_id(&["/tmp1", "/tmp2", "/tmp3"]),
-            Some(WorkspaceId(3))
+            WorkspaceId(1),
+            db.workspace(&["/tmp1"]).unwrap().workspace_id
+        );
+        assert_eq!(
+            db.workspace(&["/tmp1", "/tmp2"]).unwrap().workspace_id,
+            WorkspaceId(2)
+        );
+        assert_eq!(
+            db.workspace(&["/tmp1", "/tmp2", "/tmp3"])
+                .unwrap()
+                .workspace_id,
+            WorkspaceId(3)
+        );
+        assert_eq!(
+            db.workspace(&["/tmp2", "/tmp3"]).unwrap().workspace_id,
+            WorkspaceId(4)
+        );
+        assert_eq!(
+            db.workspace(&["/tmp2", "/tmp3", "/tmp4"])
+                .unwrap()
+                .workspace_id,
+            WorkspaceId(5)
         );
-        assert_eq!(db.workspace_id(&["/tmp2", "/tmp3"]), Some(WorkspaceId(4)));
         assert_eq!(
-            db.workspace_id(&["/tmp2", "/tmp3", "/tmp4"]),
-            Some(WorkspaceId(5))
+            db.workspace(&["/tmp2", "/tmp4"]).unwrap().workspace_id,
+            WorkspaceId(6)
+        );
+        assert_eq!(
+            db.workspace(&["/tmp2"]).unwrap().workspace_id,
+            WorkspaceId(7)
         );
-        assert_eq!(db.workspace_id(&["/tmp2", "/tmp4"]), Some(WorkspaceId(6)));
-        assert_eq!(db.workspace_id(&["/tmp2"]), Some(WorkspaceId(7)));
 
-        assert_eq!(db.workspace_id(&["/tmp1", "/tmp5"]), None);
-        assert_eq!(db.workspace_id(&["/tmp5"]), None);
-        assert_eq!(db.workspace_id(&["/tmp2", "/tmp3", "/tmp4", "/tmp5"]), None);
+        assert_eq!(db.workspace(&["/tmp1", "/tmp5"]), None);
+        assert_eq!(db.workspace(&["/tmp5"]), None);
+        assert_eq!(db.workspace(&["/tmp2", "/tmp3", "/tmp4", "/tmp5"]), None);
     }
 
     #[test]
@@ -479,13 +568,21 @@ mod tests {
             db.update_worktrees(workspace_id, entries);
         }
 
-        assert_eq!(db.workspace_id(&["/tmp2"]), None);
-        assert_eq!(db.workspace_id(&["/tmp2", "/tmp3"]), None);
-        assert_eq!(db.workspace_id(&["/tmp"]), Some(WorkspaceId(1)));
-        assert_eq!(db.workspace_id(&["/tmp", "/tmp2"]), Some(WorkspaceId(2)));
+        assert_eq!(db.workspace(&["/tmp2"]), None);
+        assert_eq!(db.workspace(&["/tmp2", "/tmp3"]), None);
+        assert_eq!(
+            db.workspace(&["/tmp"]).unwrap().workspace_id,
+            WorkspaceId(1)
+        );
+        assert_eq!(
+            db.workspace(&["/tmp", "/tmp2"]).unwrap().workspace_id,
+            WorkspaceId(2)
+        );
         assert_eq!(
-            db.workspace_id(&["/tmp", "/tmp2", "/tmp3"]),
-            Some(WorkspaceId(3))
+            db.workspace(&["/tmp", "/tmp2", "/tmp3"])
+                .unwrap()
+                .workspace_id,
+            WorkspaceId(3)
         );
     }
 
@@ -526,15 +623,21 @@ mod tests {
         db.update_worktrees(&WorkspaceId(2), &["/tmp2", "/tmp3"]);
 
         // Make sure that workspace 3 doesn't exist
-        assert_eq!(db.workspace_id(&["/tmp2", "/tmp3"]), Some(WorkspaceId(2)));
+        assert_eq!(
+            db.workspace(&["/tmp2", "/tmp3"]).unwrap().workspace_id,
+            WorkspaceId(2)
+        );
 
         // And that workspace 1 was untouched
-        assert_eq!(db.workspace_id(&["/tmp"]), Some(WorkspaceId(1)));
+        assert_eq!(
+            db.workspace(&["/tmp"]).unwrap().workspace_id,
+            WorkspaceId(1)
+        );
 
         // And that workspace 2 is no longer registered under these roots
-        assert_eq!(db.workspace_id(&["/tmp", "/tmp2"]), None);
+        assert_eq!(db.workspace(&["/tmp", "/tmp2"]), None);
 
-        assert_eq!(Some(WorkspaceId(2)), db.last_workspace_id());
+        assert_eq!(db.last_workspace_id().unwrap().workspace_id, WorkspaceId(2));
 
         let recent_workspaces = db.recent_workspaces(10);
         assert_eq!(