@hatk/hatk 0.0.1-alpha.9 → 0.0.1-alpha.92

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 (218) hide show
  1. package/dist/adapter.d.ts +19 -0
  2. package/dist/adapter.d.ts.map +1 -0
  3. package/dist/adapter.js +113 -0
  4. package/dist/backfill.d.ts +29 -2
  5. package/dist/backfill.d.ts.map +1 -1
  6. package/dist/backfill.js +142 -51
  7. package/dist/car.d.ts +20 -0
  8. package/dist/car.d.ts.map +1 -1
  9. package/dist/car.js +108 -0
  10. package/dist/cli.js +247 -1043
  11. package/dist/config.d.ts +145 -1
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +61 -8
  14. package/dist/database/adapter-factory.d.ts +6 -0
  15. package/dist/database/adapter-factory.d.ts.map +1 -0
  16. package/dist/database/adapter-factory.js +20 -0
  17. package/dist/database/adapters/duckdb-search.d.ts +12 -0
  18. package/dist/database/adapters/duckdb-search.d.ts.map +1 -0
  19. package/dist/database/adapters/duckdb-search.js +27 -0
  20. package/dist/database/adapters/duckdb.d.ts +25 -0
  21. package/dist/database/adapters/duckdb.d.ts.map +1 -0
  22. package/dist/database/adapters/duckdb.js +161 -0
  23. package/dist/database/adapters/sqlite-search.d.ts +16 -0
  24. package/dist/database/adapters/sqlite-search.d.ts.map +1 -0
  25. package/dist/database/adapters/sqlite-search.js +76 -0
  26. package/dist/database/adapters/sqlite.d.ts +18 -0
  27. package/dist/database/adapters/sqlite.d.ts.map +1 -0
  28. package/dist/database/adapters/sqlite.js +88 -0
  29. package/dist/{db.d.ts → database/db.d.ts} +68 -6
  30. package/dist/database/db.d.ts.map +1 -0
  31. package/dist/database/db.js +1775 -0
  32. package/dist/database/dialect.d.ts +45 -0
  33. package/dist/database/dialect.d.ts.map +1 -0
  34. package/dist/database/dialect.js +72 -0
  35. package/dist/{fts.d.ts → database/fts.d.ts} +7 -0
  36. package/dist/database/fts.d.ts.map +1 -0
  37. package/dist/{fts.js → database/fts.js} +122 -34
  38. package/dist/database/index.d.ts +7 -0
  39. package/dist/database/index.d.ts.map +1 -0
  40. package/dist/database/index.js +6 -0
  41. package/dist/database/ports.d.ts +50 -0
  42. package/dist/database/ports.d.ts.map +1 -0
  43. package/dist/database/ports.js +1 -0
  44. package/dist/{schema.d.ts → database/schema.d.ts} +16 -3
  45. package/dist/database/schema.d.ts.map +1 -0
  46. package/dist/{schema.js → database/schema.js} +126 -44
  47. package/dist/dev-entry.d.ts +8 -0
  48. package/dist/dev-entry.d.ts.map +1 -0
  49. package/dist/dev-entry.js +127 -0
  50. package/dist/feeds.d.ts +26 -8
  51. package/dist/feeds.d.ts.map +1 -1
  52. package/dist/feeds.js +72 -16
  53. package/dist/hooks.d.ts +102 -0
  54. package/dist/hooks.d.ts.map +1 -0
  55. package/dist/hooks.js +186 -0
  56. package/dist/hydrate.d.ts +49 -6
  57. package/dist/hydrate.d.ts.map +1 -1
  58. package/dist/hydrate.js +21 -20
  59. package/dist/indexer.d.ts +167 -3
  60. package/dist/indexer.d.ts.map +1 -1
  61. package/dist/indexer.js +556 -94
  62. package/dist/jetstream.d.ts +118 -0
  63. package/dist/jetstream.d.ts.map +1 -0
  64. package/dist/jetstream.js +225 -0
  65. package/dist/labels.d.ts +36 -0
  66. package/dist/labels.d.ts.map +1 -1
  67. package/dist/labels.js +71 -6
  68. package/dist/lex-types.d.ts +2 -0
  69. package/dist/lex-types.d.ts.map +1 -1
  70. package/dist/lexicon-resolve.d.ts.map +1 -1
  71. package/dist/lexicon-resolve.js +27 -112
  72. package/dist/lexicons/com/atproto/label/defs.json +75 -0
  73. package/dist/lexicons/com/atproto/moderation/defs.json +30 -0
  74. package/dist/lexicons/com/atproto/repo/strongRef.json +21 -0
  75. package/dist/lexicons/dev/hatk/applyWrites.json +87 -0
  76. package/dist/lexicons/dev/hatk/createRecord.json +40 -0
  77. package/dist/lexicons/dev/hatk/createReport.json +48 -0
  78. package/dist/lexicons/dev/hatk/deleteRecord.json +25 -0
  79. package/dist/lexicons/dev/hatk/describeCollections.json +41 -0
  80. package/dist/lexicons/dev/hatk/describeFeeds.json +29 -0
  81. package/dist/lexicons/dev/hatk/describeLabels.json +45 -0
  82. package/dist/lexicons/dev/hatk/getFeed.json +30 -0
  83. package/dist/lexicons/dev/hatk/getPreferences.json +19 -0
  84. package/dist/lexicons/dev/hatk/getRecord.json +26 -0
  85. package/dist/lexicons/dev/hatk/getRecords.json +32 -0
  86. package/dist/lexicons/dev/hatk/putPreference.json +28 -0
  87. package/dist/lexicons/dev/hatk/putRecord.json +41 -0
  88. package/dist/lexicons/dev/hatk/searchRecords.json +32 -0
  89. package/dist/lexicons/dev/hatk/uploadBlob.json +23 -0
  90. package/dist/logger.d.ts +29 -0
  91. package/dist/logger.d.ts.map +1 -1
  92. package/dist/logger.js +29 -0
  93. package/dist/main.js +198 -75
  94. package/dist/mst.d.ts +15 -0
  95. package/dist/mst.d.ts.map +1 -1
  96. package/dist/mst.js +13 -0
  97. package/dist/oauth/db.d.ts +16 -1
  98. package/dist/oauth/db.d.ts.map +1 -1
  99. package/dist/oauth/db.js +74 -19
  100. package/dist/oauth/discovery.d.ts +10 -0
  101. package/dist/oauth/discovery.d.ts.map +1 -1
  102. package/dist/oauth/discovery.js +54 -2
  103. package/dist/oauth/server.d.ts +93 -1
  104. package/dist/oauth/server.d.ts.map +1 -1
  105. package/dist/oauth/server.js +416 -39
  106. package/dist/oauth/service-describe.d.ts +42 -0
  107. package/dist/oauth/service-describe.d.ts.map +1 -0
  108. package/dist/oauth/service-describe.js +108 -0
  109. package/dist/oauth/session.d.ts +32 -0
  110. package/dist/oauth/session.d.ts.map +1 -0
  111. package/dist/oauth/session.js +131 -0
  112. package/dist/opengraph.d.ts +10 -0
  113. package/dist/opengraph.d.ts.map +1 -1
  114. package/dist/opengraph.js +94 -42
  115. package/dist/pds-proxy.d.ts +82 -0
  116. package/dist/pds-proxy.d.ts.map +1 -0
  117. package/dist/pds-proxy.js +356 -0
  118. package/dist/private-collections.d.ts +13 -0
  119. package/dist/private-collections.d.ts.map +1 -0
  120. package/dist/private-collections.js +27 -0
  121. package/dist/push.d.ts +54 -0
  122. package/dist/push.d.ts.map +1 -0
  123. package/dist/push.js +367 -0
  124. package/dist/renderer.d.ts +27 -0
  125. package/dist/renderer.d.ts.map +1 -0
  126. package/dist/renderer.js +46 -0
  127. package/dist/resolve-hatk.d.ts +6 -0
  128. package/dist/resolve-hatk.d.ts.map +1 -0
  129. package/dist/resolve-hatk.js +20 -0
  130. package/dist/response.d.ts +16 -0
  131. package/dist/response.d.ts.map +1 -0
  132. package/dist/response.js +69 -0
  133. package/dist/scanner.d.ts +21 -0
  134. package/dist/scanner.d.ts.map +1 -0
  135. package/dist/scanner.js +88 -0
  136. package/dist/seed.d.ts +19 -0
  137. package/dist/seed.d.ts.map +1 -1
  138. package/dist/seed.js +43 -4
  139. package/dist/server-init.d.ts +8 -0
  140. package/dist/server-init.d.ts.map +1 -0
  141. package/dist/server-init.js +62 -0
  142. package/dist/server.d.ts +34 -3
  143. package/dist/server.d.ts.map +1 -1
  144. package/dist/server.js +1032 -649
  145. package/dist/setup.d.ts +28 -1
  146. package/dist/setup.d.ts.map +1 -1
  147. package/dist/setup.js +50 -3
  148. package/dist/spaces/blob.d.ts +51 -0
  149. package/dist/spaces/blob.d.ts.map +1 -0
  150. package/dist/spaces/blob.js +111 -0
  151. package/dist/spaces/credential.d.ts +62 -0
  152. package/dist/spaces/credential.d.ts.map +1 -0
  153. package/dist/spaces/credential.js +184 -0
  154. package/dist/spaces/engine.d.ts +97 -0
  155. package/dist/spaces/engine.d.ts.map +1 -0
  156. package/dist/spaces/engine.js +559 -0
  157. package/dist/spaces/guard.d.ts +41 -0
  158. package/dist/spaces/guard.d.ts.map +1 -0
  159. package/dist/spaces/guard.js +79 -0
  160. package/dist/spaces/identity.d.ts +37 -0
  161. package/dist/spaces/identity.d.ts.map +1 -0
  162. package/dist/spaces/identity.js +88 -0
  163. package/dist/spaces/index.d.ts +55 -0
  164. package/dist/spaces/index.d.ts.map +1 -0
  165. package/dist/spaces/index.js +133 -0
  166. package/dist/spaces/notify.d.ts +51 -0
  167. package/dist/spaces/notify.d.ts.map +1 -0
  168. package/dist/spaces/notify.js +121 -0
  169. package/dist/spaces/records.d.ts +37 -0
  170. package/dist/spaces/records.d.ts.map +1 -0
  171. package/dist/spaces/records.js +63 -0
  172. package/dist/spaces/store.d.ts +51 -0
  173. package/dist/spaces/store.d.ts.map +1 -0
  174. package/dist/spaces/store.js +99 -0
  175. package/dist/spaces/uri.d.ts +60 -0
  176. package/dist/spaces/uri.d.ts.map +1 -0
  177. package/dist/spaces/uri.js +97 -0
  178. package/dist/spaces/verify.d.ts +39 -0
  179. package/dist/spaces/verify.d.ts.map +1 -0
  180. package/dist/spaces/verify.js +87 -0
  181. package/dist/spaces/viewer.d.ts +51 -0
  182. package/dist/spaces/viewer.d.ts.map +1 -0
  183. package/dist/spaces/viewer.js +167 -0
  184. package/dist/spaces/visibility.d.ts +57 -0
  185. package/dist/spaces/visibility.d.ts.map +1 -0
  186. package/dist/spaces/visibility.js +81 -0
  187. package/dist/templates/feed.tpl +18 -0
  188. package/dist/templates/hook.tpl +5 -0
  189. package/dist/templates/label.tpl +15 -0
  190. package/dist/templates/og.tpl +17 -0
  191. package/dist/templates/seed.tpl +11 -0
  192. package/dist/templates/setup.tpl +5 -0
  193. package/dist/templates/test-feed.tpl +19 -0
  194. package/dist/templates/test-xrpc.tpl +19 -0
  195. package/dist/templates/xrpc.tpl +53 -0
  196. package/dist/test.d.ts +3 -1
  197. package/dist/test.d.ts.map +1 -1
  198. package/dist/test.js +60 -36
  199. package/dist/views.js +1 -1
  200. package/dist/vite-plugin.d.ts +1 -1
  201. package/dist/vite-plugin.d.ts.map +1 -1
  202. package/dist/vite-plugin.js +254 -66
  203. package/dist/xrpc.d.ts +101 -12
  204. package/dist/xrpc.d.ts.map +1 -1
  205. package/dist/xrpc.js +255 -55
  206. package/package.json +21 -9
  207. package/public/admin-auth.js +271 -306
  208. package/public/admin.html +177 -61
  209. package/dist/db.d.ts.map +0 -1
  210. package/dist/db.js +0 -1361
  211. package/dist/fts.d.ts.map +0 -1
  212. package/dist/oauth/hooks.d.ts +0 -10
  213. package/dist/oauth/hooks.d.ts.map +0 -1
  214. package/dist/oauth/hooks.js +0 -40
  215. package/dist/schema.d.ts.map +0 -1
  216. package/dist/test-browser.d.ts +0 -14
  217. package/dist/test-browser.d.ts.map +0 -1
  218. package/dist/test-browser.js +0 -26
@@ -0,0 +1,45 @@
1
+ import type { Dialect } from './ports.ts';
2
+ export interface SqlDialect {
3
+ /** Map from lexicon type key to SQL column type */
4
+ typeMap: Record<string, string>;
5
+ /** Timestamp type name */
6
+ timestampType: string;
7
+ /** JSON type name */
8
+ jsonType: string;
9
+ /** Parameter placeholder for index (1-based). DuckDB/Postgres: $1 SQLite: ? */
10
+ param(index: number): string;
11
+ /** Whether the engine supports native bulk appenders (DuckDB) vs batched INSERT */
12
+ supportsAppender: boolean;
13
+ /** SQL for upsert — 'INSERT OR REPLACE' (DuckDB/SQLite) vs 'ON CONFLICT DO UPDATE' */
14
+ upsertPrefix: string;
15
+ /** Extract a string value from a JSON column. Returns SQL expression. */
16
+ jsonExtractString(column: string, path: string): string;
17
+ /** Aggregate strings from a JSON array. Returns SQL expression. */
18
+ jsonArrayStringAgg(column: string, jsonPath: string): string;
19
+ /** Information schema query to list user tables */
20
+ listTablesQuery: string;
21
+ /** CHECKPOINT or equivalent (for WAL compaction). null if not needed. */
22
+ checkpointSQL: string | null;
23
+ /** Current timestamp expression */
24
+ currentTimestamp: string;
25
+ /** ILIKE or equivalent for case-insensitive matching */
26
+ ilike: string;
27
+ /** Cast expression for safe timestamp parsing. DuckDB: TRY_CAST(x AS TIMESTAMP), SQLite: x */
28
+ tryCastTimestamp(expr: string): string;
29
+ /** COUNT(*)::INTEGER or equivalent */
30
+ countAsInteger: string;
31
+ /** GREATEST(...) or MAX(...) for multi-arg max */
32
+ greatest(exprs: string[]): string;
33
+ /** jaro_winkler_similarity or null if unsupported */
34
+ jaroWinklerSimilarity: string | null;
35
+ /** string_agg or group_concat */
36
+ stringAgg(column: string, separator: string): string;
37
+ /** CREATE SEQUENCE support */
38
+ supportsSequences: boolean;
39
+ /** SQL to get columns for a table. Returns rows with column_name/name and data_type/type. */
40
+ introspectColumnsQuery(tableName: string): string;
41
+ }
42
+ export declare const DUCKDB_DIALECT: SqlDialect;
43
+ export declare const SQLITE_DIALECT: SqlDialect;
44
+ export declare function getDialect(dialect: Dialect): SqlDialect;
45
+ //# sourceMappingURL=dialect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialect.d.ts","sourceRoot":"","sources":["../../src/database/dialect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAEzC,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/B,0BAA0B;IAC1B,aAAa,EAAE,MAAM,CAAA;IAErB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,CAAA;IAEhB,gFAAgF;IAChF,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAE5B,mFAAmF;IACnF,gBAAgB,EAAE,OAAO,CAAA;IAEzB,sFAAsF;IACtF,YAAY,EAAE,MAAM,CAAA;IAEpB,yEAAyE;IACzE,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAEvD,mEAAmE;IACnE,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IAE5D,mDAAmD;IACnD,eAAe,EAAE,MAAM,CAAA;IAEvB,yEAAyE;IACzE,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAE5B,mCAAmC;IACnC,gBAAgB,EAAE,MAAM,CAAA;IAExB,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IAEb,8FAA8F;IAC9F,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAEtC,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAA;IAEtB,kDAAkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAA;IAEjC,qDAAqD;IACrD,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAA;IAEpC,iCAAiC;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;IAEpD,8BAA8B;IAC9B,iBAAiB,EAAE,OAAO,CAAA;IAE1B,6FAA6F;IAC7F,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;CAClD;AAED,eAAO,MAAM,cAAc,EAAE,UA8B5B,CAAA;AAED,eAAO,MAAM,cAAc,EAAE,UA+B5B,CAAA;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CASvD"}
@@ -0,0 +1,72 @@
1
+ export const DUCKDB_DIALECT = {
2
+ typeMap: {
3
+ text: 'TEXT',
4
+ integer: 'INTEGER',
5
+ bigint: 'BIGINT',
6
+ boolean: 'BOOLEAN',
7
+ blob: 'BLOB',
8
+ timestamp: 'TIMESTAMP',
9
+ timestamptz: 'TIMESTAMPTZ',
10
+ json: 'JSON',
11
+ },
12
+ timestampType: 'TIMESTAMP',
13
+ jsonType: 'JSON',
14
+ param: (i) => `$${i}`,
15
+ supportsAppender: true,
16
+ upsertPrefix: 'INSERT OR REPLACE INTO',
17
+ jsonExtractString: (col, path) => `json_extract_string(${col}, '${path}')`,
18
+ jsonArrayStringAgg: (col, path) => `list_string_agg(json_extract_string(${col}, '${path}'))`,
19
+ listTablesQuery: `SELECT table_name FROM information_schema.tables WHERE table_schema = 'main' AND table_name NOT LIKE '\\_%' ESCAPE '\\'`,
20
+ checkpointSQL: 'CHECKPOINT',
21
+ currentTimestamp: 'CURRENT_TIMESTAMP',
22
+ ilike: 'ILIKE',
23
+ tryCastTimestamp: (expr) => `TRY_CAST(${expr} AS TIMESTAMP)`,
24
+ countAsInteger: 'COUNT(*)::INTEGER',
25
+ greatest: (exprs) => `GREATEST(${exprs.join(', ')})`,
26
+ jaroWinklerSimilarity: 'jaro_winkler_similarity',
27
+ stringAgg: (col, sep) => `string_agg(${col}, ${sep})`,
28
+ supportsSequences: true,
29
+ introspectColumnsQuery: (tableName) => `SELECT column_name, data_type FROM information_schema.columns WHERE table_name = '${tableName}'`,
30
+ };
31
+ export const SQLITE_DIALECT = {
32
+ typeMap: {
33
+ text: 'TEXT',
34
+ integer: 'INTEGER',
35
+ bigint: 'INTEGER',
36
+ boolean: 'INTEGER',
37
+ blob: 'BLOB',
38
+ timestamp: 'TEXT',
39
+ timestamptz: 'TEXT',
40
+ json: 'TEXT',
41
+ },
42
+ timestampType: 'TEXT',
43
+ jsonType: 'TEXT',
44
+ param: (_i) => '?',
45
+ supportsAppender: false,
46
+ upsertPrefix: 'INSERT OR REPLACE INTO',
47
+ jsonExtractString: (col, path) => `json_extract(${col}, '${path}')`,
48
+ jsonArrayStringAgg: (col, path) => {
49
+ return `(SELECT group_concat(je.value, ' ') FROM json_each(${col}, '${path}') je)`;
50
+ },
51
+ listTablesQuery: `SELECT name AS table_name FROM sqlite_master WHERE type='table' AND name NOT LIKE '\\_%' ESCAPE '\\'`,
52
+ checkpointSQL: null,
53
+ currentTimestamp: 'CURRENT_TIMESTAMP',
54
+ ilike: 'LIKE',
55
+ tryCastTimestamp: (expr) => expr,
56
+ countAsInteger: 'CAST(COUNT(*) AS INTEGER)',
57
+ greatest: (exprs) => `MAX(${exprs.join(', ')})`,
58
+ jaroWinklerSimilarity: null,
59
+ stringAgg: (col, sep) => `group_concat(${col}, ${sep})`,
60
+ supportsSequences: false,
61
+ introspectColumnsQuery: (tableName) => `PRAGMA table_info("${tableName}")`,
62
+ };
63
+ export function getDialect(dialect) {
64
+ switch (dialect) {
65
+ case 'duckdb':
66
+ return DUCKDB_DIALECT;
67
+ case 'sqlite':
68
+ return SQLITE_DIALECT;
69
+ case 'postgres':
70
+ throw new Error('PostgreSQL adapter not yet implemented');
71
+ }
72
+ }
@@ -1,3 +1,7 @@
1
+ import type { SearchPort } from './ports.ts';
2
+ export declare function setSearchPort(port: SearchPort | null): void;
3
+ export declare function hasSearchPort(): boolean;
4
+ export declare function getSearchPort(): SearchPort | null;
1
5
  export declare function getSearchColumns(collection: string): string[];
2
6
  export declare function getLastRebuiltAt(collection: string): string | null;
3
7
  /**
@@ -11,6 +15,9 @@ export declare function ftsTableName(collection: string): string;
11
15
  * using Porter stemmer with English stopwords.
12
16
  */
13
17
  export declare function buildFtsIndex(collection: string): Promise<void>;
18
+ export declare function buildFtsRow(collection: string, uri: string): Promise<Record<string, string | null> | null>;
19
+ export declare function updateFtsRecord(collection: string, uri: string): Promise<void>;
20
+ export declare function deleteFtsRecord(collection: string, uri: string): Promise<void>;
14
21
  /**
15
22
  * Strip English stop words from a search query, preserving non-stop-word terms.
16
23
  * Returns the cleaned query string. If all words are stop words, returns the original query.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fts.d.ts","sourceRoot":"","sources":["../../src/database/fts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAuE5C,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAE3D;AAED,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAWD,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7D;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEvD;AAqFD;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrE;AAED,wBAAsB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAehH;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAepF;AAED,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAYpF;AAokBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B5E"}
@@ -1,6 +1,6 @@
1
- import { getSchema, runSQL } from "./db.js";
2
- import { getLexicon } from "./schema.js";
3
- import { emit, timer } from "./logger.js";
1
+ import { getSchema, runSQL, getSqlDialect, querySQL } from "./db.js";
2
+ import { getLexicon, q } from "./schema.js";
3
+ import { emit, timer } from "../logger.js";
4
4
  /**
5
5
  * Resolve a lexicon ref like "#artist" to its definition.
6
6
  * Only handles local refs (same lexicon).
@@ -15,7 +15,7 @@ function resolveRef(ref, lexicon) {
15
15
  * Given a JSON column and its lexicon property definition, produce
16
16
  * search column expressions that extract searchable text.
17
17
  */
18
- function jsonSearchColumns(colName, prop, lexicon) {
18
+ function jsonSearchColumns(colName, prop, lexicon, dialect) {
19
19
  const columns = [];
20
20
  // Strip table qualifier (e.g. "t.artists" → "artists") for use in aliases
21
21
  const aliasBase = colName.includes('.') ? colName.split('.').pop() : colName;
@@ -26,7 +26,7 @@ function jsonSearchColumns(colName, prop, lexicon) {
26
26
  if (itemDef.type === 'string') {
27
27
  // array of strings — join into one text column
28
28
  columns.push({
29
- expr: `list_string_agg(json_extract_string(${colName}, '$[*]'))`,
29
+ expr: dialect.jsonArrayStringAgg(colName, '$[*]'),
30
30
  alias: `${aliasBase}_text`,
31
31
  });
32
32
  }
@@ -35,7 +35,7 @@ function jsonSearchColumns(colName, prop, lexicon) {
35
35
  for (const [field, fieldProp] of Object.entries(itemDef.properties)) {
36
36
  if (fieldProp.type === 'string') {
37
37
  columns.push({
38
- expr: `list_string_agg(json_extract_string(${colName}, '$[*].${field}'))`,
38
+ expr: dialect.jsonArrayStringAgg(colName, `$[*].${field}`),
39
39
  alias: `${aliasBase}_${field}`,
40
40
  });
41
41
  }
@@ -47,7 +47,7 @@ function jsonSearchColumns(colName, prop, lexicon) {
47
47
  for (const [field, fieldProp] of Object.entries(prop.properties)) {
48
48
  if (fieldProp.type === 'string') {
49
49
  columns.push({
50
- expr: `json_extract_string(${colName}, '$.${field}')`,
50
+ expr: dialect.jsonExtractString(colName, `$.${field}`),
51
51
  alias: `${aliasBase}_${field}`,
52
52
  });
53
53
  }
@@ -56,10 +56,22 @@ function jsonSearchColumns(colName, prop, lexicon) {
56
56
  // blob, union, unknown — skip (no useful text to extract)
57
57
  return columns;
58
58
  }
59
+ let searchPort = null;
60
+ export function setSearchPort(port) {
61
+ searchPort = port;
62
+ }
63
+ export function hasSearchPort() {
64
+ return searchPort !== null;
65
+ }
66
+ export function getSearchPort() {
67
+ return searchPort;
68
+ }
59
69
  // Tracks when each collection's FTS index was last rebuilt
60
70
  const lastRebuiltAt = new Map();
61
71
  // Cache of search column metadata per collection, populated during buildFtsIndex
62
72
  const searchColumnCache = new Map();
73
+ // Cache of computed FTS schemas per collection (deterministic, so compute once)
74
+ const ftsSchemaCache = new Map();
63
75
  export function getSearchColumns(collection) {
64
76
  return searchColumnCache.get(collection) || [];
65
77
  }
@@ -74,30 +86,36 @@ export function ftsTableName(collection) {
74
86
  return '_fts_' + collection.replace(/\./g, '_');
75
87
  }
76
88
  /**
77
- * Build FTS index for a collection.
78
- * Creates a shadow table copy and indexes all TEXT NOT NULL columns
79
- * using Porter stemmer with English stopwords.
89
+ * Compute the FTS schema for a collection: search column names, source query, and safe table name.
80
90
  */
81
- export async function buildFtsIndex(collection) {
91
+ function computeFtsSchema(collection) {
92
+ const cached = ftsSchemaCache.get(collection);
93
+ if (cached)
94
+ return cached;
82
95
  const schema = getSchema(collection);
83
96
  if (!schema)
84
97
  throw new Error(`Unknown collection: ${collection}`);
85
98
  const lexicon = getLexicon(collection);
86
99
  const record = lexicon?.defs?.main?.record;
87
100
  // Build column list for shadow table
101
+ const dialect = getSqlDialect();
88
102
  const selectExprs = ['t.uri', 't.cid', 't.did', 't.indexed_at'];
89
103
  const searchColNames = [];
90
104
  for (const col of schema.columns) {
91
- if (col.duckdbType === 'TEXT') {
92
- selectExprs.push(`t.${col.name}`);
105
+ // A blob column holds {ref, mimeType, size} metadata — no searchable text.
106
+ // This has to be decided on isJson, not on sqlType: SQLite's jsonType is
107
+ // TEXT, so a blob column would otherwise fall into the plain-TEXT branch
108
+ // below and be indexed as raw JSON.
109
+ if (col.isJson && record?.properties?.[col.originalName]?.type === 'blob')
110
+ continue;
111
+ if (col.sqlType === 'TEXT') {
112
+ selectExprs.push(`t.${q(col.name)}`);
93
113
  searchColNames.push(col.name);
94
114
  }
95
- else if (col.duckdbType === 'JSON' && record?.properties) {
115
+ else if (col.isJson && record?.properties) {
96
116
  const prop = record.properties[col.originalName];
97
- if (prop?.type === 'blob')
98
- continue; // skip blobs
99
117
  if (prop && lexicon) {
100
- const derived = jsonSearchColumns(`t.${col.name}`, prop, lexicon);
118
+ const derived = jsonSearchColumns(`t.${q(col.name)}`, prop, lexicon, dialect);
101
119
  if (derived.length > 0) {
102
120
  for (const d of derived) {
103
121
  selectExprs.push(`${d.expr} AS ${d.alias}`);
@@ -107,16 +125,17 @@ export async function buildFtsIndex(collection) {
107
125
  }
108
126
  }
109
127
  // Fallback: cast JSON to TEXT
110
- selectExprs.push(`CAST(t.${col.name} AS TEXT) AS ${col.name}`);
128
+ selectExprs.push(`CAST(t.${q(col.name)} AS TEXT) AS ${q(col.name)}`);
111
129
  searchColNames.push(col.name);
112
130
  }
113
131
  }
114
132
  // Include searchable text from child tables (decomposed array fields)
115
133
  for (const child of schema.children) {
116
134
  for (const col of child.columns) {
117
- if (col.duckdbType === 'TEXT') {
135
+ if (col.sqlType === 'TEXT') {
118
136
  const alias = `${child.fieldName}_${col.name}`;
119
- selectExprs.push(`(SELECT string_agg(c.${col.name}, ' ') FROM ${child.tableName} c WHERE c.parent_uri = t.uri) AS ${alias}`);
137
+ const agg = dialect.stringAgg(`c.${q(col.name)}`, "' '");
138
+ selectExprs.push(`(SELECT ${agg} FROM ${child.tableName} c WHERE c.parent_uri = t.uri) AS ${alias}`);
120
139
  searchColNames.push(alias);
121
140
  }
122
141
  }
@@ -125,9 +144,10 @@ export async function buildFtsIndex(collection) {
125
144
  for (const union of schema.unions) {
126
145
  for (const branch of union.branches) {
127
146
  for (const col of branch.columns) {
128
- if (col.duckdbType === 'TEXT') {
147
+ if (col.sqlType === 'TEXT') {
129
148
  const alias = `${union.fieldName}_${branch.branchName}_${col.name}`;
130
- selectExprs.push(`(SELECT string_agg(c.${col.name}, ' ') FROM ${branch.tableName} c WHERE c.parent_uri = t.uri) AS ${alias}`);
149
+ const agg = dialect.stringAgg(`c.${q(col.name)}`, "' '");
150
+ selectExprs.push(`(SELECT ${agg} FROM ${branch.tableName} c WHERE c.parent_uri = t.uri) AS ${alias}`);
131
151
  searchColNames.push(alias);
132
152
  }
133
153
  }
@@ -136,23 +156,83 @@ export async function buildFtsIndex(collection) {
136
156
  // Include handle from _repos for people search
137
157
  selectExprs.push('r.handle');
138
158
  searchColNames.push('handle');
139
- if (searchColNames.length === 0) {
140
- return;
141
- }
142
159
  const safeName = ftsTableName(collection);
143
- // Build shadow table with derived text columns, joining _repos for handle
144
- await runSQL(`CREATE OR REPLACE TABLE ${safeName} AS SELECT ${selectExprs.join(', ')} FROM ${schema.tableName} t LEFT JOIN _repos r ON t.did = r.did`);
145
- // Drop existing index (ignore error if none exists)
146
- try {
147
- await runSQL(`PRAGMA drop_fts_index('${safeName}')`);
160
+ const sourceQuery = `SELECT ${selectExprs.join(', ')} FROM ${schema.tableName} t LEFT JOIN _repos r ON t.did = r.did`;
161
+ const result = { searchColNames, sourceQuery, safeName };
162
+ ftsSchemaCache.set(collection, result);
163
+ return result;
164
+ }
165
+ /**
166
+ * Build FTS index for a collection.
167
+ * Creates a shadow table copy and indexes all TEXT NOT NULL columns
168
+ * using Porter stemmer with English stopwords.
169
+ */
170
+ export async function buildFtsIndex(collection) {
171
+ if (!searchPort)
172
+ return; // No FTS support for this adapter
173
+ const { searchColNames, sourceQuery, safeName } = computeFtsSchema(collection);
174
+ if (searchColNames.length === 0)
175
+ return;
176
+ // For incremental ports: skip rebuild if index already exists
177
+ if (searchPort.indexExists) {
178
+ const exists = await searchPort.indexExists(safeName);
179
+ if (exists) {
180
+ searchColumnCache.set(collection, searchColNames);
181
+ lastRebuiltAt.set(collection, new Date().toISOString());
182
+ return;
183
+ }
148
184
  }
149
- catch { }
150
- // Build FTS index over all search columns
151
- const colList = searchColNames.map((c) => `'${c}'`).join(', ');
152
- await runSQL(`PRAGMA create_fts_index('${safeName}', 'uri', ${colList}, stemmer='porter', stopwords='english', strip_accents=1, lower=1, overwrite=1)`);
185
+ await searchPort.buildIndex(safeName, sourceQuery, searchColNames);
153
186
  searchColumnCache.set(collection, searchColNames);
154
187
  lastRebuiltAt.set(collection, new Date().toISOString());
155
188
  }
189
+ export async function buildFtsRow(collection, uri) {
190
+ const { searchColNames, sourceQuery } = computeFtsSchema(collection);
191
+ if (searchColNames.length === 0)
192
+ return null;
193
+ // Append WHERE clause to filter for single record
194
+ const sql = sourceQuery + ' WHERE t.uri = $1';
195
+ const rows = await querySQL(sql, [uri]);
196
+ if (!rows || rows.length === 0)
197
+ return null;
198
+ const row = rows[0];
199
+ const result = {};
200
+ for (const col of searchColNames) {
201
+ result[col] = row[col] != null ? String(row[col]) : null;
202
+ }
203
+ return result;
204
+ }
205
+ export async function updateFtsRecord(collection, uri) {
206
+ if (!searchPort || !searchPort.updateIndex)
207
+ return;
208
+ const searchCols = searchColumnCache.get(collection);
209
+ if (!searchCols || searchCols.length === 0)
210
+ return;
211
+ try {
212
+ const row = await buildFtsRow(collection, uri);
213
+ if (!row)
214
+ return;
215
+ const safeName = ftsTableName(collection);
216
+ await searchPort.updateIndex(safeName, uri, row, searchCols);
217
+ }
218
+ catch (err) {
219
+ emit('fts', 'update_error', { collection, uri, error: err.message });
220
+ }
221
+ }
222
+ export async function deleteFtsRecord(collection, uri) {
223
+ if (!searchPort || !searchPort.deleteFromIndex)
224
+ return;
225
+ const searchCols = searchColumnCache.get(collection);
226
+ if (!searchCols || searchCols.length === 0)
227
+ return;
228
+ try {
229
+ const safeName = ftsTableName(collection);
230
+ await searchPort.deleteFromIndex(safeName, uri, searchCols);
231
+ }
232
+ catch (err) {
233
+ emit('fts', 'delete_error', { collection, uri, error: err.message });
234
+ }
235
+ }
156
236
  /**
157
237
  * Rebuild FTS indexes for all registered collections.
158
238
  */
@@ -752,6 +832,14 @@ export async function rebuildAllIndexes(collections) {
752
832
  errors.push(`${collection}: ${err.message}`);
753
833
  }
754
834
  }
835
+ // Compact WAL to free memory after heavy FTS operations (DuckDB only)
836
+ try {
837
+ const { getSqlDialect } = await import("./db.js");
838
+ const d = getSqlDialect();
839
+ if (d.checkpointSQL)
840
+ await runSQL(d.checkpointSQL);
841
+ }
842
+ catch { }
755
843
  emit('fts', 'rebuild', {
756
844
  collections_total: collections.length,
757
845
  collections_rebuilt: rebuilt,
@@ -0,0 +1,7 @@
1
+ export type { DatabasePort, BulkInserter, SearchPort, Dialect } from './ports.ts';
2
+ export type { SqlDialect } from './dialect.ts';
3
+ export { getDialect, DUCKDB_DIALECT, SQLITE_DIALECT } from './dialect.ts';
4
+ export { createAdapter } from './adapter-factory.ts';
5
+ export { initDatabase, closeDatabase, querySQL, runSQL, insertRecord, deleteRecord, queryRecords, searchRecords, getRecordByUri, getCursor, setCursor, bulkInsertRecords, packCursor, unpackCursor, } from './db.ts';
6
+ export { type TableSchema, type ColumnDef, type ChildTableSchema, loadLexicons, discoverCollections, buildSchemas, generateTableSchema, generateCreateTableSQL, toSnakeCase, getLexicon, getLexiconArray, getAllLexicons, storeLexicons, columnName, } from './schema.ts';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/database/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACjF,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAGpD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,SAAS,EACT,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,SAAS,CAAA;AAGhB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,YAAY,EACZ,mBAAmB,EACnB,YAAY,EACZ,mBAAmB,EACnB,sBAAsB,EACtB,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,aAAa,EACb,UAAU,GACX,MAAM,aAAa,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { getDialect, DUCKDB_DIALECT, SQLITE_DIALECT } from "./dialect.js";
2
+ export { createAdapter } from "./adapter-factory.js";
3
+ // Re-export commonly used functions from db.ts
4
+ export { initDatabase, closeDatabase, querySQL, runSQL, insertRecord, deleteRecord, queryRecords, searchRecords, getRecordByUri, getCursor, setCursor, bulkInsertRecords, packCursor, unpackCursor, } from "./db.js";
5
+ // Re-export schema utilities
6
+ export { loadLexicons, discoverCollections, buildSchemas, generateTableSchema, generateCreateTableSQL, toSnakeCase, getLexicon, getLexiconArray, getAllLexicons, storeLexicons, columnName, } from "./schema.js";
@@ -0,0 +1,50 @@
1
+ export type Dialect = 'duckdb' | 'sqlite' | 'postgres';
2
+ export interface DatabasePort {
3
+ /** Dialect identifier for SQL generation differences */
4
+ dialect: Dialect;
5
+ /** Open a database connection. path is file path or ':memory:' */
6
+ open(path: string): Promise<void>;
7
+ /** Close all connections and release resources */
8
+ close(): void;
9
+ /** Execute a read query, return rows as plain objects */
10
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
11
+ /** Execute a write statement (INSERT, UPDATE, DELETE, DDL) */
12
+ execute(sql: string, params?: unknown[]): Promise<void>;
13
+ /** Execute multiple statements in sequence (for DDL batches) */
14
+ executeMultiple(sql: string): Promise<void>;
15
+ /** Begin a transaction */
16
+ beginTransaction(): Promise<void>;
17
+ /** Commit the current transaction */
18
+ commit(): Promise<void>;
19
+ /** Rollback the current transaction */
20
+ rollback(): Promise<void>;
21
+ /** Create a bulk inserter for high-throughput writes */
22
+ createBulkInserter(table: string, columns: string[], options?: {
23
+ onConflict?: 'ignore' | 'replace';
24
+ batchSize?: number;
25
+ }): Promise<BulkInserter>;
26
+ }
27
+ export interface BulkInserter {
28
+ /** Append a single row of values */
29
+ append(values: unknown[]): void;
30
+ /** Flush buffered rows to the database */
31
+ flush(): Promise<void>;
32
+ /** Close the inserter and release resources */
33
+ close(): Promise<void>;
34
+ }
35
+ export interface SearchPort {
36
+ /** Build/rebuild an FTS index for a table */
37
+ buildIndex(shadowTable: string, sourceQuery: string, searchColumns: string[]): Promise<void>;
38
+ /** Incrementally update a single record in the FTS index */
39
+ updateIndex?(shadowTable: string, uri: string, row: Record<string, string | null>, searchColumns: string[]): Promise<void>;
40
+ /** Remove a single record from the FTS index */
41
+ deleteFromIndex?(shadowTable: string, uri: string, searchColumns: string[]): Promise<void>;
42
+ /** Check if the FTS index already exists (for skipping rebuild on startup) */
43
+ indexExists?(shadowTable: string): Promise<boolean>;
44
+ /** Search a table, returning URIs with scores */
45
+ search(shadowTable: string, query: string, searchColumns: string[], limit: number, offset: number): Promise<Array<{
46
+ uri: string;
47
+ score: number;
48
+ }>>;
49
+ }
50
+ //# sourceMappingURL=ports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ports.d.ts","sourceRoot":"","sources":["../../src/database/ports.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAA;AAEtD,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,OAAO,EAAE,OAAO,CAAA;IAEhB,kEAAkE;IAClE,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjC,kDAAkD;IAClD,KAAK,IAAI,IAAI,CAAA;IAEb,yDAAyD;IACzD,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;IAEjF,8DAA8D;IAC9D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvD,gEAAgE;IAChE,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3C,0BAA0B;IAC1B,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjC,qCAAqC;IACrC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvB,uCAAuC;IACvC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzB,wDAAwD;IACxD,kBAAkB,CAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC,YAAY,CAAC,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAE/B,0CAA0C;IAC1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtB,+CAA+C;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE5F,4DAA4D;IAC5D,WAAW,CAAC,CACV,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAClC,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,IAAI,CAAC,CAAA;IAEhB,gDAAgD;IAChD,eAAe,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE1F,8EAA8E;IAC9E,WAAW,CAAC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAEnD,iDAAiD;IACjD,MAAM,CACJ,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EAAE,EACvB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAClD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,11 @@
1
+ import type { SqlDialect } from './dialect.ts';
1
2
  export interface ColumnDef {
2
3
  name: string;
3
4
  originalName: string;
4
- duckdbType: string;
5
+ sqlType: string;
5
6
  notNull: boolean;
6
7
  isRef: boolean;
8
+ isJson: boolean;
7
9
  }
8
10
  export interface UnionBranchSchema {
9
11
  type: string;
@@ -33,7 +35,10 @@ export interface ChildTableSchema {
33
35
  columns: ColumnDef[];
34
36
  }
35
37
  export declare function toSnakeCase(str: string): string;
38
+ export declare function columnName(fieldName: string): string;
39
+ export declare function q(name: string): string;
36
40
  export declare function loadLexicons(lexiconsDir: string): Map<string, any>;
41
+ export declare function validatableLexicons(lexicons: Map<string, any>): any[];
37
42
  /**
38
43
  * Discover collections by scanning lexicons for record-type definitions.
39
44
  */
@@ -46,6 +51,14 @@ export declare function getAllLexicons(): Array<{
46
51
  }>;
47
52
  /** Get all stored lexicons as a flat array (for @bigmoves/lexicon validators) */
48
53
  export declare function getLexiconArray(): any[];
49
- export declare function generateTableSchema(nsid: string, lexicon: any, lexicons?: Map<string, any>): TableSchema;
50
- export declare function generateCreateTableSQL(schema: TableSchema): string;
54
+ export declare function generateTableSchema(nsid: string, lexicon: any, lexicons?: Map<string, any>, dialect?: SqlDialect): TableSchema;
55
+ export declare function generateCreateTableSQL(schema: TableSchema, dialect?: SqlDialect): string;
56
+ /**
57
+ * Build table schemas and DDL from lexicons and collections.
58
+ * Shared by main.ts (server boot) and cli.ts (hatk schema command).
59
+ */
60
+ export declare function buildSchemas(lexicons: Map<string, any>, collections: string[], dialect?: SqlDialect): {
61
+ schemas: TableSchema[];
62
+ ddlStatements: string[];
63
+ };
51
64
  //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/database/schema.ts"],"names":[],"mappings":"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"}