fix(kbdb): 刪 record 不再刪掉別人還指著的 entry(Arcrun#128 的必然配套)
上一筆讓 slot 可以指向既有 entry 之後,同一條 entry 會同時被別的 record 指著。 deleteRecord 舊寫法是「這筆 record 的每個 entry_id 都刪掉」,在共用的情況下會: · 把**別人還在用**的那條水池資料一起刪掉(他的 slot 從此指向不存在的列),或 · 撞上 `entry_values.entry_id REFERENCES entries(id)` 的 FK 而整個刪除失敗 ⇒ 條件改成「已經沒有任何 entry_values 指著它」才刪 (`DELETE FROM entries WHERE id = ? AND NOT EXISTS (SELECT 1 FROM entry_values WHERE entry_id = ?)`) **沒有共用時行為與舊版完全相同**:這筆 record 的關聯列已先刪掉,若沒有別人指著, NOT EXISTS 恆為真 ⇒ 照樣刪。差別只出現在真的被共用的那一條上。 驗(同檔 +2 條,真 SQLite 且 `PRAGMA foreign_keys = ON`) · 兩筆 record 共用一段、刪掉其中一筆:entries 2 → 1(只少掉那筆自己專屬的 title), 共用那條還在,另一筆 record 讀回來的 slot 值不受影響 · 沒有共用時:3 個 slot 的 entry 全刪、entry_values 歸零、getRecord 回 null(同舊版) kbdb 全套 232 綠 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -325,7 +325,19 @@ export async function searchByTemplate(db: D1Database, template: string, owner_i
|
||||
return ids.map((id) => byId.get(id)).filter((r): r is RecordResult => !!r);
|
||||
}
|
||||
|
||||
/** 刪除一筆 record:先刪 entry_values(FK),再刪底層 entries。回 false 表示 record 不存在。 */
|
||||
/**
|
||||
* 刪除一筆 record:先刪 entry_values(FK),再刪底層 entries。回 false 表示 record 不存在。
|
||||
*
|
||||
* 🔴 **還有別人指著的 entry 不刪**(Arcrun#128 的必然配套,不是順手加的):
|
||||
* slot 值可以指向既有 entry 之後,同一條 entry 會同時被別的 record 指著。
|
||||
* 舊寫法「這筆 record 的每個 entry_id 都刪掉」在那種情況下會:
|
||||
* · 把**別人還在用**的那條水池資料一起刪掉(他的 slot 從此指向不存在的列),或
|
||||
* · 撞上 `entry_values.entry_id REFERENCES entries(id)` 的 FK 而整個刪除失敗。
|
||||
* ⇒ 條件改成「已經沒有任何 entry_values 指著它」才刪。
|
||||
*
|
||||
* **沒有共用時行為與舊版完全相同**:這筆 record 的關聯列已先刪掉,若沒有別人指著,
|
||||
* `NOT EXISTS` 恆為真 ⇒ 照樣刪。差別只出現在「真的被共用」的那條上。
|
||||
*/
|
||||
export async function deleteRecord(db: D1Database, recordId: string): Promise<boolean> {
|
||||
const evRes = await db
|
||||
.prepare('SELECT entry_id FROM entry_values WHERE record_id = ?')
|
||||
@@ -335,7 +347,10 @@ export async function deleteRecord(db: D1Database, recordId: string): Promise<bo
|
||||
if (rows.length === 0) return false;
|
||||
await db.prepare('DELETE FROM entry_values WHERE record_id = ?').bind(recordId).run();
|
||||
for (const { entry_id } of rows) {
|
||||
await db.prepare('DELETE FROM entries WHERE id = ?').bind(entry_id).run();
|
||||
await db
|
||||
.prepare('DELETE FROM entries WHERE id = ? AND NOT EXISTS (SELECT 1 FROM entry_values WHERE entry_id = ?)')
|
||||
.bind(entry_id, entry_id)
|
||||
.run();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user