@earendil-works/pi-session-backend-sqlite-node 0.84.0 → 0.84.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/README.md +10 -3
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +10 -3
  5. package/dist/index.js.map +1 -1
  6. package/dist/sqlite/branch-cache.d.ts.map +1 -1
  7. package/dist/sqlite/branch-cache.js +12 -13
  8. package/dist/sqlite/branch-cache.js.map +1 -1
  9. package/dist/sqlite/index.d.ts +1 -0
  10. package/dist/sqlite/index.d.ts.map +1 -1
  11. package/dist/sqlite/index.js +1 -0
  12. package/dist/sqlite/index.js.map +1 -1
  13. package/dist/sqlite/migrations/001_initial.sql +9 -10
  14. package/dist/sqlite/migrations.d.ts.map +1 -1
  15. package/dist/sqlite/migrations.js +5 -4
  16. package/dist/sqlite/migrations.js.map +1 -1
  17. package/dist/sqlite/repo.d.ts.map +1 -1
  18. package/dist/sqlite/repo.js +60 -46
  19. package/dist/sqlite/repo.js.map +1 -1
  20. package/dist/sqlite/search-backend.d.ts +7 -2
  21. package/dist/sqlite/search-backend.d.ts.map +1 -1
  22. package/dist/sqlite/search-backend.js +60 -25
  23. package/dist/sqlite/search-backend.js.map +1 -1
  24. package/dist/sqlite/sql.d.ts +19 -0
  25. package/dist/sqlite/sql.d.ts.map +1 -0
  26. package/dist/sqlite/sql.js +58 -0
  27. package/dist/sqlite/sql.js.map +1 -0
  28. package/dist/sqlite/storage/branch-entries.d.ts +8 -2
  29. package/dist/sqlite/storage/branch-entries.d.ts.map +1 -1
  30. package/dist/sqlite/storage/branch-entries.js +87 -61
  31. package/dist/sqlite/storage/branch-entries.js.map +1 -1
  32. package/dist/sqlite/storage/branch-tips.d.ts.map +1 -1
  33. package/dist/sqlite/storage/branch-tips.js +8 -11
  34. package/dist/sqlite/storage/branch-tips.js.map +1 -1
  35. package/dist/sqlite/storage/entries.d.ts +7 -2
  36. package/dist/sqlite/storage/entries.d.ts.map +1 -1
  37. package/dist/sqlite/storage/entries.js +22 -23
  38. package/dist/sqlite/storage/entries.js.map +1 -1
  39. package/dist/sqlite/storage/facts.d.ts +1 -0
  40. package/dist/sqlite/storage/facts.d.ts.map +1 -1
  41. package/dist/sqlite/storage/facts.js +26 -29
  42. package/dist/sqlite/storage/facts.js.map +1 -1
  43. package/dist/sqlite/storage/lanes.d.ts +1 -0
  44. package/dist/sqlite/storage/lanes.d.ts.map +1 -1
  45. package/dist/sqlite/storage/lanes.js +41 -52
  46. package/dist/sqlite/storage/lanes.js.map +1 -1
  47. package/dist/sqlite/storage/records.d.ts +2 -2
  48. package/dist/sqlite/storage/records.d.ts.map +1 -1
  49. package/dist/sqlite/storage/records.js +27 -47
  50. package/dist/sqlite/storage/records.js.map +1 -1
  51. package/dist/sqlite/storage/session-sequences.d.ts.map +1 -1
  52. package/dist/sqlite/storage/session-sequences.js +5 -6
  53. package/dist/sqlite/storage/session-sequences.js.map +1 -1
  54. package/dist/sqlite/storage/session-stats.d.ts.map +1 -1
  55. package/dist/sqlite/storage/session-stats.js +14 -19
  56. package/dist/sqlite/storage/session-stats.js.map +1 -1
  57. package/dist/sqlite/storage/sessions.d.ts +2 -2
  58. package/dist/sqlite/storage/sessions.d.ts.map +1 -1
  59. package/dist/sqlite/storage/sessions.js +38 -41
  60. package/dist/sqlite/storage/sessions.js.map +1 -1
  61. package/dist/sqlite/storage/writer-leases.d.ts.map +1 -1
  62. package/dist/sqlite/storage/writer-leases.js +18 -17
  63. package/dist/sqlite/storage/writer-leases.js.map +1 -1
  64. package/dist/sqlite/types.d.ts +1 -0
  65. package/dist/sqlite/types.d.ts.map +1 -1
  66. package/dist/sqlite/types.js.map +1 -1
  67. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"facts.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/facts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,OAAO;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,UAAU,CACzB,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,QASpB;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,uBAUrG;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM;;;IAYzE;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,aAetG;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAEnE","sourcesContent":["import type { SqliteDatabase } from \"../types.ts\";\n\nexport interface FactRow {\n\tsession_id: string;\n\tseq: number;\n\tkind: string;\n\tkey: string | null;\n\tvalue: string | null;\n}\n\nexport function appendFact(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tseq: number,\n\tkind: string,\n\tkey: string | null,\n\tvalue: string | null,\n) {\n\tdb.prepare(\"INSERT INTO facts (session_id, seq, kind, key, value) VALUES (?, ?, ?, ?, ?)\").run(\n\t\tsessionId,\n\t\tseq,\n\t\tkind,\n\t\tkey,\n\t\tvalue,\n\t);\n}\n\nexport function readLatestFact(db: SqliteDatabase, sessionId: string, kind: string, key: string | null) {\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, kind, key, value\n\t\t\tFROM facts\n\t\t\tWHERE session_id = ? AND kind = ? AND key IS ?\n\t\t\tORDER BY seq DESC\n\t\t\tLIMIT 1`,\n\t\t)\n\t\t.get<FactRow>(sessionId, kind, key);\n}\n\nexport function readLatestLabelFacts(db: SqliteDatabase, sessionId: string) {\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT key, value FROM (\n\t\t\t\tSELECT key, value, ROW_NUMBER() OVER (PARTITION BY key ORDER BY seq DESC) AS rank\n\t\t\t\tFROM facts\n\t\t\t\tWHERE session_id = ? AND kind = 'label'\n\t\t\t)\n\t\t\tWHERE rank = 1 AND value IS NOT NULL\n\t\t\tORDER BY key`,\n\t\t)\n\t\t.all<{ key: string; value: string }>(sessionId);\n}\n\nexport function readFactRows(db: SqliteDatabase, sessionId: string, options: { afterSeq?: number } = {}) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (options.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(options.afterSeq);\n\t}\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, kind, key, value\n\t\t\tFROM facts\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq`,\n\t\t)\n\t\t.all<FactRow>(...params);\n}\n\nexport function deleteFactRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM facts WHERE session_id = ?\").run(sessionId);\n}\n"]}
1
+ {"version":3,"file":"facts.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/facts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,OAAO;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,UAAU,CACzB,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,QAKpB;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,uBAMrG;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM;;;IAczE;AAED,wBAAgB,YAAY,CAC3B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,aAQnD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAEnE","sourcesContent":["import { sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface FactRow {\n\tsession_id: string;\n\tseq: number;\n\tkind: string;\n\tkey: string | null;\n\tvalue: string | null;\n}\n\nexport function appendFact(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tseq: number,\n\tkind: string,\n\tkey: string | null,\n\tvalue: string | null,\n) {\n\tsql`INSERT INTO facts (session_id, seq, kind, key, value) VALUES (${sessionId}, ${seq}, ${kind}, ${key}, ${value})`.run(\n\t\tdb,\n\t);\n}\n\nexport function readLatestFact(db: SqliteDatabase, sessionId: string, kind: string, key: string | null) {\n\treturn sql`SELECT session_id, seq, kind, key, value\n\t\tFROM facts INDEXED BY idx_facts_session_kind_key_seq\n\t\tWHERE session_id = ${sessionId} AND kind = ${kind} AND key IS ${key}\n\t\tORDER BY seq DESC\n\t\tLIMIT 1`.get<FactRow>(db);\n}\n\nexport function readLatestLabelFacts(db: SqliteDatabase, sessionId: string) {\n\treturn sql`SELECT f.key, f.value\n\t\tFROM facts AS f INDEXED BY idx_facts_session_kind_key_seq\n\t\tWHERE f.session_id = ${sessionId}\n\t\t\tAND f.kind = 'label'\n\t\t\tAND f.value IS NOT NULL\n\t\t\tAND f.seq = (\n\t\t\t\tSELECT MAX(candidate.seq)\n\t\t\t\tFROM facts AS candidate INDEXED BY idx_facts_session_kind_key_seq\n\t\t\t\tWHERE candidate.session_id = f.session_id\n\t\t\t\t\tAND candidate.kind = f.kind\n\t\t\t\t\tAND candidate.key IS f.key\n\t\t\t)\n\t\tORDER BY f.key`.all<{ key: string; value: string }>(db);\n}\n\nexport function readFactRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\toptions: { afterSeq?: number; limit?: number } = {},\n) {\n\tconst after = options.afterSeq === undefined ? sql`` : sql` AND seq > ${options.afterSeq}`;\n\tconst limit = options.limit === undefined ? sql`` : sql` LIMIT ${options.limit}`;\n\treturn sql`SELECT session_id, seq, kind, key, value\n\t\tFROM facts\n\t\tWHERE session_id = ${sessionId}${after}\n\t\tORDER BY seq${limit}`.all<FactRow>(db);\n}\n\nexport function deleteFactRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM facts WHERE session_id = ${sessionId}`.run(db);\n}\n"]}
@@ -1,41 +1,38 @@
1
+ import { sql } from "../sql.js";
1
2
  export function appendFact(db, sessionId, seq, kind, key, value) {
2
- db.prepare("INSERT INTO facts (session_id, seq, kind, key, value) VALUES (?, ?, ?, ?, ?)").run(sessionId, seq, kind, key, value);
3
+ sql `INSERT INTO facts (session_id, seq, kind, key, value) VALUES (${sessionId}, ${seq}, ${kind}, ${key}, ${value})`.run(db);
3
4
  }
4
5
  export function readLatestFact(db, sessionId, kind, key) {
5
- return db
6
- .prepare(`SELECT session_id, seq, kind, key, value
7
- FROM facts
8
- WHERE session_id = ? AND kind = ? AND key IS ?
9
- ORDER BY seq DESC
10
- LIMIT 1`)
11
- .get(sessionId, kind, key);
6
+ return sql `SELECT session_id, seq, kind, key, value
7
+ FROM facts INDEXED BY idx_facts_session_kind_key_seq
8
+ WHERE session_id = ${sessionId} AND kind = ${kind} AND key IS ${key}
9
+ ORDER BY seq DESC
10
+ LIMIT 1`.get(db);
12
11
  }
13
12
  export function readLatestLabelFacts(db, sessionId) {
14
- return db
15
- .prepare(`SELECT key, value FROM (
16
- SELECT key, value, ROW_NUMBER() OVER (PARTITION BY key ORDER BY seq DESC) AS rank
17
- FROM facts
18
- WHERE session_id = ? AND kind = 'label'
13
+ return sql `SELECT f.key, f.value
14
+ FROM facts AS f INDEXED BY idx_facts_session_kind_key_seq
15
+ WHERE f.session_id = ${sessionId}
16
+ AND f.kind = 'label'
17
+ AND f.value IS NOT NULL
18
+ AND f.seq = (
19
+ SELECT MAX(candidate.seq)
20
+ FROM facts AS candidate INDEXED BY idx_facts_session_kind_key_seq
21
+ WHERE candidate.session_id = f.session_id
22
+ AND candidate.kind = f.kind
23
+ AND candidate.key IS f.key
19
24
  )
20
- WHERE rank = 1 AND value IS NOT NULL
21
- ORDER BY key`)
22
- .all(sessionId);
25
+ ORDER BY f.key`.all(db);
23
26
  }
24
27
  export function readFactRows(db, sessionId, options = {}) {
25
- const predicates = ["session_id = ?"];
26
- const params = [sessionId];
27
- if (options.afterSeq !== undefined) {
28
- predicates.push("seq > ?");
29
- params.push(options.afterSeq);
30
- }
31
- return db
32
- .prepare(`SELECT session_id, seq, kind, key, value
33
- FROM facts
34
- WHERE ${predicates.join(" AND ")}
35
- ORDER BY seq`)
36
- .all(...params);
28
+ const after = options.afterSeq === undefined ? sql `` : sql ` AND seq > ${options.afterSeq}`;
29
+ const limit = options.limit === undefined ? sql `` : sql ` LIMIT ${options.limit}`;
30
+ return sql `SELECT session_id, seq, kind, key, value
31
+ FROM facts
32
+ WHERE session_id = ${sessionId}${after}
33
+ ORDER BY seq${limit}`.all(db);
37
34
  }
38
35
  export function deleteFactRows(db, sessionId) {
39
- db.prepare("DELETE FROM facts WHERE session_id = ?").run(sessionId);
36
+ sql `DELETE FROM facts WHERE session_id = ${sessionId}`.run(db);
40
37
  }
41
38
  //# sourceMappingURL=facts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"facts.js","sourceRoot":"","sources":["../../../src/sqlite/storage/facts.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,UAAU,CACzB,EAAkB,EAClB,SAAiB,EACjB,GAAW,EACX,IAAY,EACZ,GAAkB,EAClB,KAAoB,EACnB;IACD,EAAE,CAAC,OAAO,CAAC,8EAA8E,CAAC,CAAC,GAAG,CAC7F,SAAS,EACT,GAAG,EACH,IAAI,EACJ,GAAG,EACH,KAAK,CACL,CAAC;AAAA,CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE,GAAkB,EAAE;IACvG,OAAO,EAAE;SACP,OAAO,CACP;;;;WAIQ,CACR;SACA,GAAG,CAAU,SAAS,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;AAAA,CACrC;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAkB,EAAE,SAAiB,EAAE;IAC3E,OAAO,EAAE;SACP,OAAO,CACP;;;;;;gBAMa,CACb;SACA,GAAG,CAAiC,SAAS,CAAC,CAAC;AAAA,CACjD;AAED,MAAM,UAAU,YAAY,CAAC,EAAkB,EAAE,SAAiB,EAAE,OAAO,GAA0B,EAAE,EAAE;IACxG,MAAM,UAAU,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,MAAM,MAAM,GAAc,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE;SACP,OAAO,CACP;;WAEQ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;gBACnB,CACb;SACA,GAAG,CAAU,GAAG,MAAM,CAAC,CAAC;AAAA,CAC1B;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE;IACrE,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAAA,CACpE","sourcesContent":["import type { SqliteDatabase } from \"../types.ts\";\n\nexport interface FactRow {\n\tsession_id: string;\n\tseq: number;\n\tkind: string;\n\tkey: string | null;\n\tvalue: string | null;\n}\n\nexport function appendFact(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tseq: number,\n\tkind: string,\n\tkey: string | null,\n\tvalue: string | null,\n) {\n\tdb.prepare(\"INSERT INTO facts (session_id, seq, kind, key, value) VALUES (?, ?, ?, ?, ?)\").run(\n\t\tsessionId,\n\t\tseq,\n\t\tkind,\n\t\tkey,\n\t\tvalue,\n\t);\n}\n\nexport function readLatestFact(db: SqliteDatabase, sessionId: string, kind: string, key: string | null) {\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, kind, key, value\n\t\t\tFROM facts\n\t\t\tWHERE session_id = ? AND kind = ? AND key IS ?\n\t\t\tORDER BY seq DESC\n\t\t\tLIMIT 1`,\n\t\t)\n\t\t.get<FactRow>(sessionId, kind, key);\n}\n\nexport function readLatestLabelFacts(db: SqliteDatabase, sessionId: string) {\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT key, value FROM (\n\t\t\t\tSELECT key, value, ROW_NUMBER() OVER (PARTITION BY key ORDER BY seq DESC) AS rank\n\t\t\t\tFROM facts\n\t\t\t\tWHERE session_id = ? AND kind = 'label'\n\t\t\t)\n\t\t\tWHERE rank = 1 AND value IS NOT NULL\n\t\t\tORDER BY key`,\n\t\t)\n\t\t.all<{ key: string; value: string }>(sessionId);\n}\n\nexport function readFactRows(db: SqliteDatabase, sessionId: string, options: { afterSeq?: number } = {}) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (options.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(options.afterSeq);\n\t}\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, kind, key, value\n\t\t\tFROM facts\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq`,\n\t\t)\n\t\t.all<FactRow>(...params);\n}\n\nexport function deleteFactRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM facts WHERE session_id = ?\").run(sessionId);\n}\n"]}
1
+ {"version":3,"file":"facts.js","sourceRoot":"","sources":["../../../src/sqlite/storage/facts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAWhC,MAAM,UAAU,UAAU,CACzB,EAAkB,EAClB,SAAiB,EACjB,GAAW,EACX,IAAY,EACZ,GAAkB,EAClB,KAAoB,EACnB;IACD,GAAG,CAAA,iEAAiE,SAAS,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,KAAK,KAAK,GAAG,CAAC,GAAG,CACtH,EAAE,CACF,CAAC;AAAA,CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE,GAAkB,EAAE;IACvG,OAAO,GAAG,CAAA;;uBAEY,SAAS,eAAe,IAAI,eAAe,GAAG;;UAE3D,CAAC,GAAG,CAAU,EAAE,CAAC,CAAC;AAAA,CAC3B;AAED,MAAM,UAAU,oBAAoB,CAAC,EAAkB,EAAE,SAAiB,EAAE;IAC3E,OAAO,GAAG,CAAA;;yBAEc,SAAS;;;;;;;;;;iBAUjB,CAAC,GAAG,CAAiC,EAAE,CAAC,CAAC;AAAA,CACzD;AAED,MAAM,UAAU,YAAY,CAC3B,EAAkB,EAClB,SAAiB,EACjB,OAAO,GAA0C,EAAE,EAClD;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC3F,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA,UAAU,OAAO,CAAC,KAAK,EAAE,CAAC;IACjF,OAAO,GAAG,CAAA;;uBAEY,SAAS,GAAG,KAAK;gBACxB,KAAK,EAAE,CAAC,GAAG,CAAU,EAAE,CAAC,CAAC;AAAA,CACxC;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE;IACrE,GAAG,CAAA,wCAAwC,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC/D","sourcesContent":["import { sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface FactRow {\n\tsession_id: string;\n\tseq: number;\n\tkind: string;\n\tkey: string | null;\n\tvalue: string | null;\n}\n\nexport function appendFact(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tseq: number,\n\tkind: string,\n\tkey: string | null,\n\tvalue: string | null,\n) {\n\tsql`INSERT INTO facts (session_id, seq, kind, key, value) VALUES (${sessionId}, ${seq}, ${kind}, ${key}, ${value})`.run(\n\t\tdb,\n\t);\n}\n\nexport function readLatestFact(db: SqliteDatabase, sessionId: string, kind: string, key: string | null) {\n\treturn sql`SELECT session_id, seq, kind, key, value\n\t\tFROM facts INDEXED BY idx_facts_session_kind_key_seq\n\t\tWHERE session_id = ${sessionId} AND kind = ${kind} AND key IS ${key}\n\t\tORDER BY seq DESC\n\t\tLIMIT 1`.get<FactRow>(db);\n}\n\nexport function readLatestLabelFacts(db: SqliteDatabase, sessionId: string) {\n\treturn sql`SELECT f.key, f.value\n\t\tFROM facts AS f INDEXED BY idx_facts_session_kind_key_seq\n\t\tWHERE f.session_id = ${sessionId}\n\t\t\tAND f.kind = 'label'\n\t\t\tAND f.value IS NOT NULL\n\t\t\tAND f.seq = (\n\t\t\t\tSELECT MAX(candidate.seq)\n\t\t\t\tFROM facts AS candidate INDEXED BY idx_facts_session_kind_key_seq\n\t\t\t\tWHERE candidate.session_id = f.session_id\n\t\t\t\t\tAND candidate.kind = f.kind\n\t\t\t\t\tAND candidate.key IS f.key\n\t\t\t)\n\t\tORDER BY f.key`.all<{ key: string; value: string }>(db);\n}\n\nexport function readFactRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\toptions: { afterSeq?: number; limit?: number } = {},\n) {\n\tconst after = options.afterSeq === undefined ? sql`` : sql` AND seq > ${options.afterSeq}`;\n\tconst limit = options.limit === undefined ? sql`` : sql` LIMIT ${options.limit}`;\n\treturn sql`SELECT session_id, seq, kind, key, value\n\t\tFROM facts\n\t\tWHERE session_id = ${sessionId}${after}\n\t\tORDER BY seq${limit}`.all<FactRow>(db);\n}\n\nexport function deleteFactRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM facts WHERE session_id = ${sessionId}`.run(db);\n}\n"]}
@@ -29,6 +29,7 @@ export declare function startLaneOperation(db: SqliteDatabase, sessionId: string
29
29
  export declare function finishLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string): void;
30
30
  export declare function readLaneMoveRows(db: SqliteDatabase, sessionId: string, options?: {
31
31
  afterSeq?: number;
32
+ limit?: number;
32
33
  }): LaneMoveRow[];
33
34
  export declare function deleteLaneRows(db: SqliteDatabase, sessionId: string): void;
34
35
  //# sourceMappingURL=lanes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lanes.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/lanes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,OAAO;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,QAMnH;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM;;;;;IA2B9D;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAI3E;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;;EAe/E;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAOjH;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAM/G;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAKrG;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAQpG;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAIrG;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,iBAe1G;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAGnE","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface LaneRow {\n\tsession_id: string;\n\tlane: string;\n\tleaf_id: string | null;\n\topen_operation_id: string | null;\n}\n\nexport interface LaneMoveRow {\n\tsession_id: string;\n\tseq: number;\n\tlane: string;\n\tleaf_id: string | null;\n}\n\nexport function createInitialLane(db: SqliteDatabase, sessionId: string, lane = \"main\", leafId: string | null = null) {\n\tdb.prepare(\"INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)\").run(\n\t\tsessionId,\n\t\tlane,\n\t\tleafId,\n\t);\n}\n\nexport function readLanes(db: SqliteDatabase, sessionId: string) {\n\tconst rows = db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\tl.session_id,\n\t\t\t\tl.lane,\n\t\t\t\tl.leaf_id,\n\t\t\t\tl.open_operation_id,\n\t\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t\t)) AS leaf_exists\n\t\t\tFROM lanes AS l\n\t\t\tWHERE l.session_id = ?\n\t\t\tORDER BY l.lane`,\n\t\t)\n\t\t.all<LaneRow & { leaf_exists: number }>(sessionId);\n\tfor (const row of rows) {\n\t\tif (row.leaf_exists === 0) {\n\t\t\tthrow new SessionError(\"storage\", `Lane ${row.lane} points at missing entry ${row.leaf_id}`);\n\t\t}\n\t}\n\treturn rows.map(({ session_id, lane, leaf_id, open_operation_id }) => ({\n\t\tsession_id,\n\t\tlane,\n\t\tleaf_id,\n\t\topen_operation_id,\n\t}));\n}\n\nexport function readLane(db: SqliteDatabase, sessionId: string, lane: string) {\n\treturn db\n\t\t.prepare(\"SELECT session_id, lane, leaf_id, open_operation_id FROM lanes WHERE session_id = ? AND lane = ?\")\n\t\t.get<LaneRow>(sessionId, lane);\n}\n\nexport function readLaneHead(db: SqliteDatabase, sessionId: string, lane: string) {\n\tconst row = db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\tl.leaf_id,\n\t\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t\t)) AS leaf_exists\n\t\t\tFROM lanes AS l\n\t\t\tWHERE l.session_id = ? AND l.lane = ?`,\n\t\t)\n\t\t.get<{ leaf_id: string | null; leaf_exists: number }>(sessionId, lane);\n\tif (!row) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tif (row.leaf_exists === 0) throw new SessionError(\"storage\", `Entry ${row.leaf_id} not found`);\n\treturn { leafId: row.leaf_id };\n}\n\nexport function createLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tdb.prepare(\"INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)\").run(\n\t\tsessionId,\n\t\tlane,\n\t\tleafId,\n\t);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function moveLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?\")\n\t\t.run(leafId, sessionId, lane);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function setLaneLeaf(db: SqliteDatabase, sessionId: string, lane: string, leafId: string | null) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?\")\n\t\t.run(leafId, sessionId, lane);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n}\n\nexport function startLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET open_operation_id = ? WHERE session_id = ? AND lane = ? AND open_operation_id IS NULL\")\n\t\t.run(runId, sessionId, lane);\n\tif (result.changes === 1) return;\n\tconst current = readLane(db, sessionId, lane);\n\tif (!current) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tthrow new SessionError(\"storage\", `Lane ${lane} already has an open operation ${current.open_operation_id}`);\n}\n\nexport function finishLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tdb.prepare(\n\t\t\"UPDATE lanes SET open_operation_id = NULL WHERE session_id = ? AND lane = ? AND open_operation_id = ?\",\n\t).run(sessionId, lane, runId);\n}\n\nexport function readLaneMoveRows(db: SqliteDatabase, sessionId: string, options: { afterSeq?: number } = {}) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (options.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(options.afterSeq);\n\t}\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, lane, leaf_id\n\t\t\tFROM lane_moves\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq`,\n\t\t)\n\t\t.all<LaneMoveRow>(...params);\n}\n\nexport function deleteLaneRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM lane_moves WHERE session_id = ?\").run(sessionId);\n\tdb.prepare(\"DELETE FROM lanes WHERE session_id = ?\").run(sessionId);\n}\n\nfunction appendLaneMove(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tdb.prepare(\"INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (?, ?, ?, ?)\").run(\n\t\tsessionId,\n\t\tseq,\n\t\tlane,\n\t\tleafId,\n\t);\n}\n"]}
1
+ {"version":3,"file":"lanes.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/lanes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,OAAO;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,MAAM,GAAE,MAAM,GAAG,IAAW,QAGnH;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM;;;;;IAuB9D;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,uBAI3E;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;;EAc/E;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAIjH;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAI/G;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,QAGrG;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAOpG;AAED,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAGrG;AAED,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,iBAQnD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAGnE","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport { sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface LaneRow {\n\tsession_id: string;\n\tlane: string;\n\tleaf_id: string | null;\n\topen_operation_id: string | null;\n}\n\nexport interface LaneMoveRow {\n\tsession_id: string;\n\tseq: number;\n\tlane: string;\n\tleaf_id: string | null;\n}\n\nexport function createInitialLane(db: SqliteDatabase, sessionId: string, lane = \"main\", leafId: string | null = null) {\n\tsql`INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)\n\t\tVALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);\n}\n\nexport function readLanes(db: SqliteDatabase, sessionId: string) {\n\tconst rows = sql`SELECT\n\t\t\tl.session_id,\n\t\t\tl.lane,\n\t\t\tl.leaf_id,\n\t\t\tl.open_operation_id,\n\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t)) AS leaf_exists\n\t\tFROM lanes AS l\n\t\tWHERE l.session_id = ${sessionId}\n\t\tORDER BY l.lane`.all<LaneRow & { leaf_exists: number }>(db);\n\tfor (const row of rows) {\n\t\tif (row.leaf_exists === 0) {\n\t\t\tthrow new SessionError(\"storage\", `Lane ${row.lane} points at missing entry ${row.leaf_id}`);\n\t\t}\n\t}\n\treturn rows.map(({ session_id, lane, leaf_id, open_operation_id }) => ({\n\t\tsession_id,\n\t\tlane,\n\t\tleaf_id,\n\t\topen_operation_id,\n\t}));\n}\n\nexport function readLane(db: SqliteDatabase, sessionId: string, lane: string) {\n\treturn sql`SELECT session_id, lane, leaf_id, open_operation_id\n\t\tFROM lanes\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane}`.get<LaneRow>(db);\n}\n\nexport function readLaneHead(db: SqliteDatabase, sessionId: string, lane: string) {\n\tconst row = sql`SELECT\n\t\t\tl.leaf_id,\n\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t)) AS leaf_exists\n\t\tFROM lanes AS l\n\t\tWHERE l.session_id = ${sessionId} AND l.lane = ${lane}`.get<{\n\t\tleaf_id: string | null;\n\t\tleaf_exists: number;\n\t}>(db);\n\tif (!row) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tif (row.leaf_exists === 0) throw new SessionError(\"storage\", `Entry ${row.leaf_id} not found`);\n\treturn { leafId: row.leaf_id };\n}\n\nexport function createLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tsql`INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)\n\t\tVALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function moveLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tconst result = sql`UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function setLaneLeaf(db: SqliteDatabase, sessionId: string, lane: string, leafId: string | null) {\n\tconst result = sql`UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n}\n\nexport function startLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tconst result = sql`UPDATE lanes SET open_operation_id = ${runId}\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id IS NULL`.run(db);\n\tif (result.changes === 1) return;\n\tconst current = readLane(db, sessionId, lane);\n\tif (!current) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tthrow new SessionError(\"storage\", `Lane ${lane} already has an open operation ${current.open_operation_id}`);\n}\n\nexport function finishLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tsql`UPDATE lanes SET open_operation_id = NULL\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id = ${runId}`.run(db);\n}\n\nexport function readLaneMoveRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\toptions: { afterSeq?: number; limit?: number } = {},\n) {\n\tconst after = options.afterSeq === undefined ? sql`` : sql` AND seq > ${options.afterSeq}`;\n\tconst limit = options.limit === undefined ? sql`` : sql` LIMIT ${options.limit}`;\n\treturn sql`SELECT session_id, seq, lane, leaf_id\n\t\tFROM lane_moves\n\t\tWHERE session_id = ${sessionId}${after}\n\t\tORDER BY seq${limit}`.all<LaneMoveRow>(db);\n}\n\nexport function deleteLaneRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM lane_moves WHERE session_id = ${sessionId}`.run(db);\n\tsql`DELETE FROM lanes WHERE session_id = ${sessionId}`.run(db);\n}\n\nfunction appendLaneMove(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tsql`INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (${sessionId}, ${seq}, ${lane}, ${leafId})`.run(\n\t\tdb,\n\t);\n}\n"]}
@@ -1,21 +1,21 @@
1
1
  import { SessionError } from "@earendil-works/pi-agent-core";
2
+ import { sql } from "../sql.js";
2
3
  export function createInitialLane(db, sessionId, lane = "main", leafId = null) {
3
- db.prepare("INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)").run(sessionId, lane, leafId);
4
+ sql `INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)
5
+ VALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);
4
6
  }
5
7
  export function readLanes(db, sessionId) {
6
- const rows = db
7
- .prepare(`SELECT
8
- l.session_id,
9
- l.lane,
10
- l.leaf_id,
11
- l.open_operation_id,
12
- (l.leaf_id IS NULL OR EXISTS (
13
- SELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id
14
- )) AS leaf_exists
15
- FROM lanes AS l
16
- WHERE l.session_id = ?
17
- ORDER BY l.lane`)
18
- .all(sessionId);
8
+ const rows = sql `SELECT
9
+ l.session_id,
10
+ l.lane,
11
+ l.leaf_id,
12
+ l.open_operation_id,
13
+ (l.leaf_id IS NULL OR EXISTS (
14
+ SELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id
15
+ )) AS leaf_exists
16
+ FROM lanes AS l
17
+ WHERE l.session_id = ${sessionId}
18
+ ORDER BY l.lane`.all(db);
19
19
  for (const row of rows) {
20
20
  if (row.leaf_exists === 0) {
21
21
  throw new SessionError("storage", `Lane ${row.lane} points at missing entry ${row.leaf_id}`);
@@ -29,20 +29,18 @@ export function readLanes(db, sessionId) {
29
29
  }));
30
30
  }
31
31
  export function readLane(db, sessionId, lane) {
32
- return db
33
- .prepare("SELECT session_id, lane, leaf_id, open_operation_id FROM lanes WHERE session_id = ? AND lane = ?")
34
- .get(sessionId, lane);
32
+ return sql `SELECT session_id, lane, leaf_id, open_operation_id
33
+ FROM lanes
34
+ WHERE session_id = ${sessionId} AND lane = ${lane}`.get(db);
35
35
  }
36
36
  export function readLaneHead(db, sessionId, lane) {
37
- const row = db
38
- .prepare(`SELECT
39
- l.leaf_id,
40
- (l.leaf_id IS NULL OR EXISTS (
41
- SELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id
42
- )) AS leaf_exists
43
- FROM lanes AS l
44
- WHERE l.session_id = ? AND l.lane = ?`)
45
- .get(sessionId, lane);
37
+ const row = sql `SELECT
38
+ l.leaf_id,
39
+ (l.leaf_id IS NULL OR EXISTS (
40
+ SELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id
41
+ )) AS leaf_exists
42
+ FROM lanes AS l
43
+ WHERE l.session_id = ${sessionId} AND l.lane = ${lane}`.get(db);
46
44
  if (!row)
47
45
  throw new SessionError("invalid_lane", `Lane not found: ${lane}`);
48
46
  if (row.leaf_exists === 0)
@@ -50,28 +48,24 @@ export function readLaneHead(db, sessionId, lane) {
50
48
  return { leafId: row.leaf_id };
51
49
  }
52
50
  export function createLane(db, sessionId, seq, lane, leafId) {
53
- db.prepare("INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)").run(sessionId, lane, leafId);
51
+ sql `INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)
52
+ VALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);
54
53
  appendLaneMove(db, sessionId, seq, lane, leafId);
55
54
  }
56
55
  export function moveLane(db, sessionId, seq, lane, leafId) {
57
- const result = db
58
- .prepare("UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?")
59
- .run(leafId, sessionId, lane);
56
+ const result = sql `UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);
60
57
  if (result.changes !== 1)
61
58
  throw new SessionError("invalid_lane", `Lane not found: ${lane}`);
62
59
  appendLaneMove(db, sessionId, seq, lane, leafId);
63
60
  }
64
61
  export function setLaneLeaf(db, sessionId, lane, leafId) {
65
- const result = db
66
- .prepare("UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?")
67
- .run(leafId, sessionId, lane);
62
+ const result = sql `UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);
68
63
  if (result.changes !== 1)
69
64
  throw new SessionError("invalid_lane", `Lane not found: ${lane}`);
70
65
  }
71
66
  export function startLaneOperation(db, sessionId, lane, runId) {
72
- const result = db
73
- .prepare("UPDATE lanes SET open_operation_id = ? WHERE session_id = ? AND lane = ? AND open_operation_id IS NULL")
74
- .run(runId, sessionId, lane);
67
+ const result = sql `UPDATE lanes SET open_operation_id = ${runId}
68
+ WHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id IS NULL`.run(db);
75
69
  if (result.changes === 1)
76
70
  return;
77
71
  const current = readLane(db, sessionId, lane);
@@ -80,27 +74,22 @@ export function startLaneOperation(db, sessionId, lane, runId) {
80
74
  throw new SessionError("storage", `Lane ${lane} already has an open operation ${current.open_operation_id}`);
81
75
  }
82
76
  export function finishLaneOperation(db, sessionId, lane, runId) {
83
- db.prepare("UPDATE lanes SET open_operation_id = NULL WHERE session_id = ? AND lane = ? AND open_operation_id = ?").run(sessionId, lane, runId);
77
+ sql `UPDATE lanes SET open_operation_id = NULL
78
+ WHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id = ${runId}`.run(db);
84
79
  }
85
80
  export function readLaneMoveRows(db, sessionId, options = {}) {
86
- const predicates = ["session_id = ?"];
87
- const params = [sessionId];
88
- if (options.afterSeq !== undefined) {
89
- predicates.push("seq > ?");
90
- params.push(options.afterSeq);
91
- }
92
- return db
93
- .prepare(`SELECT session_id, seq, lane, leaf_id
94
- FROM lane_moves
95
- WHERE ${predicates.join(" AND ")}
96
- ORDER BY seq`)
97
- .all(...params);
81
+ const after = options.afterSeq === undefined ? sql `` : sql ` AND seq > ${options.afterSeq}`;
82
+ const limit = options.limit === undefined ? sql `` : sql ` LIMIT ${options.limit}`;
83
+ return sql `SELECT session_id, seq, lane, leaf_id
84
+ FROM lane_moves
85
+ WHERE session_id = ${sessionId}${after}
86
+ ORDER BY seq${limit}`.all(db);
98
87
  }
99
88
  export function deleteLaneRows(db, sessionId) {
100
- db.prepare("DELETE FROM lane_moves WHERE session_id = ?").run(sessionId);
101
- db.prepare("DELETE FROM lanes WHERE session_id = ?").run(sessionId);
89
+ sql `DELETE FROM lane_moves WHERE session_id = ${sessionId}`.run(db);
90
+ sql `DELETE FROM lanes WHERE session_id = ${sessionId}`.run(db);
102
91
  }
103
92
  function appendLaneMove(db, sessionId, seq, lane, leafId) {
104
- db.prepare("INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (?, ?, ?, ?)").run(sessionId, seq, lane, leafId);
93
+ sql `INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (${sessionId}, ${seq}, ${lane}, ${leafId})`.run(db);
105
94
  }
106
95
  //# sourceMappingURL=lanes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lanes.js","sourceRoot":"","sources":["../../../src/sqlite/storage/lanes.ts"],"names":[],"mappings":"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","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface LaneRow {\n\tsession_id: string;\n\tlane: string;\n\tleaf_id: string | null;\n\topen_operation_id: string | null;\n}\n\nexport interface LaneMoveRow {\n\tsession_id: string;\n\tseq: number;\n\tlane: string;\n\tleaf_id: string | null;\n}\n\nexport function createInitialLane(db: SqliteDatabase, sessionId: string, lane = \"main\", leafId: string | null = null) {\n\tdb.prepare(\"INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)\").run(\n\t\tsessionId,\n\t\tlane,\n\t\tleafId,\n\t);\n}\n\nexport function readLanes(db: SqliteDatabase, sessionId: string) {\n\tconst rows = db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\tl.session_id,\n\t\t\t\tl.lane,\n\t\t\t\tl.leaf_id,\n\t\t\t\tl.open_operation_id,\n\t\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t\t)) AS leaf_exists\n\t\t\tFROM lanes AS l\n\t\t\tWHERE l.session_id = ?\n\t\t\tORDER BY l.lane`,\n\t\t)\n\t\t.all<LaneRow & { leaf_exists: number }>(sessionId);\n\tfor (const row of rows) {\n\t\tif (row.leaf_exists === 0) {\n\t\t\tthrow new SessionError(\"storage\", `Lane ${row.lane} points at missing entry ${row.leaf_id}`);\n\t\t}\n\t}\n\treturn rows.map(({ session_id, lane, leaf_id, open_operation_id }) => ({\n\t\tsession_id,\n\t\tlane,\n\t\tleaf_id,\n\t\topen_operation_id,\n\t}));\n}\n\nexport function readLane(db: SqliteDatabase, sessionId: string, lane: string) {\n\treturn db\n\t\t.prepare(\"SELECT session_id, lane, leaf_id, open_operation_id FROM lanes WHERE session_id = ? AND lane = ?\")\n\t\t.get<LaneRow>(sessionId, lane);\n}\n\nexport function readLaneHead(db: SqliteDatabase, sessionId: string, lane: string) {\n\tconst row = db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\tl.leaf_id,\n\t\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t\t)) AS leaf_exists\n\t\t\tFROM lanes AS l\n\t\t\tWHERE l.session_id = ? AND l.lane = ?`,\n\t\t)\n\t\t.get<{ leaf_id: string | null; leaf_exists: number }>(sessionId, lane);\n\tif (!row) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tif (row.leaf_exists === 0) throw new SessionError(\"storage\", `Entry ${row.leaf_id} not found`);\n\treturn { leafId: row.leaf_id };\n}\n\nexport function createLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tdb.prepare(\"INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id) VALUES (?, ?, ?, NULL)\").run(\n\t\tsessionId,\n\t\tlane,\n\t\tleafId,\n\t);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function moveLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?\")\n\t\t.run(leafId, sessionId, lane);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function setLaneLeaf(db: SqliteDatabase, sessionId: string, lane: string, leafId: string | null) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET leaf_id = ? WHERE session_id = ? AND lane = ?\")\n\t\t.run(leafId, sessionId, lane);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n}\n\nexport function startLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tconst result = db\n\t\t.prepare(\"UPDATE lanes SET open_operation_id = ? WHERE session_id = ? AND lane = ? AND open_operation_id IS NULL\")\n\t\t.run(runId, sessionId, lane);\n\tif (result.changes === 1) return;\n\tconst current = readLane(db, sessionId, lane);\n\tif (!current) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tthrow new SessionError(\"storage\", `Lane ${lane} already has an open operation ${current.open_operation_id}`);\n}\n\nexport function finishLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tdb.prepare(\n\t\t\"UPDATE lanes SET open_operation_id = NULL WHERE session_id = ? AND lane = ? AND open_operation_id = ?\",\n\t).run(sessionId, lane, runId);\n}\n\nexport function readLaneMoveRows(db: SqliteDatabase, sessionId: string, options: { afterSeq?: number } = {}) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (options.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(options.afterSeq);\n\t}\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, lane, leaf_id\n\t\t\tFROM lane_moves\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq`,\n\t\t)\n\t\t.all<LaneMoveRow>(...params);\n}\n\nexport function deleteLaneRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM lane_moves WHERE session_id = ?\").run(sessionId);\n\tdb.prepare(\"DELETE FROM lanes WHERE session_id = ?\").run(sessionId);\n}\n\nfunction appendLaneMove(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tdb.prepare(\"INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (?, ?, ?, ?)\").run(\n\t\tsessionId,\n\t\tseq,\n\t\tlane,\n\t\tleafId,\n\t);\n}\n"]}
1
+ {"version":3,"file":"lanes.js","sourceRoot":"","sources":["../../../src/sqlite/storage/lanes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAiBhC,MAAM,UAAU,iBAAiB,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAI,GAAG,MAAM,EAAE,MAAM,GAAkB,IAAI,EAAE;IACrH,GAAG,CAAA;YACQ,SAAS,KAAK,IAAI,KAAK,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC1D;AAED,MAAM,UAAU,SAAS,CAAC,EAAkB,EAAE,SAAiB,EAAE;IAChE,MAAM,IAAI,GAAG,GAAG,CAAA;;;;;;;;;yBASQ,SAAS;kBAChB,CAAC,GAAG,CAAoC,EAAE,CAAC,CAAC;IAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,GAAG,CAAC,IAAI,4BAA4B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9F,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,CAAC,CAAC;QACtE,UAAU;QACV,IAAI;QACJ,OAAO;QACP,iBAAiB;KACjB,CAAC,CAAC,CAAC;AAAA,CACJ;AAED,MAAM,UAAU,QAAQ,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE;IAC7E,OAAO,GAAG,CAAA;;uBAEY,SAAS,eAAe,IAAI,EAAE,CAAC,GAAG,CAAU,EAAE,CAAC,CAAC;AAAA,CACtE;AAED,MAAM,UAAU,YAAY,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE;IACjF,MAAM,GAAG,GAAG,GAAG,CAAA;;;;;;yBAMS,SAAS,iBAAiB,IAAI,EAAE,CAAC,GAAG,CAGzD,EAAE,CAAC,CAAC;IACP,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC5E,IAAI,GAAG,CAAC,WAAW,KAAK,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC;IAC/F,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;AAAA,CAC/B;AAED,MAAM,UAAU,UAAU,CAAC,EAAkB,EAAE,SAAiB,EAAE,GAAW,EAAE,IAAY,EAAE,MAAqB,EAAE;IACnH,GAAG,CAAA;YACQ,SAAS,KAAK,IAAI,KAAK,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,CACjD;AAED,MAAM,UAAU,QAAQ,CAAC,EAAkB,EAAE,SAAiB,EAAE,GAAW,EAAE,IAAY,EAAE,MAAqB,EAAE;IACjH,MAAM,MAAM,GAAG,GAAG,CAAA,8BAA8B,MAAM,uBAAuB,SAAS,eAAe,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpH,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAC5F,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAAA,CACjD;AAED,MAAM,UAAU,WAAW,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE,MAAqB,EAAE;IACvG,MAAM,MAAM,GAAG,GAAG,CAAA,8BAA8B,MAAM,uBAAuB,SAAS,eAAe,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpH,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC;AAAA,CAC5F;AAED,MAAM,UAAU,kBAAkB,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE,KAAa,EAAE;IACtG,MAAM,MAAM,GAAG,GAAG,CAAA,wCAAwC,KAAK;uBACzC,SAAS,eAAe,IAAI,gCAAgC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3F,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC;QAAE,OAAO;IACjC,MAAM,OAAO,GAAG,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,YAAY,CAAC,cAAc,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC;IAChF,MAAM,IAAI,YAAY,CAAC,SAAS,EAAE,QAAQ,IAAI,kCAAkC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;AAAA,CAC7G;AAED,MAAM,UAAU,mBAAmB,CAAC,EAAkB,EAAE,SAAiB,EAAE,IAAY,EAAE,KAAa,EAAE;IACvG,GAAG,CAAA;uBACmB,SAAS,eAAe,IAAI,4BAA4B,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC9F;AAED,MAAM,UAAU,gBAAgB,CAC/B,EAAkB,EAClB,SAAiB,EACjB,OAAO,GAA0C,EAAE,EAClD;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC3F,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA,EAAE,CAAC,CAAC,CAAC,GAAG,CAAA,UAAU,OAAO,CAAC,KAAK,EAAE,CAAC;IACjF,OAAO,GAAG,CAAA;;uBAEY,SAAS,GAAG,KAAK;gBACxB,KAAK,EAAE,CAAC,GAAG,CAAc,EAAE,CAAC,CAAC;AAAA,CAC5C;AAED,MAAM,UAAU,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE;IACrE,GAAG,CAAA,6CAA6C,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpE,GAAG,CAAA,wCAAwC,SAAS,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,CAC/D;AAED,SAAS,cAAc,CAAC,EAAkB,EAAE,SAAiB,EAAE,GAAW,EAAE,IAAY,EAAE,MAAqB,EAAE;IAChH,GAAG,CAAA,mEAAmE,SAAS,KAAK,GAAG,KAAK,IAAI,KAAK,MAAM,GAAG,CAAC,GAAG,CACjH,EAAE,CACF,CAAC;AAAA,CACF","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport { sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface LaneRow {\n\tsession_id: string;\n\tlane: string;\n\tleaf_id: string | null;\n\topen_operation_id: string | null;\n}\n\nexport interface LaneMoveRow {\n\tsession_id: string;\n\tseq: number;\n\tlane: string;\n\tleaf_id: string | null;\n}\n\nexport function createInitialLane(db: SqliteDatabase, sessionId: string, lane = \"main\", leafId: string | null = null) {\n\tsql`INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)\n\t\tVALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);\n}\n\nexport function readLanes(db: SqliteDatabase, sessionId: string) {\n\tconst rows = sql`SELECT\n\t\t\tl.session_id,\n\t\t\tl.lane,\n\t\t\tl.leaf_id,\n\t\t\tl.open_operation_id,\n\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t)) AS leaf_exists\n\t\tFROM lanes AS l\n\t\tWHERE l.session_id = ${sessionId}\n\t\tORDER BY l.lane`.all<LaneRow & { leaf_exists: number }>(db);\n\tfor (const row of rows) {\n\t\tif (row.leaf_exists === 0) {\n\t\t\tthrow new SessionError(\"storage\", `Lane ${row.lane} points at missing entry ${row.leaf_id}`);\n\t\t}\n\t}\n\treturn rows.map(({ session_id, lane, leaf_id, open_operation_id }) => ({\n\t\tsession_id,\n\t\tlane,\n\t\tleaf_id,\n\t\topen_operation_id,\n\t}));\n}\n\nexport function readLane(db: SqliteDatabase, sessionId: string, lane: string) {\n\treturn sql`SELECT session_id, lane, leaf_id, open_operation_id\n\t\tFROM lanes\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane}`.get<LaneRow>(db);\n}\n\nexport function readLaneHead(db: SqliteDatabase, sessionId: string, lane: string) {\n\tconst row = sql`SELECT\n\t\t\tl.leaf_id,\n\t\t\t(l.leaf_id IS NULL OR EXISTS (\n\t\t\t\tSELECT 1 FROM entries AS e WHERE e.session_id = l.session_id AND e.id = l.leaf_id\n\t\t\t)) AS leaf_exists\n\t\tFROM lanes AS l\n\t\tWHERE l.session_id = ${sessionId} AND l.lane = ${lane}`.get<{\n\t\tleaf_id: string | null;\n\t\tleaf_exists: number;\n\t}>(db);\n\tif (!row) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tif (row.leaf_exists === 0) throw new SessionError(\"storage\", `Entry ${row.leaf_id} not found`);\n\treturn { leafId: row.leaf_id };\n}\n\nexport function createLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tsql`INSERT INTO lanes (session_id, lane, leaf_id, open_operation_id)\n\t\tVALUES (${sessionId}, ${lane}, ${leafId}, NULL)`.run(db);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function moveLane(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tconst result = sql`UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tappendLaneMove(db, sessionId, seq, lane, leafId);\n}\n\nexport function setLaneLeaf(db: SqliteDatabase, sessionId: string, lane: string, leafId: string | null) {\n\tconst result = sql`UPDATE lanes SET leaf_id = ${leafId} WHERE session_id = ${sessionId} AND lane = ${lane}`.run(db);\n\tif (result.changes !== 1) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n}\n\nexport function startLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tconst result = sql`UPDATE lanes SET open_operation_id = ${runId}\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id IS NULL`.run(db);\n\tif (result.changes === 1) return;\n\tconst current = readLane(db, sessionId, lane);\n\tif (!current) throw new SessionError(\"invalid_lane\", `Lane not found: ${lane}`);\n\tthrow new SessionError(\"storage\", `Lane ${lane} already has an open operation ${current.open_operation_id}`);\n}\n\nexport function finishLaneOperation(db: SqliteDatabase, sessionId: string, lane: string, runId: string) {\n\tsql`UPDATE lanes SET open_operation_id = NULL\n\t\tWHERE session_id = ${sessionId} AND lane = ${lane} AND open_operation_id = ${runId}`.run(db);\n}\n\nexport function readLaneMoveRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\toptions: { afterSeq?: number; limit?: number } = {},\n) {\n\tconst after = options.afterSeq === undefined ? sql`` : sql` AND seq > ${options.afterSeq}`;\n\tconst limit = options.limit === undefined ? sql`` : sql` LIMIT ${options.limit}`;\n\treturn sql`SELECT session_id, seq, lane, leaf_id\n\t\tFROM lane_moves\n\t\tWHERE session_id = ${sessionId}${after}\n\t\tORDER BY seq${limit}`.all<LaneMoveRow>(db);\n}\n\nexport function deleteLaneRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM lane_moves WHERE session_id = ${sessionId}`.run(db);\n\tsql`DELETE FROM lanes WHERE session_id = ${sessionId}`.run(db);\n}\n\nfunction appendLaneMove(db: SqliteDatabase, sessionId: string, seq: number, lane: string, leafId: string | null) {\n\tsql`INSERT INTO lane_moves (session_id, seq, lane, leaf_id) VALUES (${sessionId}, ${seq}, ${lane}, ${leafId})`.run(\n\t\tdb,\n\t);\n}\n"]}
@@ -7,7 +7,7 @@ export interface RecordRow {
7
7
  run_id: string | null;
8
8
  type: string;
9
9
  op_kind: string | null;
10
- timestamp: string;
10
+ timestamp: number;
11
11
  payload: string;
12
12
  }
13
13
  export interface NewRecordRow {
@@ -17,7 +17,7 @@ export interface NewRecordRow {
17
17
  runId?: string;
18
18
  type: string;
19
19
  opKind?: string;
20
- timestamp: string;
20
+ timestamp: number;
21
21
  payload: string;
22
22
  }
23
23
  export declare function appendRecordRow(db: SqliteDatabase, sessionId: string, record: NewRecordRow): void;
@@ -1 +1 @@
1
- {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/records.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,QAgB1F;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,WAIlF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAErE;AAED,wBAAgB,cAAc,CAC7B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE;IACN,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CACV,eAmCN;AAED,wBAAgB,qBAAqB,CACpC,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,SAAS,EAAE,CAqBb","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface RecordRow {\n\tsession_id: string;\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trun_id: string | null;\n\ttype: string;\n\top_kind: string | null;\n\ttimestamp: string;\n\tpayload: string;\n}\n\nexport interface NewRecordRow {\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trunId?: string;\n\ttype: string;\n\topKind?: string;\n\ttimestamp: string;\n\tpayload: string;\n}\n\nexport function appendRecordRow(db: SqliteDatabase, sessionId: string, record: NewRecordRow) {\n\tdb.prepare(\n\t\t`INSERT INTO records\n\t\t\t(session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload)\n\t\t\tVALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t).run(\n\t\tsessionId,\n\t\trecord.seq,\n\t\trecord.id,\n\t\trecord.lane,\n\t\trecord.runId ?? null,\n\t\trecord.type,\n\t\trecord.opKind ?? null,\n\t\trecord.timestamp,\n\t\trecord.payload,\n\t);\n}\n\nexport function idExistsInRecords(db: SqliteDatabase, sessionId: string, id: string) {\n\treturn !!db\n\t\t.prepare(\"SELECT 1 AS found FROM records WHERE session_id = ? AND id = ? LIMIT 1\")\n\t\t.get<{ found: number }>(sessionId, id);\n}\n\nexport function deleteRecordRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM records WHERE session_id = ?\").run(sessionId);\n}\n\nexport function readRecordRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tquery: {\n\t\tlane?: string;\n\t\ttype?: string;\n\t\trunId?: string;\n\t\toperationKind?: string;\n\t\tafterSeq?: number;\n\t\torder?: \"newestFirst\" | \"oldestFirst\";\n\t\tlimit?: number;\n\t} = {},\n) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (query.lane !== undefined) {\n\t\tpredicates.push(\"lane = ?\");\n\t\tparams.push(query.lane);\n\t}\n\tif (query.type !== undefined) {\n\t\tpredicates.push(\"type = ?\");\n\t\tparams.push(query.type);\n\t}\n\tif (query.runId !== undefined) {\n\t\tpredicates.push(\"run_id = ?\");\n\t\tparams.push(query.runId);\n\t}\n\tif (query.operationKind !== undefined) {\n\t\tpredicates.push(\"op_kind = ?\");\n\t\tparams.push(query.operationKind);\n\t}\n\tif (query.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(query.afterSeq);\n\t}\n\tconst limit = query.limit === undefined ? \"\" : \" LIMIT ?\";\n\tif (query.limit !== undefined) params.push(query.limit);\n\tconst direction = query.order === \"oldestFirst\" ? \"ASC\" : \"DESC\";\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\t\tFROM records\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq ${direction}${limit}`,\n\t\t)\n\t\t.all<RecordRow>(...params);\n}\n\nexport function readOpenOperationRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tlane: string,\n\t_options: { limit?: number } = {},\n): RecordRow[] {\n\tconst laneRow = db\n\t\t.prepare(\"SELECT open_operation_id FROM lanes WHERE session_id = ? AND lane = ?\")\n\t\t.get<{ open_operation_id: string | null }>(sessionId, lane);\n\tif (!laneRow?.open_operation_id) return [];\n\n\tconst record = db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\t\tFROM records\n\t\t\tWHERE session_id = ?\n\t\t\t\tAND id = ?`,\n\t\t)\n\t\t.get<RecordRow>(sessionId, laneRow.open_operation_id);\n\tif (!record) {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at missing open operation ${laneRow.open_operation_id}`);\n\t}\n\tif (record.lane !== lane || record.type !== \"operation_started\") {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at invalid open operation ${laneRow.open_operation_id}`);\n\t}\n\treturn [record];\n}\n"]}
1
+ {"version":3,"file":"records.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/records.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,WAAW,SAAS;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,QAM1F;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,WAIlF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAErE;AAED,wBAAgB,cAAc,CAC7B,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,GAAE;IACN,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,aAAa,GAAG,aAAa,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CACV,eAcN;AAED,wBAAgB,qBAAqB,CACpC,EAAE,EAAE,cAAc,EAClB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,SAAS,EAAE,CAiBb","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport { joinSqlFragments, sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface RecordRow {\n\tsession_id: string;\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trun_id: string | null;\n\ttype: string;\n\top_kind: string | null;\n\ttimestamp: number;\n\tpayload: string;\n}\n\nexport interface NewRecordRow {\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trunId?: string;\n\ttype: string;\n\topKind?: string;\n\ttimestamp: number;\n\tpayload: string;\n}\n\nexport function appendRecordRow(db: SqliteDatabase, sessionId: string, record: NewRecordRow) {\n\tsql`INSERT INTO records\n\t\t\t(session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload)\n\t\t\tVALUES (${sessionId}, ${record.seq}, ${record.id}, ${record.lane}, ${record.runId ?? null}, ${record.type}, ${record.opKind ?? null}, ${record.timestamp}, ${record.payload})`.run(\n\t\tdb,\n\t);\n}\n\nexport function idExistsInRecords(db: SqliteDatabase, sessionId: string, id: string) {\n\treturn !!sql`SELECT 1 AS found FROM records WHERE session_id = ${sessionId} AND id = ${id} LIMIT 1`.get<{\n\t\tfound: number;\n\t}>(db);\n}\n\nexport function deleteRecordRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM records WHERE session_id = ${sessionId}`.run(db);\n}\n\nexport function readRecordRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tquery: {\n\t\tlane?: string;\n\t\ttype?: string;\n\t\trunId?: string;\n\t\toperationKind?: string;\n\t\tafterSeq?: number;\n\t\torder?: \"newestFirst\" | \"oldestFirst\";\n\t\tlimit?: number;\n\t} = {},\n) {\n\tconst predicates = [sql`session_id = ${sessionId}`];\n\tif (query.lane !== undefined) predicates.push(sql`lane = ${query.lane}`);\n\tif (query.type !== undefined) predicates.push(sql`type = ${query.type}`);\n\tif (query.runId !== undefined) predicates.push(sql`run_id = ${query.runId}`);\n\tif (query.operationKind !== undefined) predicates.push(sql`op_kind = ${query.operationKind}`);\n\tif (query.afterSeq !== undefined) predicates.push(sql`seq > ${query.afterSeq}`);\n\tconst direction = query.order === \"oldestFirst\" ? sql`ASC` : sql`DESC`;\n\tconst limit = query.limit === undefined ? sql`` : sql` LIMIT ${query.limit}`;\n\treturn sql`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\tFROM records\n\t\tWHERE ${joinSqlFragments(predicates, \" AND \")}\n\t\tORDER BY seq ${direction}${limit}`.all<RecordRow>(db);\n}\n\nexport function readOpenOperationRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tlane: string,\n\t_options: { limit?: number } = {},\n): RecordRow[] {\n\tconst laneRow = sql`SELECT open_operation_id FROM lanes WHERE session_id = ${sessionId} AND lane = ${lane}`.get<{\n\t\topen_operation_id: string | null;\n\t}>(db);\n\tif (!laneRow?.open_operation_id) return [];\n\n\tconst record = sql`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\tFROM records\n\t\tWHERE session_id = ${sessionId}\n\t\t\tAND id = ${laneRow.open_operation_id}`.get<RecordRow>(db);\n\tif (!record) {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at missing open operation ${laneRow.open_operation_id}`);\n\t}\n\tif (record.lane !== lane || record.type !== \"operation_started\") {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at invalid open operation ${laneRow.open_operation_id}`);\n\t}\n\treturn [record];\n}\n"]}
@@ -1,63 +1,43 @@
1
1
  import { SessionError } from "@earendil-works/pi-agent-core";
2
+ import { joinSqlFragments, sql } from "../sql.js";
2
3
  export function appendRecordRow(db, sessionId, record) {
3
- db.prepare(`INSERT INTO records
4
+ sql `INSERT INTO records
4
5
  (session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload)
5
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(sessionId, record.seq, record.id, record.lane, record.runId ?? null, record.type, record.opKind ?? null, record.timestamp, record.payload);
6
+ VALUES (${sessionId}, ${record.seq}, ${record.id}, ${record.lane}, ${record.runId ?? null}, ${record.type}, ${record.opKind ?? null}, ${record.timestamp}, ${record.payload})`.run(db);
6
7
  }
7
8
  export function idExistsInRecords(db, sessionId, id) {
8
- return !!db
9
- .prepare("SELECT 1 AS found FROM records WHERE session_id = ? AND id = ? LIMIT 1")
10
- .get(sessionId, id);
9
+ return !!sql `SELECT 1 AS found FROM records WHERE session_id = ${sessionId} AND id = ${id} LIMIT 1`.get(db);
11
10
  }
12
11
  export function deleteRecordRows(db, sessionId) {
13
- db.prepare("DELETE FROM records WHERE session_id = ?").run(sessionId);
12
+ sql `DELETE FROM records WHERE session_id = ${sessionId}`.run(db);
14
13
  }
15
14
  export function readRecordRows(db, sessionId, query = {}) {
16
- const predicates = ["session_id = ?"];
17
- const params = [sessionId];
18
- if (query.lane !== undefined) {
19
- predicates.push("lane = ?");
20
- params.push(query.lane);
21
- }
22
- if (query.type !== undefined) {
23
- predicates.push("type = ?");
24
- params.push(query.type);
25
- }
26
- if (query.runId !== undefined) {
27
- predicates.push("run_id = ?");
28
- params.push(query.runId);
29
- }
30
- if (query.operationKind !== undefined) {
31
- predicates.push("op_kind = ?");
32
- params.push(query.operationKind);
33
- }
34
- if (query.afterSeq !== undefined) {
35
- predicates.push("seq > ?");
36
- params.push(query.afterSeq);
37
- }
38
- const limit = query.limit === undefined ? "" : " LIMIT ?";
39
- if (query.limit !== undefined)
40
- params.push(query.limit);
41
- const direction = query.order === "oldestFirst" ? "ASC" : "DESC";
42
- return db
43
- .prepare(`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload
44
- FROM records
45
- WHERE ${predicates.join(" AND ")}
46
- ORDER BY seq ${direction}${limit}`)
47
- .all(...params);
15
+ const predicates = [sql `session_id = ${sessionId}`];
16
+ if (query.lane !== undefined)
17
+ predicates.push(sql `lane = ${query.lane}`);
18
+ if (query.type !== undefined)
19
+ predicates.push(sql `type = ${query.type}`);
20
+ if (query.runId !== undefined)
21
+ predicates.push(sql `run_id = ${query.runId}`);
22
+ if (query.operationKind !== undefined)
23
+ predicates.push(sql `op_kind = ${query.operationKind}`);
24
+ if (query.afterSeq !== undefined)
25
+ predicates.push(sql `seq > ${query.afterSeq}`);
26
+ const direction = query.order === "oldestFirst" ? sql `ASC` : sql `DESC`;
27
+ const limit = query.limit === undefined ? sql `` : sql ` LIMIT ${query.limit}`;
28
+ return sql `SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload
29
+ FROM records
30
+ WHERE ${joinSqlFragments(predicates, " AND ")}
31
+ ORDER BY seq ${direction}${limit}`.all(db);
48
32
  }
49
33
  export function readOpenOperationRows(db, sessionId, lane, _options = {}) {
50
- const laneRow = db
51
- .prepare("SELECT open_operation_id FROM lanes WHERE session_id = ? AND lane = ?")
52
- .get(sessionId, lane);
34
+ const laneRow = sql `SELECT open_operation_id FROM lanes WHERE session_id = ${sessionId} AND lane = ${lane}`.get(db);
53
35
  if (!laneRow?.open_operation_id)
54
36
  return [];
55
- const record = db
56
- .prepare(`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload
57
- FROM records
58
- WHERE session_id = ?
59
- AND id = ?`)
60
- .get(sessionId, laneRow.open_operation_id);
37
+ const record = sql `SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload
38
+ FROM records
39
+ WHERE session_id = ${sessionId}
40
+ AND id = ${laneRow.open_operation_id}`.get(db);
61
41
  if (!record) {
62
42
  throw new SessionError("storage", `Lane ${lane} points at missing open operation ${laneRow.open_operation_id}`);
63
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"records.js","sourceRoot":"","sources":["../../../src/sqlite/storage/records.ts"],"names":[],"mappings":"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","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface RecordRow {\n\tsession_id: string;\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trun_id: string | null;\n\ttype: string;\n\top_kind: string | null;\n\ttimestamp: string;\n\tpayload: string;\n}\n\nexport interface NewRecordRow {\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trunId?: string;\n\ttype: string;\n\topKind?: string;\n\ttimestamp: string;\n\tpayload: string;\n}\n\nexport function appendRecordRow(db: SqliteDatabase, sessionId: string, record: NewRecordRow) {\n\tdb.prepare(\n\t\t`INSERT INTO records\n\t\t\t(session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload)\n\t\t\tVALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n\t).run(\n\t\tsessionId,\n\t\trecord.seq,\n\t\trecord.id,\n\t\trecord.lane,\n\t\trecord.runId ?? null,\n\t\trecord.type,\n\t\trecord.opKind ?? null,\n\t\trecord.timestamp,\n\t\trecord.payload,\n\t);\n}\n\nexport function idExistsInRecords(db: SqliteDatabase, sessionId: string, id: string) {\n\treturn !!db\n\t\t.prepare(\"SELECT 1 AS found FROM records WHERE session_id = ? AND id = ? LIMIT 1\")\n\t\t.get<{ found: number }>(sessionId, id);\n}\n\nexport function deleteRecordRows(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM records WHERE session_id = ?\").run(sessionId);\n}\n\nexport function readRecordRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tquery: {\n\t\tlane?: string;\n\t\ttype?: string;\n\t\trunId?: string;\n\t\toperationKind?: string;\n\t\tafterSeq?: number;\n\t\torder?: \"newestFirst\" | \"oldestFirst\";\n\t\tlimit?: number;\n\t} = {},\n) {\n\tconst predicates = [\"session_id = ?\"];\n\tconst params: unknown[] = [sessionId];\n\tif (query.lane !== undefined) {\n\t\tpredicates.push(\"lane = ?\");\n\t\tparams.push(query.lane);\n\t}\n\tif (query.type !== undefined) {\n\t\tpredicates.push(\"type = ?\");\n\t\tparams.push(query.type);\n\t}\n\tif (query.runId !== undefined) {\n\t\tpredicates.push(\"run_id = ?\");\n\t\tparams.push(query.runId);\n\t}\n\tif (query.operationKind !== undefined) {\n\t\tpredicates.push(\"op_kind = ?\");\n\t\tparams.push(query.operationKind);\n\t}\n\tif (query.afterSeq !== undefined) {\n\t\tpredicates.push(\"seq > ?\");\n\t\tparams.push(query.afterSeq);\n\t}\n\tconst limit = query.limit === undefined ? \"\" : \" LIMIT ?\";\n\tif (query.limit !== undefined) params.push(query.limit);\n\tconst direction = query.order === \"oldestFirst\" ? \"ASC\" : \"DESC\";\n\treturn db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\t\tFROM records\n\t\t\tWHERE ${predicates.join(\" AND \")}\n\t\t\tORDER BY seq ${direction}${limit}`,\n\t\t)\n\t\t.all<RecordRow>(...params);\n}\n\nexport function readOpenOperationRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tlane: string,\n\t_options: { limit?: number } = {},\n): RecordRow[] {\n\tconst laneRow = db\n\t\t.prepare(\"SELECT open_operation_id FROM lanes WHERE session_id = ? AND lane = ?\")\n\t\t.get<{ open_operation_id: string | null }>(sessionId, lane);\n\tif (!laneRow?.open_operation_id) return [];\n\n\tconst record = db\n\t\t.prepare(\n\t\t\t`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\t\tFROM records\n\t\t\tWHERE session_id = ?\n\t\t\t\tAND id = ?`,\n\t\t)\n\t\t.get<RecordRow>(sessionId, laneRow.open_operation_id);\n\tif (!record) {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at missing open operation ${laneRow.open_operation_id}`);\n\t}\n\tif (record.lane !== lane || record.type !== \"operation_started\") {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at invalid open operation ${laneRow.open_operation_id}`);\n\t}\n\treturn [record];\n}\n"]}
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../../src/sqlite/storage/records.ts"],"names":[],"mappings":"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","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport { joinSqlFragments, sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport interface RecordRow {\n\tsession_id: string;\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trun_id: string | null;\n\ttype: string;\n\top_kind: string | null;\n\ttimestamp: number;\n\tpayload: string;\n}\n\nexport interface NewRecordRow {\n\tseq: number;\n\tid: string;\n\tlane: string;\n\trunId?: string;\n\ttype: string;\n\topKind?: string;\n\ttimestamp: number;\n\tpayload: string;\n}\n\nexport function appendRecordRow(db: SqliteDatabase, sessionId: string, record: NewRecordRow) {\n\tsql`INSERT INTO records\n\t\t\t(session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload)\n\t\t\tVALUES (${sessionId}, ${record.seq}, ${record.id}, ${record.lane}, ${record.runId ?? null}, ${record.type}, ${record.opKind ?? null}, ${record.timestamp}, ${record.payload})`.run(\n\t\tdb,\n\t);\n}\n\nexport function idExistsInRecords(db: SqliteDatabase, sessionId: string, id: string) {\n\treturn !!sql`SELECT 1 AS found FROM records WHERE session_id = ${sessionId} AND id = ${id} LIMIT 1`.get<{\n\t\tfound: number;\n\t}>(db);\n}\n\nexport function deleteRecordRows(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM records WHERE session_id = ${sessionId}`.run(db);\n}\n\nexport function readRecordRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tquery: {\n\t\tlane?: string;\n\t\ttype?: string;\n\t\trunId?: string;\n\t\toperationKind?: string;\n\t\tafterSeq?: number;\n\t\torder?: \"newestFirst\" | \"oldestFirst\";\n\t\tlimit?: number;\n\t} = {},\n) {\n\tconst predicates = [sql`session_id = ${sessionId}`];\n\tif (query.lane !== undefined) predicates.push(sql`lane = ${query.lane}`);\n\tif (query.type !== undefined) predicates.push(sql`type = ${query.type}`);\n\tif (query.runId !== undefined) predicates.push(sql`run_id = ${query.runId}`);\n\tif (query.operationKind !== undefined) predicates.push(sql`op_kind = ${query.operationKind}`);\n\tif (query.afterSeq !== undefined) predicates.push(sql`seq > ${query.afterSeq}`);\n\tconst direction = query.order === \"oldestFirst\" ? sql`ASC` : sql`DESC`;\n\tconst limit = query.limit === undefined ? sql`` : sql` LIMIT ${query.limit}`;\n\treturn sql`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\tFROM records\n\t\tWHERE ${joinSqlFragments(predicates, \" AND \")}\n\t\tORDER BY seq ${direction}${limit}`.all<RecordRow>(db);\n}\n\nexport function readOpenOperationRows(\n\tdb: SqliteDatabase,\n\tsessionId: string,\n\tlane: string,\n\t_options: { limit?: number } = {},\n): RecordRow[] {\n\tconst laneRow = sql`SELECT open_operation_id FROM lanes WHERE session_id = ${sessionId} AND lane = ${lane}`.get<{\n\t\topen_operation_id: string | null;\n\t}>(db);\n\tif (!laneRow?.open_operation_id) return [];\n\n\tconst record = sql`SELECT session_id, seq, id, lane, run_id, type, op_kind, timestamp, payload\n\t\tFROM records\n\t\tWHERE session_id = ${sessionId}\n\t\t\tAND id = ${laneRow.open_operation_id}`.get<RecordRow>(db);\n\tif (!record) {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at missing open operation ${laneRow.open_operation_id}`);\n\t}\n\tif (record.lane !== lane || record.type !== \"operation_started\") {\n\t\tthrow new SessionError(\"storage\", `Lane ${lane} points at invalid open operation ${laneRow.open_operation_id}`);\n\t}\n\treturn [record];\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-sequences.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/session-sequences.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,SAAI,QAEhF;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAQpE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAErF;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAEjF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAEnE","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport function createSequence(db: SqliteDatabase, sessionId: string, nextSeq = 1) {\n\tdb.prepare(\"INSERT INTO session_sequences (session_id, next_seq) VALUES (?, ?)\").run(sessionId, nextSeq);\n}\n\nexport function getNextSequence(db: SqliteDatabase, sessionId: string) {\n\tconst sequenceRow = db\n\t\t.prepare(\"SELECT next_seq FROM session_sequences WHERE session_id = ?\")\n\t\t.get<{ next_seq: number }>(sessionId);\n\tif (!sequenceRow) {\n\t\tthrow new SessionError(\"storage\", `Missing sequence row for session ${sessionId}`);\n\t}\n\treturn sequenceRow.next_seq;\n}\n\nexport function setNextSequence(db: SqliteDatabase, sessionId: string, nextSeq: number) {\n\tdb.prepare(\"UPDATE session_sequences SET next_seq = ? WHERE session_id = ?\").run(nextSeq, sessionId);\n}\n\nexport function advanceSequence(db: SqliteDatabase, sessionId: string, seq: number) {\n\tsetNextSequence(db, sessionId, seq + 1);\n}\n\nexport function deleteSequence(db: SqliteDatabase, sessionId: string) {\n\tdb.prepare(\"DELETE FROM session_sequences WHERE session_id = ?\").run(sessionId);\n}\n"]}
1
+ {"version":3,"file":"session-sequences.d.ts","sourceRoot":"","sources":["../../../src/sqlite/storage/session-sequences.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,SAAI,QAEhF;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,UAQpE;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAErF;AAED,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAEjF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,QAEnE","sourcesContent":["import { SessionError } from \"@earendil-works/pi-agent-core\";\nimport { sql } from \"../sql.ts\";\nimport type { SqliteDatabase } from \"../types.ts\";\n\nexport function createSequence(db: SqliteDatabase, sessionId: string, nextSeq = 1) {\n\tsql`INSERT INTO session_sequences (session_id, next_seq) VALUES (${sessionId}, ${nextSeq})`.run(db);\n}\n\nexport function getNextSequence(db: SqliteDatabase, sessionId: string) {\n\tconst sequenceRow = sql`SELECT next_seq FROM session_sequences WHERE session_id = ${sessionId}`.get<{\n\t\tnext_seq: number;\n\t}>(db);\n\tif (!sequenceRow) {\n\t\tthrow new SessionError(\"storage\", `Missing sequence row for session ${sessionId}`);\n\t}\n\treturn sequenceRow.next_seq;\n}\n\nexport function setNextSequence(db: SqliteDatabase, sessionId: string, nextSeq: number) {\n\tsql`UPDATE session_sequences SET next_seq = ${nextSeq} WHERE session_id = ${sessionId}`.run(db);\n}\n\nexport function advanceSequence(db: SqliteDatabase, sessionId: string, seq: number) {\n\tsetNextSequence(db, sessionId, seq + 1);\n}\n\nexport function deleteSequence(db: SqliteDatabase, sessionId: string) {\n\tsql`DELETE FROM session_sequences WHERE session_id = ${sessionId}`.run(db);\n}\n"]}
@@ -1,23 +1,22 @@
1
1
  import { SessionError } from "@earendil-works/pi-agent-core";
2
+ import { sql } from "../sql.js";
2
3
  export function createSequence(db, sessionId, nextSeq = 1) {
3
- db.prepare("INSERT INTO session_sequences (session_id, next_seq) VALUES (?, ?)").run(sessionId, nextSeq);
4
+ sql `INSERT INTO session_sequences (session_id, next_seq) VALUES (${sessionId}, ${nextSeq})`.run(db);
4
5
  }
5
6
  export function getNextSequence(db, sessionId) {
6
- const sequenceRow = db
7
- .prepare("SELECT next_seq FROM session_sequences WHERE session_id = ?")
8
- .get(sessionId);
7
+ const sequenceRow = sql `SELECT next_seq FROM session_sequences WHERE session_id = ${sessionId}`.get(db);
9
8
  if (!sequenceRow) {
10
9
  throw new SessionError("storage", `Missing sequence row for session ${sessionId}`);
11
10
  }
12
11
  return sequenceRow.next_seq;
13
12
  }
14
13
  export function setNextSequence(db, sessionId, nextSeq) {
15
- db.prepare("UPDATE session_sequences SET next_seq = ? WHERE session_id = ?").run(nextSeq, sessionId);
14
+ sql `UPDATE session_sequences SET next_seq = ${nextSeq} WHERE session_id = ${sessionId}`.run(db);
16
15
  }
17
16
  export function advanceSequence(db, sessionId, seq) {
18
17
  setNextSequence(db, sessionId, seq + 1);
19
18
  }
20
19
  export function deleteSequence(db, sessionId) {
21
- db.prepare("DELETE FROM session_sequences WHERE session_id = ?").run(sessionId);
20
+ sql `DELETE FROM session_sequences WHERE session_id = ${sessionId}`.run(db);
22
21
  }
23
22
  //# sourceMappingURL=session-sequences.js.map