sqlite-zod-orm 3.7.0 → 3.7.1

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 CHANGED
@@ -383,6 +383,34 @@ class QueryBuilder {
383
383
  clearInterval(timer);
384
384
  };
385
385
  }
386
+ each(callback, options = {}) {
387
+ const { interval = this.defaultPollInterval } = options;
388
+ const maxRows = this.executor(`SELECT MAX(id) as _max FROM ${this.tableName}`, [], true);
389
+ let lastMaxId = maxRows[0]?._max ?? 0;
390
+ let lastRevision = this.revisionGetter?.() ?? "0";
391
+ let stopped = false;
392
+ const poll = async () => {
393
+ if (stopped)
394
+ return;
395
+ const rev = this.revisionGetter?.() ?? "0";
396
+ if (rev !== lastRevision) {
397
+ lastRevision = rev;
398
+ const newRows = this.executor(`SELECT * FROM ${this.tableName} WHERE id > ? ORDER BY id ASC`, [lastMaxId], true);
399
+ for (const rawRow of newRows) {
400
+ if (stopped)
401
+ return;
402
+ await callback(rawRow);
403
+ lastMaxId = rawRow.id;
404
+ }
405
+ }
406
+ if (!stopped)
407
+ setTimeout(poll, interval);
408
+ };
409
+ setTimeout(poll, interval);
410
+ return () => {
411
+ stopped = true;
412
+ };
413
+ }
386
414
  buildFingerprintSQL() {
387
415
  const params = [];
388
416
  let sql = `SELECT COUNT(*) as _cnt, MAX(id) as _max FROM ${this.tableName}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlite-zod-orm",
3
- "version": "3.7.0",
3
+ "version": "3.7.1",
4
4
  "description": "Type-safe SQLite ORM for Bun — Zod schemas, fluent queries, auto relationships, zero SQL",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -540,6 +540,65 @@ export class QueryBuilder<T extends Record<string, any>> {
540
540
  };
541
541
  }
542
542
 
543
+ /**
544
+ * Stream new rows one at a time via a watermark (last seen id).
545
+ *
546
+ * Unlike `.subscribe()` (which gives you an array snapshot), `.each()`
547
+ * calls your callback once per new row, in insertion order. The SQL
548
+ * `WHERE id > watermark` is rebuilt each poll with the latest value,
549
+ * so it's always O(new_rows) — not O(table_size).
550
+ *
551
+ * ```ts
552
+ * const unsub = db.messages.select().each((msg) => {
553
+ * console.log('New:', msg.text);
554
+ * });
555
+ * ```
556
+ *
557
+ * @param callback Called once per new row. Async callbacks are awaited.
558
+ * @param options `interval` in ms (default: pollInterval).
559
+ * @returns Unsubscribe function.
560
+ */
561
+ each(
562
+ callback: (row: T) => void | Promise<void>,
563
+ options: { interval?: number } = {},
564
+ ): () => void {
565
+ const { interval = this.defaultPollInterval } = options;
566
+
567
+ // Initialize watermark to current max id
568
+ const maxRows = this.executor(
569
+ `SELECT MAX(id) as _max FROM ${this.tableName}`, [], true
570
+ );
571
+ let lastMaxId: number = (maxRows[0] as any)?._max ?? 0;
572
+ let lastRevision = this.revisionGetter?.() ?? '0';
573
+ let stopped = false;
574
+
575
+ const poll = async () => {
576
+ if (stopped) return;
577
+
578
+ const rev = this.revisionGetter?.() ?? '0';
579
+ if (rev !== lastRevision) {
580
+ lastRevision = rev;
581
+
582
+ // Fetch only new rows since watermark — O(new_rows)
583
+ const newRows = this.executor(
584
+ `SELECT * FROM ${this.tableName} WHERE id > ? ORDER BY id ASC`,
585
+ [lastMaxId], true
586
+ );
587
+
588
+ for (const rawRow of newRows) {
589
+ if (stopped) return;
590
+ await callback(rawRow as unknown as T);
591
+ lastMaxId = (rawRow as any).id;
592
+ }
593
+ }
594
+
595
+ if (!stopped) setTimeout(poll, interval);
596
+ };
597
+
598
+ setTimeout(poll, interval);
599
+ return () => { stopped = true; };
600
+ }
601
+
543
602
  /** Build a lightweight fingerprint query (COUNT + MAX(id)) that shares the same WHERE clause. */
544
603
  private buildFingerprintSQL(): { sql: string; params: any[] } {
545
604
  const params: any[] = [];