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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resplite",
3
- "version": "1.4.18",
3
+ "version": "1.4.20",
4
4
  "description": "A RESP2 server with practical Redis compatibility, backed by SQLite",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -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 info = db.prepare('INSERT INTO search_rowid_allocator DEFAULT VALUES').run();
79
- return Number(info.lastInsertRowid);
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
 
@@ -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');