@bitcobblers/wod-wiki-storage 0.44.2160 → 0.45.2166

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.
Files changed (34) hide show
  1. package/dist/{chunk-MOGQICXM.mjs → chunk-7ICLFFYU.mjs} +2 -2
  2. package/dist/chunk-7ICLFFYU.mjs.map +1 -0
  3. package/dist/{chunk-IMNG2HY5.mjs → chunk-J6KVDPTL.mjs} +3 -3
  4. package/dist/chunk-J6KVDPTL.mjs.map +1 -0
  5. package/dist/{chunk-JFVXIJJI.mjs → chunk-PJ7GRYOZ.mjs} +8 -8
  6. package/dist/chunk-PJ7GRYOZ.mjs.map +1 -0
  7. package/dist/{chunk-IFLOX2TK.mjs → chunk-UN56ET7P.mjs} +3 -3
  8. package/dist/{chunk-IFLOX2TK.mjs.map → chunk-UN56ET7P.mjs.map} +1 -1
  9. package/dist/idb/index.cjs +1 -1
  10. package/dist/idb/index.cjs.map +1 -1
  11. package/dist/idb/index.d.cts +3 -3
  12. package/dist/idb/index.d.ts +3 -3
  13. package/dist/idb/index.mjs +3 -3
  14. package/dist/index.cjs +6 -6
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +3 -3
  17. package/dist/index.d.ts +3 -3
  18. package/dist/index.mjs +5 -5
  19. package/dist/{policy-DRYF6Y8i.d.cts → policy-BBwCBMtp.d.cts} +3 -2
  20. package/dist/{policy-CPscN81J.d.ts → policy-C86TCPSM.d.ts} +3 -2
  21. package/dist/sql/index.cjs +60 -44
  22. package/dist/sql/index.cjs.map +1 -1
  23. package/dist/sql/index.d.cts +3 -3
  24. package/dist/sql/index.d.ts +3 -3
  25. package/dist/sql/index.mjs +64 -48
  26. package/dist/sql/index.mjs.map +1 -1
  27. package/dist/{sync-DG4Z-szj.d.cts → sync-BDu_Q__z.d.cts} +1 -1
  28. package/dist/{sync-Bjj_c1ea.d.ts → sync-BQ0g8ctt.d.ts} +1 -1
  29. package/dist/{wire-DGYxXt3I.d.ts → wire-BO8FM1LJ.d.cts} +17 -8
  30. package/dist/{wire-DGYxXt3I.d.cts → wire-BO8FM1LJ.d.ts} +17 -8
  31. package/package.json +6 -6
  32. package/dist/chunk-IMNG2HY5.mjs.map +0 -1
  33. package/dist/chunk-JFVXIJJI.mjs.map +0 -1
  34. package/dist/chunk-MOGQICXM.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  import { S as SqlConnection, D as Database } from '../connection-DxuCLpRc.cjs';
2
2
  export { L as LibsqlClient, a as SqlRow, b as SqlStatement, c as SqlValue, l as libsqlDatabase } from '../connection-DxuCLpRc.cjs';
3
- import { e as StoreDef, R as RangeDTO, K as KeyDTO, f as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, D as DomainQuery, d as IStorageTransaction } from '../wire-DGYxXt3I.cjs';
4
- import { b as StoredSyncOp, S as SyncMutation } from '../sync-DG4Z-szj.cjs';
5
- export { A as ApplySyncBatchOptions, R as RawSyncOp, c as SYNC_OPS_TABLE, d as SYNC_STATE_TABLE, a as SyncEntry, e as SyncTargetKind, f as applySyncBatch, g as fetchSyncOps, i as initSyncTarget, p as probeSyncTarget, r as readLegacyRows, h as readRawSyncOps } from '../sync-DG4Z-szj.cjs';
3
+ import { e as StoreDef, R as RangeDTO, K as KeyDTO, f as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, D as DomainQuery, d as IStorageTransaction } from '../wire-BO8FM1LJ.cjs';
4
+ import { b as StoredSyncOp, S as SyncMutation } from '../sync-BDu_Q__z.cjs';
5
+ export { A as ApplySyncBatchOptions, R as RawSyncOp, c as SYNC_OPS_TABLE, d as SYNC_STATE_TABLE, a as SyncEntry, e as SyncTargetKind, f as applySyncBatch, g as fetchSyncOps, i as initSyncTarget, p as probeSyncTarget, r as readLegacyRows, h as readRawSyncOps } from '../sync-BDu_Q__z.cjs';
6
6
  import '@libsql/client';
7
7
  import '@bitcobblers/wod-wiki-core';
8
8
  import '@bitcobblers/wod-wiki-lang';
@@ -1,8 +1,8 @@
1
1
  import { S as SqlConnection, D as Database } from '../connection-DxuCLpRc.js';
2
2
  export { L as LibsqlClient, a as SqlRow, b as SqlStatement, c as SqlValue, l as libsqlDatabase } from '../connection-DxuCLpRc.js';
3
- import { e as StoreDef, R as RangeDTO, K as KeyDTO, f as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, D as DomainQuery, d as IStorageTransaction } from '../wire-DGYxXt3I.js';
4
- import { b as StoredSyncOp, S as SyncMutation } from '../sync-Bjj_c1ea.js';
5
- export { A as ApplySyncBatchOptions, R as RawSyncOp, c as SYNC_OPS_TABLE, d as SYNC_STATE_TABLE, a as SyncEntry, e as SyncTargetKind, f as applySyncBatch, g as fetchSyncOps, i as initSyncTarget, p as probeSyncTarget, r as readLegacyRows, h as readRawSyncOps } from '../sync-Bjj_c1ea.js';
3
+ import { e as StoreDef, R as RangeDTO, K as KeyDTO, f as DomainQueryResult, T as TxOp, I as IStorage, S as StoreName, a as IReadOnlyStore, b as StoreType, c as IReadWriteStore, D as DomainQuery, d as IStorageTransaction } from '../wire-BO8FM1LJ.js';
4
+ import { b as StoredSyncOp, S as SyncMutation } from '../sync-BQ0g8ctt.js';
5
+ export { A as ApplySyncBatchOptions, R as RawSyncOp, c as SYNC_OPS_TABLE, d as SYNC_STATE_TABLE, a as SyncEntry, e as SyncTargetKind, f as applySyncBatch, g as fetchSyncOps, i as initSyncTarget, p as probeSyncTarget, r as readLegacyRows, h as readRawSyncOps } from '../sync-BQ0g8ctt.js';
6
6
  import '@libsql/client';
7
7
  import '@bitcobblers/wod-wiki-core';
8
8
  import '@bitcobblers/wod-wiki-lang';
@@ -1,23 +1,28 @@
1
- import { DOMAIN_PROJECTION_VERSION, bufferToOps, bufferedGet, overlayRows, isDirty, bufferSlot } from '../chunk-JFVXIJJI.mjs';
2
- import { getRows, storeDefinition, deleteRows, clearRows, SCHEMA_TABLE, decodeRowJson, initializeStore, putRow, wipeRows, getRow, listRowsFromIndexMany, listRows, countRows, putRows, deleteIn, batchInsert, SYNC_STATE_TABLE, encodeRowJson } from '../chunk-IFLOX2TK.mjs';
3
- export { SCHEMA_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, initSyncTarget, initializeStore, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, storeDefinition, wipeRows } from '../chunk-IFLOX2TK.mjs';
4
- import { rowsEqual, validateStoredPins, DB_VERSION, STORE_DEFS, stampUserOwned, rangeFromIDB, keyFromValue, isRange } from '../chunk-IMNG2HY5.mjs';
1
+ import { DOMAIN_PROJECTION_VERSION, bufferToOps, bufferedGet, overlayRows, isDirty, bufferSlot } from '../chunk-PJ7GRYOZ.mjs';
2
+ import { getRows, storeDefinition, deleteRows, clearRows, SCHEMA_TABLE, decodeRowJson, encodeRowJson, initializeStore, putRow, wipeRows, getRow, listRowsFromIndexMany, listRows, countRows, putRows, deleteIn, batchInsert, SYNC_STATE_TABLE } from '../chunk-UN56ET7P.mjs';
3
+ export { SCHEMA_TABLE, SYNC_OPS_TABLE, SYNC_STATE_TABLE, applySyncBatch, clearRows, countRows, decodeRowJson, deleteRows, encodeRowJson, fetchSyncOps, getRow, getRows, initSyncTarget, initializeStore, listRows, listRowsFromIndexMany, probeSyncTarget, putRow, putRows, readLegacyRows, readRawSyncOps, storeDefinition, wipeRows } from '../chunk-UN56ET7P.mjs';
4
+ import { rowsEqual, validateStoredPins, DB_VERSION, STORE_DEFS, stampUserOwned, rangeFromIDB, keyFromValue, isRange } from '../chunk-J6KVDPTL.mjs';
5
5
  import { libsqlDatabase } from '../chunk-6ZTAWTAP.mjs';
6
6
  export { libsqlDatabase } from '../chunk-6ZTAWTAP.mjs';
7
7
  import { StorageError } from '../chunk-XRQKLSOT.mjs';
8
8
  export { StorageError } from '../chunk-XRQKLSOT.mjs';
9
- import { catalogOfItem, sourceMatches } from '@bitcobblers/wod-wiki-wql';
9
+ import { WQL_SOURCE_VALUES, migrateLegacyRow, hasLegacyIdentity, sourceMatches, sourceShape } from '@bitcobblers/wod-wiki-wql';
10
10
  import { createClient } from '@libsql/client/web';
11
11
 
12
12
  var TABLES = ["domain_note", "query_block"];
13
13
  var PROJECTION_GUARD_KEY = "domain_projection";
14
- function sourceItem(row) {
14
+ function sourceNote(row) {
15
15
  const item = {};
16
- for (const key of ["id", "noteId", "sourceId", "type", "seedOrigin", "seedChunkId", "sourcePath", "catalog", "notebookId"]) {
16
+ for (const key of ["id", "noteId", "sourceId", "type", "seedOrigin", "seedChunkId", "feedOrigin", "feedSourceId", "sourcePath", "notebookId"]) {
17
17
  const value = row[key];
18
18
  if (typeof value === "string") item[key] = value;
19
19
  else if (value != null) throw new StorageError(400, `${key} must be a string`);
20
20
  }
21
+ const tags = row["tags"];
22
+ if (tags !== void 0 && tags !== null) {
23
+ if (!Array.isArray(tags) || !tags.every((t) => typeof t === "string")) throw new StorageError(400, "tags must be a string array");
24
+ item.tags = tags;
25
+ }
21
26
  return item;
22
27
  }
23
28
  var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
@@ -28,11 +33,11 @@ function ensureDdl(db) {
28
33
  const n = db.dialect === "postgres" ? " DOUBLE PRECISION" : "";
29
34
  const t = db.dialect === "postgres" ? ' TEXT COLLATE "C"' : " TEXT";
30
35
  const ddl = [
31
- `CREATE TABLE IF NOT EXISTS "domain_note" ("note_id"${t} PRIMARY KEY NOT NULL, "note_type"${t}, "catalog"${t}, "source_id"${t}, "source_path"${t}, "title"${t} NOT NULL, "title_search"${t} NOT NULL, "created_at"${n} NOT NULL, "date"${n}, "text_search"${t} NOT NULL, "journal"${n} NOT NULL, "payload"${t} NOT NULL)`,
36
+ `CREATE TABLE IF NOT EXISTS "domain_note" ("note_id"${t} PRIMARY KEY NOT NULL, "note_type"${t}, "source_id"${t}, "source_path"${t}, "title"${t} NOT NULL, "title_search"${t} NOT NULL, "created_at"${n} NOT NULL, "date"${n}, "text_search"${t} NOT NULL, "journal"${n} NOT NULL, "payload"${t} NOT NULL)`,
32
37
  `CREATE INDEX IF NOT EXISTS "idx_domain_note_date" ON "domain_note" ("date", "note_id")`,
33
38
  `CREATE INDEX IF NOT EXISTS "idx_domain_note_created" ON "domain_note" ("created_at", "note_id")`,
34
39
  `CREATE INDEX IF NOT EXISTS "idx_domain_note_source_path" ON "domain_note" ("source_path")`,
35
- `CREATE TABLE IF NOT EXISTS "query_block" ("occurrence_id"${t} PRIMARY KEY NOT NULL, "source_note_id"${t}, "parent_note_id"${t}, "content_id"${t}, "section_key"${t}, "ordinal"${n}, "data_type"${t}, "source_id"${t}, "source_path"${t}, "catalog"${t}, "effective_date"${n} NOT NULL, "created_at"${n} NOT NULL, "note_title"${t}, "normalized_text"${t} NOT NULL, "journal"${n} NOT NULL, "payload"${t} NOT NULL)`,
40
+ `CREATE TABLE IF NOT EXISTS "query_block" ("occurrence_id"${t} PRIMARY KEY NOT NULL, "source_note_id"${t}, "parent_note_id"${t}, "content_id"${t}, "section_key"${t}, "ordinal"${n} NOT NULL, "data_type"${t}, "source_id"${t}, "source_path"${t}, "effective_date"${n} NOT NULL, "created_at"${n} NOT NULL, "note_title"${t}, "normalized_text"${t} NOT NULL, "journal"${n} NOT NULL, "payload"${t} NOT NULL)`,
36
41
  `CREATE INDEX IF NOT EXISTS "idx_query_block_type" ON "query_block" ("data_type", "effective_date", "occurrence_id")`,
37
42
  `CREATE INDEX IF NOT EXISTS "idx_query_block_parent" ON "query_block" ("parent_note_id", "ordinal")`,
38
43
  `CREATE INDEX IF NOT EXISTS "idx_query_block_content" ON "query_block" ("content_id")`,
@@ -43,17 +48,16 @@ function ensureDdl(db) {
43
48
  for (const sql of ddl) await tx.exec(sql);
44
49
  });
45
50
  }
46
- var DOMAIN_NOTE_COLS = ["note_id", "note_type", "catalog", "source_id", "source_path", "title", "title_search", "created_at", "date", "text_search", "journal", "payload"];
47
- var QUERY_BLOCK_COLS = ["occurrence_id", "source_note_id", "parent_note_id", "content_id", "section_key", "ordinal", "data_type", "source_id", "source_path", "catalog", "effective_date", "created_at", "note_title", "normalized_text", "journal", "payload"];
51
+ var DOMAIN_NOTE_COLS = ["note_id", "note_type", "source_id", "source_path", "title", "title_search", "created_at", "date", "text_search", "journal", "payload"];
52
+ var QUERY_BLOCK_COLS = ["occurrence_id", "source_note_id", "parent_note_id", "content_id", "section_key", "ordinal", "data_type", "source_id", "source_path", "effective_date", "created_at", "note_title", "normalized_text", "journal", "payload"];
48
53
  var conflictUpdate = (table, cols, keys) => `ON CONFLICT (${keys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ` + cols.filter((c) => !keys.includes(c)).map((c) => `"${c}" = excluded."${c}"`).join(",") + ` WHERE ` + cols.filter((col) => !keys.includes(col)).map((col) => `"${table}"."${col}" IS DISTINCT FROM excluded."${col}"`).join(" OR ");
49
54
  function domainNoteRow(note) {
50
55
  const id = text(note.id);
51
56
  if (!id) return void 0;
52
- const source = sourceItem(note);
57
+ const source = sourceNote(note);
53
58
  return [
54
59
  id,
55
60
  T(note.type),
56
- T(catalogOfItem(source)),
57
61
  T(note.sourceId),
58
62
  T(note.sourcePath),
59
63
  T(note.title) ?? "",
@@ -72,7 +76,7 @@ async function upsertDomainNotes(conn, notes) {
72
76
  function queryBlockRow(block, parent) {
73
77
  const id = text(block.id);
74
78
  if (!id) return void 0;
75
- const source = sourceItem(block);
79
+ const source = sourceNote(block);
76
80
  const createdAt = N(block.createdAt);
77
81
  const effective = parent ? parent.date ?? parent.created_at : createdAt;
78
82
  return [
@@ -85,7 +89,6 @@ function queryBlockRow(block, parent) {
85
89
  T(block.dataType),
86
90
  T(block.sourceId),
87
91
  T(block.sourcePath),
88
- T(catalogOfItem(source)),
89
92
  effective,
90
93
  createdAt,
91
94
  parent?.note.title ?? T(block.noteTitle),
@@ -265,11 +268,21 @@ async function rebuildProjections(conn) {
265
268
  `CREATE TABLE IF NOT EXISTS "${SCHEMA_TABLE}" ("key" TEXT PRIMARY KEY, "value" TEXT NOT NULL)`
266
269
  );
267
270
  for (const t of TABLES) await conn.exec(`DELETE FROM "${t}"`);
268
- const notes = await conn.query(`SELECT "data" FROM "notes"`);
269
- const noteObjs = notes.map((row) => decodeRowJson(String(row.data)));
271
+ const notes = await conn.query(`SELECT "k0", "data" FROM "notes"`);
272
+ const noteObjs = notes.map((row) => migrateLegacyRow(decodeRowJson(String(row.data))));
273
+ for (let i = 0; i < notes.length; i++) {
274
+ if (hasLegacyIdentity(decodeRowJson(String(notes[i].data)))) {
275
+ await conn.exec(`UPDATE "notes" SET "data" = ? WHERE "k0" = ?`, [encodeRowJson(noteObjs[i]), String(notes[i].k0)]);
276
+ }
277
+ }
270
278
  await upsertDomainNotes(conn, noteObjs);
271
- const blocks = await conn.query(`SELECT "data" FROM "block_index"`);
272
- const blockObjs = blocks.map((row) => decodeRowJson(String(row.data)));
279
+ const blocks = await conn.query(`SELECT "k0", "data" FROM "block_index"`);
280
+ const blockObjs = blocks.map((row) => migrateLegacyRow(decodeRowJson(String(row.data))));
281
+ for (let i = 0; i < blocks.length; i++) {
282
+ if (hasLegacyIdentity(decodeRowJson(String(blocks[i].data)))) {
283
+ await conn.exec(`UPDATE "block_index" SET "data" = ? WHERE "k0" = ?`, [encodeRowJson(blockObjs[i]), String(blocks[i].k0)]);
284
+ }
285
+ }
273
286
  const index = indexNoteIdentities(noteObjs);
274
287
  await upsertQueryBlocks(conn, blockObjs.map((b) => [b, resolveParentFrom(index, b)]));
275
288
  await conn.exec(
@@ -371,7 +384,7 @@ var MAX_CLAUSES = 32;
371
384
  var MAX_VALUES = 64;
372
385
  var MAX_VALUE_LEN = 256;
373
386
  var MAX_ORDER = 4;
374
- var listFields = ["id", "noteId", "type", "catalog", "source", "tags", "effort"];
387
+ var listFields = ["id", "noteId", "type", "source", "tags", "effort"];
375
388
  var onlyKeys = (obj, allowed) => Object.keys(obj).every((k) => allowed.includes(k));
376
389
  function bad(msg) {
377
390
  return new StorageError(400, msg);
@@ -403,6 +416,15 @@ function parsePredicate(v, plan) {
403
416
  }
404
417
  return { field, values: strArray(obj.values, `predicate ${field}.values`), ...negate ? { negate } : {} };
405
418
  }
419
+ if (field === "typedTag") {
420
+ if (!onlyKeys(obj, ["field", "tagType", "values", "negate"])) {
421
+ throw bad("predicate typedTag accepts only field/tagType/values/negate");
422
+ }
423
+ if (typeof obj.tagType !== "string" || obj.tagType.length < 1 || obj.tagType.length > MAX_VALUE_LEN) {
424
+ throw bad(`predicate typedTag.tagType must be 1..=${MAX_VALUE_LEN} chars`);
425
+ }
426
+ return { field: "typedTag", tagType: obj.tagType, values: strArray(obj.values, "predicate typedTag.values"), ...negate ? { negate } : {} };
427
+ }
406
428
  if (field === "text") {
407
429
  if (!onlyKeys(obj, ["field", "value"]) || negate) throw bad("predicate text accepts only {field, value}");
408
430
  if (typeof obj.value !== "string" || obj.value.length < 1 || obj.value.length > MAX_VALUE_LEN) {
@@ -435,9 +457,9 @@ function parsePredicate(v, plan) {
435
457
  }
436
458
  if (field === "defaultNotes") {
437
459
  if (plan === "blocks") throw bad("predicate defaultNotes does not apply to the blocks plan");
438
- if (!onlyKeys(obj, ["field", "feeds"])) throw bad("predicate defaultNotes accepts only {field, feeds}");
439
- if (typeof obj.feeds !== "boolean") throw bad("predicate defaultNotes.feeds must be boolean");
440
- return { field: "defaultNotes", feeds: obj.feeds };
460
+ if (!onlyKeys(obj, ["field", "nonPages"])) throw bad("predicate defaultNotes accepts only {field, nonPages}");
461
+ if (typeof obj.nonPages !== "boolean") throw bad("predicate defaultNotes.nonPages must be boolean");
462
+ return { field: "defaultNotes", nonPages: obj.nonPages };
441
463
  }
442
464
  throw bad(`unknown predicate field: ${field}`);
443
465
  }
@@ -462,8 +484,8 @@ function parseQuery(body) {
462
484
  if (body === null || typeof body !== "object" || Array.isArray(body)) throw bad("body must be a DomainQuery object");
463
485
  const obj = body;
464
486
  const plan = obj.plan;
465
- if (plan !== "notes" && plan !== "blocks" && plan !== "entries") {
466
- throw bad("body.plan must be notes | blocks | entries");
487
+ if (plan !== "notes" && plan !== "blocks" && plan !== "detail") {
488
+ throw bad("body.plan must be notes | blocks | detail");
467
489
  }
468
490
  for (const k of Object.keys(obj)) {
469
491
  if (!["plan", "selection", "filters", "order", "offset", "limit"].includes(k)) {
@@ -520,25 +542,17 @@ var Sql = class {
520
542
  return `${col} IN (${values.map((v) => this.bind(v)).join(", ")})`;
521
543
  }
522
544
  };
523
- var SOURCE_ALL_KINDS = ["journal", "feeds", "guides", "playground", "dashboards", "efforts"];
545
+ var SOURCE_ALL_KINDS = ["journal", ...WQL_SOURCE_VALUES.filter((k) => k !== "journal")];
524
546
  function sourceKindSql(ctx, kind, sid, typeExpr, journalCol) {
525
- switch (kind) {
526
- case "journal":
527
- return `(${journalCol} = 1)`;
528
- case "feed":
529
- case "feeds":
530
- return `(substr(${sid}, 1, 11) = 'collection:' OR substr(${sid}, 1, 16) = 'page:collection:')`;
531
- case "page":
532
- case "pages":
533
- return `(${sid} = 'page' OR substr(${sid}, 1, 5) = 'page:' OR substr(${sid}, 1, 7) = 'guides:')`;
534
- case "guide":
535
- case "guides":
536
- return `(substr(${sid}, 1, 7) = 'guides:')`;
537
- case "playground":
538
- return typeExpr ? `(${sid} = 'playground' OR (${typeExpr} IS NOT NULL AND ${typeExpr} = 'playground'))` : `(${sid} = 'playground')`;
539
- default:
540
- return `(${sid} = ${ctx.bind(kind)})`;
541
- }
547
+ if (kind === "journal") return `(${journalCol} = 1)`;
548
+ const shape = sourceShape(kind) ?? { exact: [kind] };
549
+ const parts = [];
550
+ for (const v of shape.exact ?? []) parts.push(`${sid} = ${ctx.bind(v)}`);
551
+ for (const p of shape.prefixes ?? []) parts.push(`substr(${sid}, 1, ${p.length}) = ${ctx.bind(p)}`);
552
+ if (shape.legacyType) {
553
+ parts.push(typeExpr ? `${typeExpr} = ${ctx.bind(shape.legacyType)}` : "FALSE");
554
+ }
555
+ return `(${parts.join(" OR ")})`;
542
556
  }
543
557
  function sourcePredicateSql(ctx, values, negate, sid, typeExpr, journalCol) {
544
558
  const matched = values.map((v) => sourceKindSql(ctx, v, sid, typeExpr, journalCol)).join(" OR ");
@@ -551,7 +565,6 @@ function predicateSql(ctx, p, plan) {
551
565
  const sid = blocks ? 'q."source_id"' : 'n."source_id"';
552
566
  const typeExpr = blocks ? null : 'n."note_type"';
553
567
  const typeCol = blocks ? 'q."data_type"' : 'n."note_type"';
554
- const catalogCol = blocks ? 'q."catalog"' : 'n."catalog"';
555
568
  const journalCol = blocks ? 'q."journal"' : 'n."journal"';
556
569
  const noteId = blocks ? 'q."source_note_id"' : 'n."note_id"';
557
570
  switch (p.field) {
@@ -561,8 +574,6 @@ function predicateSql(ctx, p, plan) {
561
574
  return wrap(p.negate === true, ctx.inList(noteId, p.values));
562
575
  case "type":
563
576
  return wrap(p.negate === true, ctx.inList(typeCol, p.values));
564
- case "catalog":
565
- return wrap(p.negate === true, ctx.inList(catalogCol, p.values));
566
577
  case "source":
567
578
  return sourcePredicateSql(ctx, p.values, p.negate === true, sid, typeExpr, journalCol);
568
579
  case "tags":
@@ -570,6 +581,11 @@ function predicateSql(ctx, p, plan) {
570
581
  p.negate === true,
571
582
  `EXISTS (SELECT 1 FROM "note_tags" nt JOIN "tags" t ON t."k0" = nt."i_by_tag_0" WHERE nt."i_by_note_0" = ${noteId} AND t."i_by_label_0" IN (${p.values.map((v) => ctx.bind(v)).join(", ")}))`
572
583
  );
584
+ case "typedTag":
585
+ return wrap(
586
+ p.negate === true,
587
+ `EXISTS (SELECT 1 FROM "note_tags" nt JOIN "tags" t ON t."k0" = nt."i_by_tag_0" WHERE nt."i_by_note_0" = ${noteId} AND t."i_by_type_0" = ${ctx.bind(p.tagType)} AND t."i_by_label_0" IN (${p.values.map((v) => ctx.bind(v)).join(", ")}))`
588
+ );
573
589
  case "effort":
574
590
  return wrap(
575
591
  p.negate === true,
@@ -591,7 +607,7 @@ function predicateSql(ctx, p, plan) {
591
607
  return `(${sid} IS NULL OR ${sid} = '' OR ${all})`;
592
608
  }
593
609
  case "defaultNotes":
594
- return p.feeds ? `(n."note_type" IS NULL OR n."note_type" <> 'page')` : `(n."note_type" = 'note' OR (substr(COALESCE(n."source_id", ''), 1, 5) <> 'page:' AND substr(COALESCE(n."source_id", ''), 1, 7) <> 'guides:' AND COALESCE(n."note_type", '') NOT IN ('feed','syntax','behavior','analytics','dashboard','home','page')))`;
610
+ return p.nonPages ? `(n."note_type" IS NULL OR n."note_type" <> 'page')` : `(n."note_type" = 'note' OR (substr(COALESCE(n."source_id", ''), 1, 5) <> 'page:' AND substr(COALESCE(n."source_id", ''), 1, 7) <> 'guides:' AND COALESCE(n."note_type", '') NOT IN ('feed','syntax','behavior','analytics','dashboard','home','page')))`;
595
611
  }
596
612
  }
597
613
  function clausesSql(ctx, clauses, plan) {
@@ -642,7 +658,7 @@ async function execute(conn, q, pg) {
642
658
  const matchedCount = q.filters.length === 0 ? selectedCount : await count(fullWhere, allParams);
643
659
  const ordering = orderSql(q.order, plan);
644
660
  const paging = pagingSql(q, pg);
645
- if (plan !== "entries") {
661
+ if (plan !== "detail") {
646
662
  const pageSql2 = `SELECT "payload" FROM ${table}${fullWhere} ORDER BY ${ordering}${paging}`;
647
663
  const rows2 = (await conn.query(pageSql2, allParams)).map((r) => decodeRowJson(String(r.payload)));
648
664
  const result = { projectionVersion: DOMAIN_PROJECTION_VERSION, selectedCount, matchedCount, plan, rows: rows2 };