@@ -25,7 +25,7 @@ pub use project::WorktreePaths;
use project::{AgentId, linked_worktree_short_name};
use remote::{RemoteConnectionOptions, same_remote_connection_identity};
use ui::{App, Context, SharedString, ThreadItemWorktreeInfo, WorktreeKind};
-use util::ResultExt as _;
+use util::{ResultExt as _, debug_panic};
use workspace::{PathList, SerializedWorkspaceLocation, WorkspaceDb};
use crate::DEFAULT_THREAD_TITLE;
@@ -593,20 +593,7 @@ impl ThreadMetadataStore {
this.threads_by_session.clear();
for row in rows {
- if let Some(sid) = &row.session_id {
- this.threads_by_session.insert(sid.clone(), row.thread_id);
- }
- this.threads_by_paths
- .entry(row.folder_paths().clone())
- .or_default()
- .insert(row.thread_id);
- if !row.main_worktree_paths().is_empty() {
- this.threads_by_main_paths
- .entry(row.main_worktree_paths().clone())
- .or_default()
- .insert(row.thread_id);
- }
- this.threads.insert(row.thread_id, row);
+ this.cache_thread_metadata(row);
}
cx.notify();
@@ -631,6 +618,11 @@ impl ThreadMetadataStore {
}
fn save_internal(&mut self, metadata: ThreadMetadata) {
+ if metadata.session_id.is_none() {
+ debug_panic!("cannot store thread metadata without a session_id");
+ return;
+ };
+
if let Some(thread) = self.threads.get(&metadata.thread_id) {
if thread.folder_paths() != metadata.folder_paths() {
if let Some(thread_ids) = self.threads_by_paths.get_mut(thread.folder_paths()) {
@@ -649,10 +641,20 @@ impl ThreadMetadataStore {
}
}
- if let Some(sid) = &metadata.session_id {
- self.threads_by_session
- .insert(sid.clone(), metadata.thread_id);
- }
+ self.cache_thread_metadata(metadata.clone());
+ self.pending_thread_ops_tx
+ .try_send(DbOperation::Upsert(metadata))
+ .log_err();
+ }
+
+ fn cache_thread_metadata(&mut self, metadata: ThreadMetadata) {
+ let Some(session_id) = metadata.session_id.as_ref() else {
+ debug_panic!("cannot store thread metadata without a session_id");
+ return;
+ };
+
+ self.threads_by_session
+ .insert(session_id.clone(), metadata.thread_id);
self.threads.insert(metadata.thread_id, metadata.clone());
@@ -667,10 +669,6 @@ impl ThreadMetadataStore {
.or_default()
.insert(metadata.thread_id);
}
-
- self.pending_thread_ops_tx
- .try_send(DbOperation::Upsert(metadata))
- .log_err();
}
pub fn update_working_directories(
@@ -1254,6 +1252,19 @@ impl Domain for ThreadMetadataDb {
DROP TABLE sidebar_threads;
ALTER TABLE sidebar_threads_v2 RENAME TO sidebar_threads;
),
+ sql!(
+ DELETE FROM thread_archived_worktrees
+ WHERE thread_id IN (
+ SELECT thread_id FROM sidebar_threads WHERE session_id IS NULL
+ );
+
+ DELETE FROM sidebar_threads WHERE session_id IS NULL;
+
+ DELETE FROM archived_git_worktrees
+ WHERE id NOT IN (
+ SELECT archived_worktree_id FROM thread_archived_worktrees
+ );
+ ),
];
}
@@ -1264,6 +1275,7 @@ impl ThreadMetadataDb {
pub fn list_ids(&self) -> anyhow::Result<Vec<ThreadId>> {
self.select::<ThreadId>(
"SELECT thread_id FROM sidebar_threads \
+ WHERE session_id IS NOT NULL \
ORDER BY updated_at DESC",
)?()
}
@@ -1273,12 +1285,18 @@ impl ThreadMetadataDb {
self.select::<ThreadMetadata>(
"SELECT thread_id, session_id, agent_id, title, updated_at, created_at, folder_paths, folder_paths_order, archived, main_worktree_paths, main_worktree_paths_order, remote_connection \
FROM sidebar_threads \
+ WHERE session_id IS NOT NULL \
ORDER BY updated_at DESC"
)?()
}
/// Upsert metadata for a thread.
pub async fn save(&self, row: ThreadMetadata) -> anyhow::Result<()> {
+ anyhow::ensure!(
+ row.session_id.is_some(),
+ "refusing to persist thread metadata without a session_id"
+ );
+
let session_id = row.session_id.as_ref().map(|s| s.0.clone());
let agent_id = if row.agent_id.as_ref() == ZED_AGENT_ID.as_ref() {
None
@@ -3370,7 +3388,8 @@ mod tests {
.unwrap()()
.unwrap();
- // Run all migrations (0-7). sqlez skips 0-6 and runs only migration 7.
+ // Run all current migrations. sqlez skips the already-applied ones and
+ // runs the remaining migrations.
connection
.migrate(
ThreadMetadataDb::NAME,