resplite 1.4.18 → 1.4.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/storage/sqlite/search.js +11 -5
- package/test/unit/search.test.js +20 -0
package/package.json
CHANGED
|
@@ -72,11 +72,17 @@ function deleteFtsRow(db, ftsTableName, ftsRowid, fieldNames, fields) {
|
|
|
72
72
|
* Allocate a monotonic FTS rowid that is never reused, even after deletes.
|
|
73
73
|
* This prevents legacy stale tokens from being remapped to a new document.
|
|
74
74
|
* @param {import('better-sqlite3').Database} db
|
|
75
|
+
* @param {string} docmapTableName
|
|
75
76
|
* @returns {number}
|
|
76
77
|
*/
|
|
77
|
-
function allocateFtsRowid(db) {
|
|
78
|
-
const
|
|
79
|
-
|
|
78
|
+
function allocateFtsRowid(db, docmapTableName) {
|
|
79
|
+
const maxDocmapRowid = db
|
|
80
|
+
.prepare(`SELECT COALESCE(MAX(fts_rowid), 0) AS m FROM ${docmapTableName}`)
|
|
81
|
+
.get().m;
|
|
82
|
+
const maxAllocated = db.prepare('SELECT COALESCE(MAX(id), 0) AS m FROM search_rowid_allocator').get().m;
|
|
83
|
+
const nextRowid = Math.max(maxDocmapRowid, maxAllocated) + 1;
|
|
84
|
+
db.prepare('INSERT INTO search_rowid_allocator(id) VALUES (?)').run(nextRowid);
|
|
85
|
+
return nextRowid;
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
/**
|
|
@@ -206,7 +212,7 @@ export function addDocument(db, idx, docId, score, replace, fields) {
|
|
|
206
212
|
if (existing) {
|
|
207
213
|
if (!replace) throw new Error('ERR document exists');
|
|
208
214
|
const previousRowid = existing.fts_rowid;
|
|
209
|
-
ftsRowid = allocateFtsRowid(db);
|
|
215
|
+
ftsRowid = allocateFtsRowid(db, docmapT);
|
|
210
216
|
db.prepare(`UPDATE ${docmapT} SET fts_rowid = ? WHERE doc_id = ?`).run(ftsRowid, docId);
|
|
211
217
|
const oldDoc = db.prepare(`SELECT fields_json FROM ${docsT} WHERE doc_id = ?`).get(docId);
|
|
212
218
|
if (oldDoc?.fields_json) {
|
|
@@ -214,7 +220,7 @@ export function addDocument(db, idx, docId, score, replace, fields) {
|
|
|
214
220
|
deleteFtsRow(db, ftsT, previousRowid, fieldNames, oldFields);
|
|
215
221
|
}
|
|
216
222
|
} else {
|
|
217
|
-
ftsRowid = allocateFtsRowid(db);
|
|
223
|
+
ftsRowid = allocateFtsRowid(db, docmapT);
|
|
218
224
|
db.prepare(`INSERT INTO ${docmapT}(doc_id, fts_rowid) VALUES (?, ?)`).run(docId, ftsRowid);
|
|
219
225
|
}
|
|
220
226
|
|
package/test/unit/search.test.js
CHANGED
|
@@ -113,6 +113,26 @@ describe('Search layer', () => {
|
|
|
113
113
|
assert.equal(search(db, 'legacy_stale', 'bicho*', { noContent: true }).total, 0);
|
|
114
114
|
});
|
|
115
115
|
|
|
116
|
+
it('allocator seeds above existing docmap rowids on legacy databases', () => {
|
|
117
|
+
createIndex(db, 'legacy_seed', [{ name: 'payload', type: 'TEXT' }]);
|
|
118
|
+
const docsT = 'search_docs__legacy_seed';
|
|
119
|
+
const docmapT = 'search_docmap__legacy_seed';
|
|
120
|
+
const ftsT = 'search_fts__legacy_seed';
|
|
121
|
+
const now = Date.now();
|
|
122
|
+
|
|
123
|
+
db.prepare(
|
|
124
|
+
`INSERT INTO ${docsT}(doc_id, score, fields_json, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`
|
|
125
|
+
).run('old-doc', 1, JSON.stringify({ payload: 'legacy payload' }), now, now);
|
|
126
|
+
db.prepare(`INSERT INTO ${docmapT}(doc_id, fts_rowid) VALUES (?, ?)`).run('old-doc', 42);
|
|
127
|
+
db.prepare(`INSERT INTO ${ftsT}(rowid, payload) VALUES (?, ?)`).run(42, 'legacy payload');
|
|
128
|
+
|
|
129
|
+
addDocument(db, 'legacy_seed', 'new-doc', 1, true, { payload: 'fresh payload' });
|
|
130
|
+
|
|
131
|
+
const newMap = db.prepare(`SELECT fts_rowid FROM ${docmapT} WHERE doc_id = ?`).get('new-doc');
|
|
132
|
+
assert.ok(newMap.fts_rowid > 42);
|
|
133
|
+
assert.equal(search(db, 'legacy_seed', 'fresh*', { noContent: true }).total, 1);
|
|
134
|
+
});
|
|
135
|
+
|
|
116
136
|
it('search with NOCONTENT returns total and doc ids', () => {
|
|
117
137
|
const r = search(db, 'names', 'hello', { noContent: true, offset: 0, count: 10 });
|
|
118
138
|
assert.equal(typeof r.total, 'number');
|