Skip to content

Commit 4f1b774

Browse files
authored
Merge pull request #253 from arabold/copilot/fix-delete-docs-bug
fix: delete pages before versions to prevent foreign key constraint failure
2 parents d157666 + 6820aef commit 4f1b774

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/store/DocumentStore.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,82 @@ describe("DocumentStore - With Embeddings", () => {
155155
expect(await store.checkDocumentExists("templib", "1.0.0")).toBe(false);
156156
});
157157

158+
it("should completely remove a version including pages and documents", async () => {
159+
const docs: Document[] = [
160+
{
161+
pageContent: "First document for removal test",
162+
metadata: {
163+
title: "Doc 1",
164+
url: "https://example.com/doc1",
165+
path: ["docs"],
166+
},
167+
},
168+
{
169+
pageContent: "Second document for removal test",
170+
metadata: {
171+
title: "Doc 2",
172+
url: "https://example.com/doc2",
173+
path: ["docs"],
174+
},
175+
},
176+
];
177+
178+
// Add documents and verify they exist
179+
await store.addDocuments("removelib", "1.0.0", docs);
180+
expect(await store.checkDocumentExists("removelib", "1.0.0")).toBe(true);
181+
182+
// Remove the version
183+
const result = await store.removeVersion("removelib", "1.0.0", true);
184+
185+
// Verify the results
186+
expect(result.documentsDeleted).toBe(2);
187+
expect(result.versionDeleted).toBe(true);
188+
expect(result.libraryDeleted).toBe(true);
189+
190+
// Verify documents no longer exist
191+
expect(await store.checkDocumentExists("removelib", "1.0.0")).toBe(false);
192+
});
193+
194+
it("should remove version but keep library when other versions exist", async () => {
195+
const v1Docs: Document[] = [
196+
{
197+
pageContent: "Version 1 document",
198+
metadata: {
199+
title: "V1 Doc",
200+
url: "https://example.com/v1",
201+
path: ["v1"],
202+
},
203+
},
204+
];
205+
206+
const v2Docs: Document[] = [
207+
{
208+
pageContent: "Version 2 document",
209+
metadata: {
210+
title: "V2 Doc",
211+
url: "https://example.com/v2",
212+
path: ["v2"],
213+
},
214+
},
215+
];
216+
217+
// Add two versions
218+
await store.addDocuments("multilib", "1.0.0", v1Docs);
219+
await store.addDocuments("multilib", "2.0.0", v2Docs);
220+
221+
// Remove only version 1.0.0
222+
const result = await store.removeVersion("multilib", "1.0.0", true);
223+
224+
// Verify version 1 was deleted but library remains
225+
expect(result.documentsDeleted).toBe(1);
226+
expect(result.versionDeleted).toBe(true);
227+
expect(result.libraryDeleted).toBe(false);
228+
229+
// Verify version 1 no longer exists but version 2 does
230+
expect(await store.checkDocumentExists("multilib", "1.0.0")).toBe(false);
231+
expect(await store.checkDocumentExists("multilib", "2.0.0")).toBe(true);
232+
});
233+
158234
it("should handle multiple versions of the same library", async () => {
159235
const v1Docs: Document[] = [
160236
{

src/store/DocumentStore.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ export class DocumentStore {
8080
getPageId: Database.Statement<[number, string]>;
8181
deleteDocuments: Database.Statement<[string, string]>;
8282
deleteDocumentsByUrl: Database.Statement<[string, string, string]>;
83+
deletePages: Database.Statement<[string, string]>;
8384
queryVersions: Database.Statement<[string]>;
8485
checkExists: Database.Statement<[string, string]>;
8586
queryLibraryVersions: Database.Statement<[]>;
@@ -238,6 +239,14 @@ export class DocumentStore {
238239
WHERE p.url = ? AND l.name = ? AND COALESCE(v.name, '') = COALESCE(?, '')
239240
)`,
240241
),
242+
deletePages: this.db.prepare<[string, string]>(
243+
`DELETE FROM pages
244+
WHERE version_id IN (
245+
SELECT v.id FROM versions v
246+
JOIN libraries l ON v.library_id = l.id
247+
WHERE l.name = ? AND COALESCE(v.name, '') = COALESCE(?, '')
248+
)`,
249+
),
241250
getDocumentBySort: this.db.prepare<[string, string]>(
242251
`SELECT d.id
243252
FROM documents d
@@ -1093,9 +1102,18 @@ export class DocumentStore {
10931102

10941103
const { id: versionId, library_id: libraryId } = versionResult;
10951104

1105+
// Delete in order to respect foreign key constraints:
1106+
// 1. documents (page_id → pages.id)
1107+
// 2. pages (version_id → versions.id)
1108+
// 3. versions (library_id → libraries.id)
1109+
// 4. libraries (if empty)
1110+
10961111
// Delete all documents for this version
10971112
const documentsDeleted = await this.deleteDocuments(library, version);
10981113

1114+
// Delete all pages for this version (must be done after documents, before version)
1115+
this.statements.deletePages.run(normalizedLibrary, normalizedVersion);
1116+
10991117
// Delete the version record
11001118
const versionDeleteResult = this.statements.deleteVersionById.run(versionId);
11011119
const versionDeleted = versionDeleteResult.changes > 0;

0 commit comments

Comments
 (0)