@dzhechkov/memory 0.2.3 → 0.2.4
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/dist/sqlite-backend.d.ts
CHANGED
|
@@ -34,7 +34,15 @@ export declare class SqliteBackend implements MemoryBackend {
|
|
|
34
34
|
static open(filePath: string): SqliteBackend;
|
|
35
35
|
put(record: MemoryRecord): Promise<void>;
|
|
36
36
|
query(query: MemoryQuery): Promise<MemoryRecord[]>;
|
|
37
|
+
/**
|
|
38
|
+
* Synchronous {@link SqliteBackend.query}. Same FTS5-ranked / keyword-fallback
|
|
39
|
+
* logic, no Promise — better-sqlite3 is physically synchronous, so a hot sync
|
|
40
|
+
* path (a recommender / `dz recall`) can query the store without an async ripple.
|
|
41
|
+
*/
|
|
42
|
+
querySync(query: MemoryQuery): MemoryRecord[];
|
|
37
43
|
all(): Promise<MemoryRecord[]>;
|
|
44
|
+
/** Synchronous {@link SqliteBackend.all}. */
|
|
45
|
+
allSync(): MemoryRecord[];
|
|
38
46
|
count(): Promise<number>;
|
|
39
47
|
/** Batch insert records within a transaction (for bulk loading). */
|
|
40
48
|
putMany(records: readonly MemoryRecord[]): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-backend.d.ts","sourceRoot":"","sources":["../src/sqlite-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAoF7E,iCAAiC;AACjC,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAM;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAM;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAkB;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEtB,EAAE,EAAE,GAAG;IAwBnB,4DAA4D;IAC5D,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa;IAW5C,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"sqlite-backend.d.ts","sourceRoot":"","sources":["../src/sqlite-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAoF7E,iCAAiC;AACjC,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,aAAa;IACjD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAM;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAM;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAM;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAM;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;IAChD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAkB;IACrD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;gBAEtB,EAAE,EAAE,GAAG;IAwBnB,4DAA4D;IAC5D,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa;IAW5C,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAaxC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIlD;;;;OAIG;IACH,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE;IAuD7C,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI9B,6CAA6C;IAC7C,OAAO,IAAI,YAAY,EAAE;IAIzB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxB,oEAAoE;IACpE,OAAO,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,IAAI;IAiB/C,qCAAqC;IACrC,KAAK,IAAI,IAAI;CAGd"}
|
package/dist/sqlite-backend.js
CHANGED
|
@@ -63,15 +63,15 @@ const FTS5_SQL = `
|
|
|
63
63
|
INSERT INTO memory_fts(rowid, text, skill_id) VALUES (new.rowid, new.text, new.skill_id);
|
|
64
64
|
END;
|
|
65
65
|
`;
|
|
66
|
-
/** FTS5 query —
|
|
66
|
+
/** FTS5 query — matching records with their relevance rank (lower = better). */
|
|
67
67
|
const FTS5_SEARCH_SQL = `
|
|
68
|
-
SELECT mr
|
|
68
|
+
SELECT mr.*, fts.rank AS _rank FROM memory_fts fts
|
|
69
69
|
JOIN memory_records mr ON mr.rowid = fts.rowid
|
|
70
70
|
WHERE memory_fts MATCH ?
|
|
71
71
|
ORDER BY fts.rank
|
|
72
72
|
`;
|
|
73
73
|
const FTS5_SEARCH_SKILL_SQL = `
|
|
74
|
-
SELECT mr
|
|
74
|
+
SELECT mr.*, fts.rank AS _rank FROM memory_fts fts
|
|
75
75
|
JOIN memory_records mr ON mr.rowid = fts.rowid
|
|
76
76
|
WHERE memory_fts MATCH ? AND mr.skill_id = ?
|
|
77
77
|
ORDER BY fts.rank
|
|
@@ -137,6 +137,14 @@ export class SqliteBackend {
|
|
|
137
137
|
return Promise.resolve();
|
|
138
138
|
}
|
|
139
139
|
query(query) {
|
|
140
|
+
return Promise.resolve(this.querySync(query));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Synchronous {@link SqliteBackend.query}. Same FTS5-ranked / keyword-fallback
|
|
144
|
+
* logic, no Promise — better-sqlite3 is physically synchronous, so a hot sync
|
|
145
|
+
* path (a recommender / `dz recall`) can query the store without an async ripple.
|
|
146
|
+
*/
|
|
147
|
+
querySync(query) {
|
|
140
148
|
const limit = query.limit ?? DEFAULT_LIMIT;
|
|
141
149
|
// FTS5 path — use SQLite full-text search when available and text query provided
|
|
142
150
|
if (this.hasFts5 && query.text !== undefined && query.text.trim().length > 0) {
|
|
@@ -151,10 +159,16 @@ export class SqliteBackend {
|
|
|
151
159
|
else {
|
|
152
160
|
rows = this.ftsSearchStmt.all(ftsQuery);
|
|
153
161
|
}
|
|
154
|
-
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
// Rank by FTS5 relevance FIRST (lower rank = better match), with score
|
|
163
|
+
// then timestamp as a true tiebreak between equally-relevant rows. Score
|
|
164
|
+
// must NOT be primary — that would discard FTS5's relevance signal and
|
|
165
|
+
// diverge from the JSON backend (which also ranks relevance-primary).
|
|
166
|
+
const ranked = rows
|
|
167
|
+
.map((row) => ({ record: rowToRecord(row), rank: row._rank }))
|
|
168
|
+
.sort((a, b) => a.rank - b.rank ||
|
|
169
|
+
b.record.score - a.record.score ||
|
|
170
|
+
b.record.timestamp.localeCompare(a.record.timestamp));
|
|
171
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
174
|
catch {
|
|
@@ -176,10 +190,14 @@ export class SqliteBackend {
|
|
|
176
190
|
.sort((a, b) => b.relevance - a.relevance ||
|
|
177
191
|
b.record.score - a.record.score ||
|
|
178
192
|
b.record.timestamp.localeCompare(a.record.timestamp));
|
|
179
|
-
return
|
|
193
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
180
194
|
}
|
|
181
195
|
all() {
|
|
182
|
-
return Promise.resolve(this.
|
|
196
|
+
return Promise.resolve(this.allSync());
|
|
197
|
+
}
|
|
198
|
+
/** Synchronous {@link SqliteBackend.all}. */
|
|
199
|
+
allSync() {
|
|
200
|
+
return this.allStmt.all().map(rowToRecord);
|
|
183
201
|
}
|
|
184
202
|
count() {
|
|
185
203
|
return Promise.resolve(this.countStmt.get().cnt);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite-backend.js","sourceRoot":"","sources":["../src/sqlite-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,2DAA2D;AAC3D,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,oEAAoE;AACpE,SAAS,WAAW,CAAC,MAAoB,EAAE,KAAwB;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACvE,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,IAAI,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4CAA4C;AAC5C,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,QAAQ,GAAG;;;;;;;;;;;;0BAYS,cAAc;CACvC,CAAC;AAEF,wDAAwD;AACxD,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"sqlite-backend.js","sourceRoot":"","sources":["../src/sqlite-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB,2DAA2D;AAC3D,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,IAAI;SACR,WAAW,EAAE;SACb,KAAK,CAAC,YAAY,CAAC;SACnB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,oEAAoE;AACpE,SAAS,WAAW,CAAC,MAAoB,EAAE,KAAwB;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACvE,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,IAAI,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4CAA4C;AAC5C,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,QAAQ,GAAG;;;;;;;;;;;;0BAYS,cAAc;CACvC,CAAC;AAEF,wDAAwD;AACxD,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;CAchB,CAAC;AAEF,gFAAgF;AAChF,MAAM,eAAe,GAAG;;;;;CAKvB,CAAC;AAEF,MAAM,qBAAqB,GAAG;;;;;CAK7B,CAAC;AAEF,MAAM,UAAU,GAAG;;;CAGlB,CAAC;AAEF,MAAM,OAAO,GAAG,8BAA8B,CAAC;AAC/C,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAC/D,MAAM,YAAY,GAAG,iDAAiD,CAAC;AAQvE;;;;;GAKG;AACH,MAAM,OAAO,aAAa;IACf,IAAI,GAAG,QAAQ,CAAC;IAER,EAAE,CAAM,CAAC,mCAAmC;IAC5C,UAAU,CAAM;IAChB,OAAO,CAAM;IACb,SAAS,CAAM;IACf,WAAW,CAAM;IACjB,aAAa,CAAkB;IAC/B,kBAAkB,CAAkB;IACpC,OAAO,CAAU;IAElC,YAAY,EAAO;QACjB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAElB,yDAAyD;QACzD,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,IAAI,CAAC;YACH,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAClB,oDAAoD;YACpD,EAAE,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;YACjE,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;YACjD,IAAI,CAAC,kBAAkB,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;YAC5D,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;QAAC,MAAM,CAAC;YACP,sDAAsD;QACxD,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9C,CAAC;IAED,4DAA4D;IAC5D,MAAM,CAAC,IAAI,CAAC,QAAgB;QAC1B,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,gEAAgE;QAChE,iEAAiE;QACjE,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAClC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAClC,OAAO,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,GAAG,CAAC,MAAoB;QACtB,IAAI,CAAC,UAAU,CAAC,GAAG,CACjB,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CACzD,CAAC;QACF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,KAAkB;QACtB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,KAAkB;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,aAAa,CAAC;QAE3C,iFAAiF;QACjF,IAAI,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7E,IAAI,CAAC;gBACH,oFAAoF;gBACpF,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACnD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,IAAI,IAAW,CAAC;oBAChB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;wBAChC,IAAI,GAAG,IAAI,CAAC,kBAAmB,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBAC/D,CAAC;yBAAM,CAAC;wBACN,IAAI,GAAG,IAAI,CAAC,aAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAC3C,CAAC;oBACD,uEAAuE;oBACvE,yEAAyE;oBACzE,uEAAuE;oBACvE,sEAAsE;oBACtE,MAAM,MAAM,GAAG,IAAI;yBAChB,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,KAAe,EAAE,CAAC,CAAC;yBACvE,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI;wBACf,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK;wBAC/B,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACvD,CAAC;oBACJ,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,6EAA6E;YAC/E,CAAC;QACH,CAAC;QAED,2BAA2B;QAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,IAAI,IAAW,CAAC;QAChB,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;QAC5B,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,OAAO;aACnB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;aACpE,IAAI,CACH,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS;YACzB,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK;YAC/B,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACvD,CAAC;QACJ,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED,GAAG;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,6CAA6C;IAC7C,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACnD,CAAC;IAED,oEAAoE;IACpE,OAAO,CAAC,OAAgC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,KAA8B,EAAE,EAAE;YACxE,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,UAAU,CAAC,GAAG,CACjB,MAAM,CAAC,EAAE,EACT,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,IAAI,EACX,MAAM,CAAC,KAAK,EACZ,MAAM,CAAC,OAAO,EACd,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CACzD,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;QACH,UAAU,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAED,qCAAqC;IACrC,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;CACF;AAED,kDAAkD;AAClD,SAAS,WAAW,CAAC,GAAQ;IAC3B,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;KAC9D,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
package/src/sqlite-backend.ts
CHANGED
|
@@ -72,16 +72,16 @@ const FTS5_SQL = `
|
|
|
72
72
|
END;
|
|
73
73
|
`;
|
|
74
74
|
|
|
75
|
-
/** FTS5 query —
|
|
75
|
+
/** FTS5 query — matching records with their relevance rank (lower = better). */
|
|
76
76
|
const FTS5_SEARCH_SQL = `
|
|
77
|
-
SELECT mr
|
|
77
|
+
SELECT mr.*, fts.rank AS _rank FROM memory_fts fts
|
|
78
78
|
JOIN memory_records mr ON mr.rowid = fts.rowid
|
|
79
79
|
WHERE memory_fts MATCH ?
|
|
80
80
|
ORDER BY fts.rank
|
|
81
81
|
`;
|
|
82
82
|
|
|
83
83
|
const FTS5_SEARCH_SKILL_SQL = `
|
|
84
|
-
SELECT mr
|
|
84
|
+
SELECT mr.*, fts.rank AS _rank FROM memory_fts fts
|
|
85
85
|
JOIN memory_records mr ON mr.rowid = fts.rowid
|
|
86
86
|
WHERE memory_fts MATCH ? AND mr.skill_id = ?
|
|
87
87
|
ORDER BY fts.rank
|
|
@@ -170,6 +170,15 @@ export class SqliteBackend implements MemoryBackend {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
query(query: MemoryQuery): Promise<MemoryRecord[]> {
|
|
173
|
+
return Promise.resolve(this.querySync(query));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Synchronous {@link SqliteBackend.query}. Same FTS5-ranked / keyword-fallback
|
|
178
|
+
* logic, no Promise — better-sqlite3 is physically synchronous, so a hot sync
|
|
179
|
+
* path (a recommender / `dz recall`) can query the store without an async ripple.
|
|
180
|
+
*/
|
|
181
|
+
querySync(query: MemoryQuery): MemoryRecord[] {
|
|
173
182
|
const limit = query.limit ?? DEFAULT_LIMIT;
|
|
174
183
|
|
|
175
184
|
// FTS5 path — use SQLite full-text search when available and text query provided
|
|
@@ -184,12 +193,19 @@ export class SqliteBackend implements MemoryBackend {
|
|
|
184
193
|
} else {
|
|
185
194
|
rows = this.ftsSearchStmt!.all(ftsQuery);
|
|
186
195
|
}
|
|
187
|
-
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
196
|
+
// Rank by FTS5 relevance FIRST (lower rank = better match), with score
|
|
197
|
+
// then timestamp as a true tiebreak between equally-relevant rows. Score
|
|
198
|
+
// must NOT be primary — that would discard FTS5's relevance signal and
|
|
199
|
+
// diverge from the JSON backend (which also ranks relevance-primary).
|
|
200
|
+
const ranked = rows
|
|
201
|
+
.map((row) => ({ record: rowToRecord(row), rank: row._rank as number }))
|
|
202
|
+
.sort(
|
|
203
|
+
(a, b) =>
|
|
204
|
+
a.rank - b.rank ||
|
|
205
|
+
b.record.score - a.record.score ||
|
|
206
|
+
b.record.timestamp.localeCompare(a.record.timestamp),
|
|
207
|
+
);
|
|
208
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
193
209
|
}
|
|
194
210
|
} catch {
|
|
195
211
|
// FTS5 query failed (e.g., special chars) — fall through to keyword approach
|
|
@@ -214,11 +230,16 @@ export class SqliteBackend implements MemoryBackend {
|
|
|
214
230
|
b.record.score - a.record.score ||
|
|
215
231
|
b.record.timestamp.localeCompare(a.record.timestamp),
|
|
216
232
|
);
|
|
217
|
-
return
|
|
233
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
218
234
|
}
|
|
219
235
|
|
|
220
236
|
all(): Promise<MemoryRecord[]> {
|
|
221
|
-
return Promise.resolve(this.
|
|
237
|
+
return Promise.resolve(this.allSync());
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** Synchronous {@link SqliteBackend.all}. */
|
|
241
|
+
allSync(): MemoryRecord[] {
|
|
242
|
+
return this.allStmt.all().map(rowToRecord);
|
|
222
243
|
}
|
|
223
244
|
|
|
224
245
|
count(): Promise<number> {
|