@dzhechkov/memory 0.2.2 → 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/json-backend.d.ts +12 -0
- package/dist/json-backend.d.ts.map +1 -1
- package/dist/json-backend.js +25 -3
- package/dist/json-backend.js.map +1 -1
- package/dist/sqlite-backend.d.ts +8 -0
- package/dist/sqlite-backend.d.ts.map +1 -1
- package/dist/sqlite-backend.js +27 -9
- package/dist/sqlite-backend.js.map +1 -1
- package/package.json +1 -1
- package/src/json-backend.ts +29 -3
- package/src/sqlite-backend.ts +32 -11
package/dist/json-backend.d.ts
CHANGED
|
@@ -21,13 +21,25 @@ export declare class JsonFileBackend implements MemoryBackend {
|
|
|
21
21
|
constructor(options?: JsonFileBackendOptions);
|
|
22
22
|
/** Create a backend and load any records already persisted at `filePath`. */
|
|
23
23
|
static open(filePath: string): Promise<JsonFileBackend>;
|
|
24
|
+
/**
|
|
25
|
+
* Synchronous counterpart to {@link JsonFileBackend.open}. Because this backend
|
|
26
|
+
* is physically synchronous (in-memory map + sync `fs`), a hot sync path (e.g.
|
|
27
|
+
* a recommender) can read the store without an async ripple.
|
|
28
|
+
*/
|
|
29
|
+
static openSync(filePath: string): JsonFileBackend;
|
|
24
30
|
put(record: MemoryRecord): Promise<void>;
|
|
25
31
|
query(query: MemoryQuery): Promise<MemoryRecord[]>;
|
|
32
|
+
/** Synchronous {@link JsonFileBackend.query} — same ranking, no Promise. */
|
|
33
|
+
querySync(query: MemoryQuery): MemoryRecord[];
|
|
26
34
|
all(): Promise<MemoryRecord[]>;
|
|
35
|
+
/** Synchronous {@link JsonFileBackend.all}. */
|
|
36
|
+
allSync(): MemoryRecord[];
|
|
27
37
|
count(): Promise<number>;
|
|
28
38
|
/** Persist every record to `filePath`. No-op when no path is configured. */
|
|
29
39
|
save(): Promise<void>;
|
|
30
40
|
/** Load records from `filePath`. No-op when no path is set or the file is absent. */
|
|
31
41
|
load(): Promise<void>;
|
|
42
|
+
/** Synchronous {@link JsonFileBackend.load}. */
|
|
43
|
+
loadSync(): void;
|
|
32
44
|
}
|
|
33
45
|
//# sourceMappingURL=json-backend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-backend.d.ts","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAuB7E,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,eAAe;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,OAAO,GAAE,sBAA2B;IAIhD,6EAA6E;WAChE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAM7D,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"json-backend.d.ts","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAuB7E,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,eAAe;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,OAAO,GAAE,sBAA2B;IAIhD,6EAA6E;WAChE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAM7D;;;;OAIG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe;IAMlD,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIlD,4EAA4E;IAC5E,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,YAAY,EAAE;IAkB7C,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI9B,+CAA+C;IAC/C,OAAO,IAAI,YAAY,EAAE;IAIzB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxB,4EAA4E;IAC5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,qFAAqF;IACrF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrB,gDAAgD;IAChD,QAAQ,IAAI,IAAI;CAMjB"}
|
package/dist/json-backend.js
CHANGED
|
@@ -43,11 +43,25 @@ export class JsonFileBackend {
|
|
|
43
43
|
await backend.load();
|
|
44
44
|
return backend;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Synchronous counterpart to {@link JsonFileBackend.open}. Because this backend
|
|
48
|
+
* is physically synchronous (in-memory map + sync `fs`), a hot sync path (e.g.
|
|
49
|
+
* a recommender) can read the store without an async ripple.
|
|
50
|
+
*/
|
|
51
|
+
static openSync(filePath) {
|
|
52
|
+
const backend = new JsonFileBackend({ filePath });
|
|
53
|
+
backend.loadSync();
|
|
54
|
+
return backend;
|
|
55
|
+
}
|
|
46
56
|
put(record) {
|
|
47
57
|
this.records.set(record.id, record);
|
|
48
58
|
return Promise.resolve();
|
|
49
59
|
}
|
|
50
60
|
query(query) {
|
|
61
|
+
return Promise.resolve(this.querySync(query));
|
|
62
|
+
}
|
|
63
|
+
/** Synchronous {@link JsonFileBackend.query} — same ranking, no Promise. */
|
|
64
|
+
querySync(query) {
|
|
51
65
|
const limit = query.limit ?? DEFAULT_LIMIT;
|
|
52
66
|
const terms = query.text !== undefined ? tokenize(query.text) : [];
|
|
53
67
|
let candidates = [...this.records.values()];
|
|
@@ -59,10 +73,14 @@ export class JsonFileBackend {
|
|
|
59
73
|
.sort((a, b) => b.relevance - a.relevance ||
|
|
60
74
|
b.record.score - a.record.score ||
|
|
61
75
|
b.record.timestamp.localeCompare(a.record.timestamp));
|
|
62
|
-
return
|
|
76
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
63
77
|
}
|
|
64
78
|
all() {
|
|
65
|
-
return Promise.resolve(
|
|
79
|
+
return Promise.resolve(this.allSync());
|
|
80
|
+
}
|
|
81
|
+
/** Synchronous {@link JsonFileBackend.all}. */
|
|
82
|
+
allSync() {
|
|
83
|
+
return [...this.records.values()];
|
|
66
84
|
}
|
|
67
85
|
count() {
|
|
68
86
|
return Promise.resolve(this.records.size);
|
|
@@ -77,12 +95,16 @@ export class JsonFileBackend {
|
|
|
77
95
|
}
|
|
78
96
|
/** Load records from `filePath`. No-op when no path is set or the file is absent. */
|
|
79
97
|
load() {
|
|
98
|
+
this.loadSync();
|
|
99
|
+
return Promise.resolve();
|
|
100
|
+
}
|
|
101
|
+
/** Synchronous {@link JsonFileBackend.load}. */
|
|
102
|
+
loadSync() {
|
|
80
103
|
if (this.filePath !== undefined && existsSync(this.filePath)) {
|
|
81
104
|
const data = JSON.parse(readFileSync(this.filePath, 'utf-8'));
|
|
82
105
|
for (const record of data)
|
|
83
106
|
this.records.set(record.id, record);
|
|
84
107
|
}
|
|
85
|
-
return Promise.resolve();
|
|
86
108
|
}
|
|
87
109
|
}
|
|
88
110
|
//# sourceMappingURL=json-backend.js.map
|
package/dist/json-backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-backend.js","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"json-backend.js","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"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"}
|
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":"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"}
|
package/package.json
CHANGED
package/src/json-backend.ts
CHANGED
|
@@ -58,12 +58,28 @@ export class JsonFileBackend implements MemoryBackend {
|
|
|
58
58
|
return backend;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Synchronous counterpart to {@link JsonFileBackend.open}. Because this backend
|
|
63
|
+
* is physically synchronous (in-memory map + sync `fs`), a hot sync path (e.g.
|
|
64
|
+
* a recommender) can read the store without an async ripple.
|
|
65
|
+
*/
|
|
66
|
+
static openSync(filePath: string): JsonFileBackend {
|
|
67
|
+
const backend = new JsonFileBackend({ filePath });
|
|
68
|
+
backend.loadSync();
|
|
69
|
+
return backend;
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
put(record: MemoryRecord): Promise<void> {
|
|
62
73
|
this.records.set(record.id, record);
|
|
63
74
|
return Promise.resolve();
|
|
64
75
|
}
|
|
65
76
|
|
|
66
77
|
query(query: MemoryQuery): Promise<MemoryRecord[]> {
|
|
78
|
+
return Promise.resolve(this.querySync(query));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Synchronous {@link JsonFileBackend.query} — same ranking, no Promise. */
|
|
82
|
+
querySync(query: MemoryQuery): MemoryRecord[] {
|
|
67
83
|
const limit = query.limit ?? DEFAULT_LIMIT;
|
|
68
84
|
const terms = query.text !== undefined ? tokenize(query.text) : [];
|
|
69
85
|
let candidates = [...this.records.values()];
|
|
@@ -78,11 +94,16 @@ export class JsonFileBackend implements MemoryBackend {
|
|
|
78
94
|
b.record.score - a.record.score ||
|
|
79
95
|
b.record.timestamp.localeCompare(a.record.timestamp),
|
|
80
96
|
);
|
|
81
|
-
return
|
|
97
|
+
return ranked.slice(0, limit).map((entry) => entry.record);
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
all(): Promise<MemoryRecord[]> {
|
|
85
|
-
return Promise.resolve(
|
|
101
|
+
return Promise.resolve(this.allSync());
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Synchronous {@link JsonFileBackend.all}. */
|
|
105
|
+
allSync(): MemoryRecord[] {
|
|
106
|
+
return [...this.records.values()];
|
|
86
107
|
}
|
|
87
108
|
|
|
88
109
|
count(): Promise<number> {
|
|
@@ -100,10 +121,15 @@ export class JsonFileBackend implements MemoryBackend {
|
|
|
100
121
|
|
|
101
122
|
/** Load records from `filePath`. No-op when no path is set or the file is absent. */
|
|
102
123
|
load(): Promise<void> {
|
|
124
|
+
this.loadSync();
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Synchronous {@link JsonFileBackend.load}. */
|
|
129
|
+
loadSync(): void {
|
|
103
130
|
if (this.filePath !== undefined && existsSync(this.filePath)) {
|
|
104
131
|
const data = JSON.parse(readFileSync(this.filePath, 'utf-8')) as MemoryRecord[];
|
|
105
132
|
for (const record of data) this.records.set(record.id, record);
|
|
106
133
|
}
|
|
107
|
-
return Promise.resolve();
|
|
108
134
|
}
|
|
109
135
|
}
|
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> {
|