sqlite-zod-orm 3.6.1 → 3.6.2
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/index.js +55 -23
- package/package.json +1 -1
- package/src/database.ts +88 -38
package/dist/index.js
CHANGED
|
@@ -4799,23 +4799,33 @@ class _Database {
|
|
|
4799
4799
|
stopped = true;
|
|
4800
4800
|
};
|
|
4801
4801
|
}
|
|
4802
|
-
|
|
4803
|
-
|
|
4802
|
+
_watchers = new Map;
|
|
4803
|
+
_getWatcher(entityName) {
|
|
4804
|
+
if (this._watchers.has(entityName))
|
|
4805
|
+
return this._watchers.get(entityName);
|
|
4804
4806
|
const allRows = this.db.query(`SELECT * FROM "${entityName}" ORDER BY id ASC`).all();
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
+
const snapshot = new Map;
|
|
4808
|
+
const snapshotEntities = new Map;
|
|
4807
4809
|
for (const row of allRows) {
|
|
4808
4810
|
snapshot.set(row.id, JSON.stringify(row));
|
|
4809
4811
|
snapshotEntities.set(row.id, row);
|
|
4810
4812
|
}
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
+
const watcher = {
|
|
4814
|
+
updateListeners: new Set,
|
|
4815
|
+
deleteListeners: new Set,
|
|
4816
|
+
snapshot,
|
|
4817
|
+
snapshotEntities,
|
|
4818
|
+
lastRevision: this._getRevision(entityName),
|
|
4819
|
+
stopped: false
|
|
4820
|
+
};
|
|
4821
|
+
this._watchers.set(entityName, watcher);
|
|
4822
|
+
const interval = this.pollInterval;
|
|
4813
4823
|
const poll = async () => {
|
|
4814
|
-
if (stopped)
|
|
4824
|
+
if (watcher.stopped)
|
|
4815
4825
|
return;
|
|
4816
4826
|
const currentRevision = this._getRevision(entityName);
|
|
4817
|
-
if (currentRevision !== lastRevision) {
|
|
4818
|
-
lastRevision = currentRevision;
|
|
4827
|
+
if (currentRevision !== watcher.lastRevision) {
|
|
4828
|
+
watcher.lastRevision = currentRevision;
|
|
4819
4829
|
const currentRows = this.db.query(`SELECT * FROM "${entityName}" ORDER BY id ASC`).all();
|
|
4820
4830
|
const currentMap = new Map;
|
|
4821
4831
|
const currentEntities = new Map;
|
|
@@ -4823,35 +4833,57 @@ class _Database {
|
|
|
4823
4833
|
currentMap.set(row.id, JSON.stringify(row));
|
|
4824
4834
|
currentEntities.set(row.id, row);
|
|
4825
4835
|
}
|
|
4826
|
-
if (
|
|
4836
|
+
if (watcher.updateListeners.size > 0) {
|
|
4827
4837
|
for (const [id, json] of currentMap) {
|
|
4828
|
-
if (stopped)
|
|
4838
|
+
if (watcher.stopped)
|
|
4829
4839
|
return;
|
|
4830
|
-
if (snapshot.has(id) && snapshot.get(id) !== json) {
|
|
4840
|
+
if (watcher.snapshot.has(id) && watcher.snapshot.get(id) !== json) {
|
|
4831
4841
|
const entity = this._attachMethods(entityName, transformFromStorage(currentEntities.get(id), this.schemas[entityName]));
|
|
4832
|
-
const oldEntity = this._attachMethods(entityName, transformFromStorage(snapshotEntities.get(id), this.schemas[entityName]));
|
|
4833
|
-
|
|
4842
|
+
const oldEntity = this._attachMethods(entityName, transformFromStorage(watcher.snapshotEntities.get(id), this.schemas[entityName]));
|
|
4843
|
+
for (const cb of watcher.updateListeners) {
|
|
4844
|
+
await cb(entity, oldEntity);
|
|
4845
|
+
}
|
|
4834
4846
|
}
|
|
4835
4847
|
}
|
|
4836
|
-
}
|
|
4837
|
-
|
|
4838
|
-
|
|
4848
|
+
}
|
|
4849
|
+
if (watcher.deleteListeners.size > 0) {
|
|
4850
|
+
for (const [id] of watcher.snapshot) {
|
|
4851
|
+
if (watcher.stopped)
|
|
4839
4852
|
return;
|
|
4840
4853
|
if (!currentMap.has(id)) {
|
|
4841
|
-
const oldEntity = this._attachMethods(entityName, transformFromStorage(snapshotEntities.get(id), this.schemas[entityName]));
|
|
4842
|
-
|
|
4854
|
+
const oldEntity = this._attachMethods(entityName, transformFromStorage(watcher.snapshotEntities.get(id), this.schemas[entityName]));
|
|
4855
|
+
for (const cb of watcher.deleteListeners) {
|
|
4856
|
+
await cb(oldEntity);
|
|
4857
|
+
}
|
|
4843
4858
|
}
|
|
4844
4859
|
}
|
|
4845
4860
|
}
|
|
4846
|
-
snapshot = currentMap;
|
|
4847
|
-
snapshotEntities = currentEntities;
|
|
4861
|
+
watcher.snapshot = currentMap;
|
|
4862
|
+
watcher.snapshotEntities = currentEntities;
|
|
4848
4863
|
}
|
|
4849
|
-
if (!stopped)
|
|
4864
|
+
if (!watcher.stopped)
|
|
4850
4865
|
setTimeout(poll, interval);
|
|
4851
4866
|
};
|
|
4852
4867
|
setTimeout(poll, interval);
|
|
4868
|
+
return watcher;
|
|
4869
|
+
}
|
|
4870
|
+
_createChangeStream(entityName, eventType, callback, _intervalOverride) {
|
|
4871
|
+
const watcher = this._getWatcher(entityName);
|
|
4872
|
+
if (eventType === "update") {
|
|
4873
|
+
watcher.updateListeners.add(callback);
|
|
4874
|
+
} else {
|
|
4875
|
+
watcher.deleteListeners.add(callback);
|
|
4876
|
+
}
|
|
4853
4877
|
return () => {
|
|
4854
|
-
|
|
4878
|
+
if (eventType === "update") {
|
|
4879
|
+
watcher.updateListeners.delete(callback);
|
|
4880
|
+
} else {
|
|
4881
|
+
watcher.deleteListeners.delete(callback);
|
|
4882
|
+
}
|
|
4883
|
+
if (watcher.updateListeners.size === 0 && watcher.deleteListeners.size === 0) {
|
|
4884
|
+
watcher.stopped = true;
|
|
4885
|
+
this._watchers.delete(entityName);
|
|
4886
|
+
}
|
|
4855
4887
|
};
|
|
4856
4888
|
}
|
|
4857
4889
|
insert(entityName, data) {
|
package/package.json
CHANGED
package/src/database.ts
CHANGED
|
@@ -204,41 +204,54 @@ class _Database<Schemas extends SchemaMap> {
|
|
|
204
204
|
return () => { stopped = true; };
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// ===========================================================================
|
|
208
|
+
// Table Watcher — shared snapshot-diff engine for update/delete events
|
|
209
|
+
// ===========================================================================
|
|
210
|
+
|
|
211
|
+
/** One watcher per table — shared by all update/delete listeners. */
|
|
212
|
+
private _watchers = new Map<string, {
|
|
213
|
+
updateListeners: Set<(row: any, oldRow: any) => void | Promise<void>>;
|
|
214
|
+
deleteListeners: Set<(row: any) => void | Promise<void>>;
|
|
215
|
+
snapshot: Map<number, string>;
|
|
216
|
+
snapshotEntities: Map<number, any>;
|
|
217
|
+
lastRevision: string;
|
|
218
|
+
stopped: boolean;
|
|
219
|
+
}>();
|
|
220
|
+
|
|
207
221
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
* Maintains a full snapshot and diffs on each poll.
|
|
211
|
-
* Only fires for the subscribed event type.
|
|
212
|
-
*
|
|
213
|
-
* - 'update': callback(row, oldRow)
|
|
214
|
-
* - 'delete': callback(row)
|
|
222
|
+
* Get or create a shared table watcher. One SELECT * per change event,
|
|
223
|
+
* no matter how many update/delete listeners are registered.
|
|
215
224
|
*/
|
|
216
|
-
|
|
217
|
-
entityName
|
|
218
|
-
eventType: 'update' | 'delete',
|
|
219
|
-
callback: (...args: any[]) => void | Promise<void>,
|
|
220
|
-
intervalOverride?: number,
|
|
221
|
-
): () => void {
|
|
222
|
-
const interval = intervalOverride ?? this.pollInterval;
|
|
225
|
+
private _getWatcher(entityName: string) {
|
|
226
|
+
if (this._watchers.has(entityName)) return this._watchers.get(entityName)!;
|
|
223
227
|
|
|
224
|
-
// Build initial snapshot
|
|
228
|
+
// Build initial snapshot
|
|
225
229
|
const allRows = this.db.query(`SELECT * FROM "${entityName}" ORDER BY id ASC`).all() as any[];
|
|
226
|
-
|
|
227
|
-
|
|
230
|
+
const snapshot = new Map<number, string>();
|
|
231
|
+
const snapshotEntities = new Map<number, any>();
|
|
228
232
|
for (const row of allRows) {
|
|
229
233
|
snapshot.set(row.id, JSON.stringify(row));
|
|
230
234
|
snapshotEntities.set(row.id, row);
|
|
231
235
|
}
|
|
232
236
|
|
|
233
|
-
|
|
234
|
-
|
|
237
|
+
const watcher = {
|
|
238
|
+
updateListeners: new Set<(row: any, oldRow: any) => void | Promise<void>>(),
|
|
239
|
+
deleteListeners: new Set<(row: any) => void | Promise<void>>(),
|
|
240
|
+
snapshot,
|
|
241
|
+
snapshotEntities,
|
|
242
|
+
lastRevision: this._getRevision(entityName),
|
|
243
|
+
stopped: false,
|
|
244
|
+
};
|
|
245
|
+
this._watchers.set(entityName, watcher);
|
|
235
246
|
|
|
247
|
+
// Single poll loop for all listeners on this table
|
|
248
|
+
const interval = this.pollInterval;
|
|
236
249
|
const poll = async () => {
|
|
237
|
-
if (stopped) return;
|
|
250
|
+
if (watcher.stopped) return;
|
|
238
251
|
|
|
239
252
|
const currentRevision = this._getRevision(entityName);
|
|
240
|
-
if (currentRevision !== lastRevision) {
|
|
241
|
-
lastRevision = currentRevision;
|
|
253
|
+
if (currentRevision !== watcher.lastRevision) {
|
|
254
|
+
watcher.lastRevision = currentRevision;
|
|
242
255
|
|
|
243
256
|
const currentRows = this.db.query(`SELECT * FROM "${entityName}" ORDER BY id ASC`).all() as any[];
|
|
244
257
|
const currentMap = new Map<number, string>();
|
|
@@ -248,46 +261,83 @@ class _Database<Schemas extends SchemaMap> {
|
|
|
248
261
|
currentEntities.set(row.id, row);
|
|
249
262
|
}
|
|
250
263
|
|
|
251
|
-
|
|
252
|
-
|
|
264
|
+
// Dispatch updates
|
|
265
|
+
if (watcher.updateListeners.size > 0) {
|
|
253
266
|
for (const [id, json] of currentMap) {
|
|
254
|
-
if (stopped) return;
|
|
255
|
-
if (snapshot.has(id) && snapshot.get(id) !== json) {
|
|
267
|
+
if (watcher.stopped) return;
|
|
268
|
+
if (watcher.snapshot.has(id) && watcher.snapshot.get(id) !== json) {
|
|
256
269
|
const entity = this._attachMethods(
|
|
257
270
|
entityName,
|
|
258
271
|
transformFromStorage(currentEntities.get(id), this.schemas[entityName]!)
|
|
259
272
|
);
|
|
260
273
|
const oldEntity = this._attachMethods(
|
|
261
274
|
entityName,
|
|
262
|
-
transformFromStorage(snapshotEntities.get(id), this.schemas[entityName]!)
|
|
275
|
+
transformFromStorage(watcher.snapshotEntities.get(id), this.schemas[entityName]!)
|
|
263
276
|
);
|
|
264
|
-
|
|
277
|
+
for (const cb of watcher.updateListeners) {
|
|
278
|
+
await cb(entity, oldEntity);
|
|
279
|
+
}
|
|
265
280
|
}
|
|
266
281
|
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Dispatch deletes
|
|
285
|
+
if (watcher.deleteListeners.size > 0) {
|
|
286
|
+
for (const [id] of watcher.snapshot) {
|
|
287
|
+
if (watcher.stopped) return;
|
|
271
288
|
if (!currentMap.has(id)) {
|
|
272
289
|
const oldEntity = this._attachMethods(
|
|
273
290
|
entityName,
|
|
274
|
-
transformFromStorage(snapshotEntities.get(id), this.schemas[entityName]!)
|
|
291
|
+
transformFromStorage(watcher.snapshotEntities.get(id), this.schemas[entityName]!)
|
|
275
292
|
);
|
|
276
|
-
|
|
293
|
+
for (const cb of watcher.deleteListeners) {
|
|
294
|
+
await cb(oldEntity);
|
|
295
|
+
}
|
|
277
296
|
}
|
|
278
297
|
}
|
|
279
298
|
}
|
|
280
299
|
|
|
281
|
-
snapshot = currentMap;
|
|
282
|
-
snapshotEntities = currentEntities;
|
|
300
|
+
watcher.snapshot = currentMap;
|
|
301
|
+
watcher.snapshotEntities = currentEntities;
|
|
283
302
|
}
|
|
284
303
|
|
|
285
|
-
if (!stopped) setTimeout(poll, interval);
|
|
304
|
+
if (!watcher.stopped) setTimeout(poll, interval);
|
|
286
305
|
};
|
|
287
306
|
|
|
288
307
|
setTimeout(poll, interval);
|
|
308
|
+
return watcher;
|
|
309
|
+
}
|
|
289
310
|
|
|
290
|
-
|
|
311
|
+
/**
|
|
312
|
+
* Register an update or delete listener on the shared table watcher.
|
|
313
|
+
* Returns an unsubscribe function that auto-stops the watcher when empty.
|
|
314
|
+
*/
|
|
315
|
+
public _createChangeStream(
|
|
316
|
+
entityName: string,
|
|
317
|
+
eventType: 'update' | 'delete',
|
|
318
|
+
callback: (...args: any[]) => void | Promise<void>,
|
|
319
|
+
_intervalOverride?: number, // reserved, uses global pollInterval
|
|
320
|
+
): () => void {
|
|
321
|
+
const watcher = this._getWatcher(entityName);
|
|
322
|
+
|
|
323
|
+
if (eventType === 'update') {
|
|
324
|
+
watcher.updateListeners.add(callback as any);
|
|
325
|
+
} else {
|
|
326
|
+
watcher.deleteListeners.add(callback as any);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return () => {
|
|
330
|
+
if (eventType === 'update') {
|
|
331
|
+
watcher.updateListeners.delete(callback as any);
|
|
332
|
+
} else {
|
|
333
|
+
watcher.deleteListeners.delete(callback as any);
|
|
334
|
+
}
|
|
335
|
+
// Auto-stop watcher when all listeners removed
|
|
336
|
+
if (watcher.updateListeners.size === 0 && watcher.deleteListeners.size === 0) {
|
|
337
|
+
watcher.stopped = true;
|
|
338
|
+
this._watchers.delete(entityName);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
291
341
|
}
|
|
292
342
|
|
|
293
343
|
// ===========================================================================
|