fix(sql): preserve file associations and list selection

This commit is contained in:
zipg authored and GitHub committed 2026-08-13 11:44:55 +08:00
1 parent 2e27f7a66a
commit e5a3917f7d
25 files changed
+558 -186

No files matched your search

+76 -28
View File
@@ -394,6 +394,7 @@ const SCHEMA_STATEMENTS: &[&str] = &[
folder_id TEXT,
name TEXT NOT NULL DEFAULT '',
database_name TEXT NOT NULL DEFAULT '',
catalog_name TEXT,
schema_name TEXT,
sql_text TEXT NOT NULL DEFAULT '',
order_index INTEGER NOT NULL DEFAULT 0,
@@ -555,6 +556,7 @@ fn ensure_saved_sql_columns_sync(conn: &Connection) -> Result<(), String> {
const FOLDER_COLUMNS: &[(&str, &str)] =
&[("parent_folder_id", "TEXT"), ("order_index", "INTEGER NOT NULL DEFAULT 0")];
const FILE_COLUMNS: &[(&str, &str)] = &[
("catalog_name", "TEXT"),
("order_index", "INTEGER NOT NULL DEFAULT 0"),
("open_count", "INTEGER NOT NULL DEFAULT 0"),
("opened_at", "TEXT"),
@@ -2863,14 +2865,15 @@ impl Storage {
for file in &library.files {
tx.execute(
"INSERT INTO saved_sql_files \
(id, connection_id, folder_id, name, database_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(id, connection_id, folder_id, name, database_name, catalog_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
params![
file.id,
file.connection_id,
file.folder_id,
file.name,
file.database,
file.catalog,
file.schema,
file.sql,
file.order_index,
@@ -2914,7 +2917,7 @@ impl Storage {
let mut file_stmt = conn
.prepare(
"SELECT id, connection_id, folder_id, name, database_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at \
"SELECT id, connection_id, folder_id, name, database_name, catalog_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at \
FROM saved_sql_files ORDER BY COALESCE(folder_id, ''), order_index, connection_id, name COLLATE NOCASE",
)
.map_err(|e| e.to_string())?;
@@ -2926,14 +2929,15 @@ impl Storage {
folder_id: row.get(2)?,
name: row.get(3)?,
database: row.get(4)?,
schema: row.get(5)?,
sql: row.get(6)?,
catalog: row.get(5)?,
schema: row.get(6)?,
sql: row.get(7)?,
sql_loaded: true,
order_index: row.get(7)?,
open_count: row.get(8)?,
opened_at: row.get(9)?,
created_at: row.get(10)?,
updated_at: row.get(11)?,
order_index: row.get(8)?,
open_count: row.get(9)?,
opened_at: row.get(10)?,
created_at: row.get(11)?,
updated_at: row.get(12)?,
})
})
.map_err(|e| e.to_string())?
@@ -2971,7 +2975,7 @@ impl Storage {
let mut file_stmt = conn
.prepare(
"SELECT id, connection_id, folder_id, name, database_name, schema_name, order_index, open_count, opened_at, created_at, updated_at \
"SELECT id, connection_id, folder_id, name, database_name, catalog_name, schema_name, order_index, open_count, opened_at, created_at, updated_at \
FROM saved_sql_files ORDER BY COALESCE(folder_id, ''), order_index, connection_id, name COLLATE NOCASE",
)
.map_err(|e| e.to_string())?;
@@ -2983,14 +2987,15 @@ impl Storage {
folder_id: row.get(2)?,
name: row.get(3)?,
database: row.get(4)?,
schema: row.get(5)?,
catalog: row.get(5)?,
schema: row.get(6)?,
sql: String::new(),
sql_loaded: false,
order_index: row.get(6)?,
open_count: row.get(7)?,
opened_at: row.get(8)?,
created_at: row.get(9)?,
updated_at: row.get(10)?,
order_index: row.get(7)?,
open_count: row.get(8)?,
opened_at: row.get(9)?,
created_at: row.get(10)?,
updated_at: row.get(11)?,
})
})
.map_err(|e| e.to_string())?
@@ -3007,7 +3012,7 @@ impl Storage {
self.with_conn(move |conn| {
let mut stmt = conn
.prepare(
"SELECT id, connection_id, folder_id, name, database_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at \
"SELECT id, connection_id, folder_id, name, database_name, catalog_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at \
FROM saved_sql_files WHERE id = ?1",
)
.map_err(|e| e.to_string())?;
@@ -3018,14 +3023,15 @@ impl Storage {
folder_id: row.get(2)?,
name: row.get(3)?,
database: row.get(4)?,
schema: row.get(5)?,
sql: row.get(6)?,
catalog: row.get(5)?,
schema: row.get(6)?,
sql: row.get(7)?,
sql_loaded: true,
order_index: row.get(7)?,
open_count: row.get(8)?,
opened_at: row.get(9)?,
created_at: row.get(10)?,
updated_at: row.get(11)?,
order_index: row.get(8)?,
open_count: row.get(9)?,
opened_at: row.get(10)?,
created_at: row.get(11)?,
updated_at: row.get(12)?,
})
}) {
Ok(file) => Ok(Some(file)),
@@ -3099,15 +3105,16 @@ impl Storage {
self.with_conn(move |conn| {
conn.execute(
"INSERT INTO saved_sql_files \
(id, connection_id, folder_id, name, database_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) \
(id, connection_id, folder_id, name, database_name, catalog_name, schema_name, sql_text, order_index, open_count, opened_at, created_at, updated_at) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) \
ON CONFLICT(id) DO UPDATE SET \
connection_id = excluded.connection_id, \
folder_id = excluded.folder_id, \
name = excluded.name, \
database_name = excluded.database_name, \
catalog_name = excluded.catalog_name, \
schema_name = excluded.schema_name, \
sql_text = CASE WHEN ?13 THEN excluded.sql_text ELSE saved_sql_files.sql_text END, \
sql_text = CASE WHEN ?14 THEN excluded.sql_text ELSE saved_sql_files.sql_text END, \
order_index = excluded.order_index, \
open_count = excluded.open_count, \
opened_at = excluded.opened_at, \
@@ -3118,6 +3125,7 @@ impl Storage {
file.folder_id,
file.name,
file.database,
file.catalog,
file.schema,
file.sql,
file.order_index,
@@ -5567,6 +5575,42 @@ mod tests {
assert!(entry.last_accessed_at >= entry.created_at);
}
#[tokio::test]
async fn saved_sql_catalog_column_migrates_legacy_database() {
let path = temp_db_path("saved-sql-catalog-migration");
{
let connection = Connection::open(&path).unwrap();
connection
.execute_batch(
"CREATE TABLE saved_sql_files (
id TEXT PRIMARY KEY,
connection_id TEXT NOT NULL,
folder_id TEXT,
name TEXT NOT NULL DEFAULT '',
database_name TEXT NOT NULL DEFAULT '',
schema_name TEXT,
sql_text TEXT NOT NULL DEFAULT '',
order_index INTEGER NOT NULL DEFAULT 0,
open_count INTEGER NOT NULL DEFAULT 0,
opened_at TEXT,
created_at TEXT NOT NULL DEFAULT '',
updated_at TEXT NOT NULL DEFAULT ''
);
INSERT INTO saved_sql_files
(id, connection_id, name, database_name, sql_text, created_at, updated_at)
VALUES
('legacy-sql', 'conn-1', 'legacy.sql', 'sales', 'SELECT 1;', '2026-01-01', '2026-01-01');",
)
.unwrap();
}
let storage = Storage::open(&path).await.unwrap();
let loaded = storage.load_saved_sql_file("legacy-sql").await.unwrap().unwrap();
assert_eq!(loaded.database, "sales");
assert_eq!(loaded.catalog, None);
}
#[tokio::test]
async fn saved_sql_summary_omits_sql_text_and_loads_file_on_demand() {
let path = temp_db_path("saved-sql-summary");
@@ -5577,6 +5621,7 @@ mod tests {
folder_id: None,
name: "large.sql".to_string(),
database: "main".to_string(),
catalog: Some("hive".to_string()),
schema: None,
sql: "SELECT * FROM very_large_table;".repeat(100),
sql_loaded: true,
@@ -5592,10 +5637,12 @@ mod tests {
let summary = storage.load_saved_sql_library_summary().await.unwrap();
assert_eq!(summary.files.len(), 1);
assert_eq!(summary.files[0].sql, "");
assert_eq!(summary.files[0].catalog.as_deref(), Some("hive"));
assert!(!summary.files[0].sql_loaded);
let loaded = storage.load_saved_sql_file("sql-1").await.unwrap().unwrap();
assert_eq!(loaded.sql, file.sql);
assert_eq!(loaded.catalog.as_deref(), Some("hive"));
assert!(loaded.sql_loaded);
}
@@ -5609,6 +5656,7 @@ mod tests {
folder_id: None,
name: "query.sql".to_string(),
database: "main".to_string(),
catalog: None,
schema: None,
sql: "SELECT 1;".to_string(),
sql_loaded: true,