@columenlabs/lumen-person 0.1.149 → 0.1.151

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/README.md CHANGED
@@ -81,6 +81,7 @@ An app that kept its own Durable Object moves into the person's store a page at
81
81
  - The old store answers `exportRows(sql, table, after)`: rows after a rowid bookmark, at most 500 rows and about 4 MB a page (at least one row, so a big blob still moves), bytes as `{b64}`.
82
82
  - The module's wake writes each page with `importRows(sql, table, page)` inside `ctx.transaction`, keeps the bookmark and asks to wake again. Rows keep their rowids, so a page sent twice changes nothing.
83
83
  - When every table is across, `rowStats` on both sides (rows and highest rowid per table) must match before the app reads from the new store. Stop the old store's alarm and writes while it moves; a table whose stats differ goes again.
84
+ - An old store that held many people's rows in one table moves each person's part: `exportRows(sql, table, after, { where: { sql: 'scope = ?', args: [email] } })` and `rowStats(sql, tables, where)` with the same filter.
84
85
 
85
86
  Point-in-time recovery (`ctx.storage.getBookmarkForTime`) restores the whole store, every module at once. Restore one module from its dump instead, and keep PITR for the whole store.
86
87
 
package/dist/move.d.ts CHANGED
@@ -9,6 +9,15 @@ export type RowStats = Record<string, {
9
9
  n: number;
10
10
  max: number;
11
11
  }>;
12
+ /**
13
+ * Only some rows of the old store's tables: a condition and its bound values, for an old store that
14
+ * held many people's rows in one table (`{ sql: 'scope = ?', args: [email] }`). The condition is
15
+ * code, never a person's text; the values are bound.
16
+ */
17
+ export interface RowFilter {
18
+ sql: string;
19
+ args: unknown[];
20
+ }
12
21
  /**
13
22
  * Rows of `table` after rowid `after`, in rowid order: at most `limit` rows and about `maxBytes`
14
23
  * (at least one row a page, so a big blob still moves). Bytes come as `{b64}`, as in a dump.
@@ -16,6 +25,7 @@ export type RowStats = Record<string, {
16
25
  export declare function exportRows(sql: SqlLike, table: string, after: number, opts?: {
17
26
  limit?: number;
18
27
  maxBytes?: number;
28
+ where?: RowFilter;
19
29
  }): RowsPage;
20
30
  /**
21
31
  * Writes a page into `table`, naming only the columns the table has (the rest keep their
@@ -25,5 +35,6 @@ export declare function exportRows(sql: SqlLike, table: string, after: number, o
25
35
  export declare function importRows(sql: SqlLike, table: string, page: DumpTable & {
26
36
  ids?: number[];
27
37
  }): number;
28
- /** Row counts and highest rowids of `tables` (a missing table counts as empty). */
29
- export declare function rowStats(sql: SqlLike, tables: string[]): RowStats;
38
+ /** Row counts and highest rowids of `tables` (a missing table counts as empty), of the rows
39
+ * `where` picks when given. */
40
+ export declare function rowStats(sql: SqlLike, tables: string[], where?: RowFilter): RowStats;
package/dist/move.js CHANGED
@@ -22,7 +22,7 @@ export function exportRows(sql, table, after, opts = {}) {
22
22
  if (!cols.length)
23
23
  return { cols, rows: [], ids: [], next: null };
24
24
  const found = sql
25
- .exec(`SELECT rowid AS _rowid_, * FROM ${quote(table)} WHERE rowid > ? ORDER BY rowid LIMIT ?`, after, limit)
25
+ .exec(`SELECT rowid AS _rowid_, * FROM ${quote(table)} WHERE rowid > ?${opts.where ? ` AND (${opts.where.sql})` : ''} ORDER BY rowid LIMIT ?`, after, ...(opts.where?.args ?? []), limit)
26
26
  .toArray();
27
27
  const rows = [];
28
28
  const ids = [];
@@ -59,13 +59,14 @@ export function importRows(sql, table, page) {
59
59
  page.rows.forEach((row, k) => sql.exec(insert, ...(ids ? [ids[k]] : []), ...pick.map(([, i]) => fromJson(row[i]))));
60
60
  return page.rows.length;
61
61
  }
62
- /** Row counts and highest rowids of `tables` (a missing table counts as empty). */
63
- export function rowStats(sql, tables) {
62
+ /** Row counts and highest rowids of `tables` (a missing table counts as empty), of the rows
63
+ * `where` picks when given. */
64
+ export function rowStats(sql, tables, where) {
64
65
  const out = {};
65
66
  for (const t of tables) {
66
67
  try {
67
68
  const r = sql
68
- .exec(`SELECT COUNT(*) AS n, MAX(rowid) AS max FROM ${quote(t)}`)
69
+ .exec(`SELECT COUNT(*) AS n, MAX(rowid) AS max FROM ${quote(t)}${where ? ` WHERE ${where.sql}` : ''}`, ...(where?.args ?? []))
69
70
  .toArray()[0];
70
71
  out[t] = { n: Number(r?.n ?? 0), max: Number(r?.max ?? 0) };
71
72
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@columenlabs/lumen-person",
3
- "version": "0.1.149",
3
+ "version": "0.1.151",
4
4
  "description": "Lumen's one store per person: a Durable Object whose SQLite holds every app's tables for that person, with migrations that fail per app, one alarm shared by every app, and backup, restore and delete per app or whole.",
5
5
  "license": "MIT",
6
6
  "type": "module",