AtlatestRepositoryfolio

folio / tree / testtest-fts-replacement.sgl

1;;; FTS replacement must remove every literal-name row, including legacy rows.
2(import (sigil test)
3 (sigil fs)
4 (sigil path)
5 (sigil sqlite)
6 (folio store)
7 (folio index))
8
9(test-group "literal FTS replacement"
10 (test "updates and removal preserve unrelated names, arbitrary rowids and tokenless names"
11 (call-with-temp-directory
12 (lambda (root)
13 (let* ((store (make-folio-store root))
14 (idx (make-folio-index store))
15 (db (folio-index-db idx)))
16 (for-each
17 (lambda (name)
18 (let* ((path (path-join (store-notes-dir store)
19 (string-append name ".md")))
20 (sibling (string-append "guard-" name)))
21 (write-file-string path "# Before\nbeforeword\n")
22 (index-note! idx path)
23 ;; Standalone FTS rowids are unrelated to notes_meta rowids.
24 ;; Old/concurrent versions can leave more than one FTS row.
25 (assert-true
26 (sqlite-run db
27 "INSERT INTO notes_fts (name, title, tags, content) VALUES (?, ?, '', 'staleword')"
28 name name))
29 (assert-true
30 (sqlite-run db
31 "INSERT INTO notes_fts (name, title, tags, content) VALUES (?, ?, '', 'guardword')"
32 sibling name))
33 (write-file-string path "# After\nafterword\n")
34 (index-note! idx path)
35 (let ((rows (sqlite-query db
36 "SELECT content FROM notes_fts WHERE name = ?" name)))
37 (assert-equal 1 (length rows))
38 (assert-equal "# After\nafterword\n" (cdr (assoc 'content (car rows)))))
39 (assert-equal 1
40 (length (sqlite-query db "SELECT rowid FROM notes_fts WHERE name = ?" sibling)))
41 (remove-note-from-index! idx name)
42 (assert-equal '()
43 (sqlite-query db "SELECT rowid FROM notes_fts WHERE name = ?" name))
44 (assert-equal 1
45 (length (sqlite-query db "SELECT rowid FROM notes_fts WHERE name = ?" sibling)))))
46 '("normal" "a\"quoted" "中文" "---" "😀" "Case-Fold" "a.b" "with space"))
47 (sqlite-close db)))))
49 (test "a failed indexed lookup falls back to literal-name replacement"
50 (call-with-temp-directory
51 (lambda (root)
52 (let* ((store (make-folio-store root))
53 (idx (make-folio-index store))
54 (db (folio-index-db idx))
55 (path (path-join (store-notes-dir store) "one.md")))
56 ;; This table accepts the old literal DELETE but cannot run MATCH.
57 ;; It injects a lookup failure independently of note tokenization.
58 (assert-true (sqlite-exec db "DROP TABLE notes_fts"))
59 (assert-true
60 (sqlite-exec db
61 "CREATE TABLE notes_fts (name TEXT, title TEXT, tags TEXT, content TEXT)"))
62 (assert-true
63 (sqlite-run db
64 "INSERT INTO notes_fts VALUES ('one', 'Old', '', 'staleword')"))
65 (write-file-string path "# One\nafterword\n")
66 (index-note! idx path)
67 (let ((rows (sqlite-query db "SELECT content FROM notes_fts WHERE name = 'one'")))
68 (assert-equal 1 (length rows))
69 (assert-equal "# One\nafterword\n" (cdr (assoc 'content (car rows)))))
70 (sqlite-close db))))))