qubu 0.0.0 → 0.3.4

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 (109) hide show
  1. package/dist/canonical-BbnqavJm.mjs +972 -0
  2. package/dist/codegen.d.mts +107 -0
  3. package/dist/codegen.mjs +1199 -0
  4. package/dist/column-CXMxx8Hq.mjs +118 -0
  5. package/dist/complete-D5Djh-zo.mjs +1788 -0
  6. package/dist/complete-types-BdFqUfbb.d.mts +371 -0
  7. package/dist/core.d.mts +33 -0
  8. package/dist/core.mjs +36 -0
  9. package/dist/ddl.d.mts +118 -0
  10. package/dist/ddl.mjs +1120 -0
  11. package/dist/dialect-b2-Z6uBF.mjs +13 -0
  12. package/dist/diff.d.mts +2 -0
  13. package/dist/diff.mjs +883 -0
  14. package/dist/drizzle-mysql.d.mts +24 -0
  15. package/dist/drizzle-mysql.mjs +72 -0
  16. package/dist/drizzle-postgres.d.mts +24 -0
  17. package/dist/drizzle-postgres.mjs +73 -0
  18. package/dist/drizzle-sqlite.d.mts +24 -0
  19. package/dist/drizzle-sqlite.mjs +82 -0
  20. package/dist/drizzle.d.mts +13 -0
  21. package/dist/drizzle.mjs +2 -0
  22. package/dist/errors-BGCoLe_r.mjs +14 -0
  23. package/dist/errors-Dxv73YJu.mjs +26 -0
  24. package/dist/explain-CkIK13L_.mjs +98 -0
  25. package/dist/index-Ds7-mhJi.d.mts +146 -0
  26. package/dist/index-Dug5HnLB.d.mts +204 -0
  27. package/dist/index.d.mts +2 -0
  28. package/dist/index.mjs +1276 -0
  29. package/dist/introspection.d.mts +117 -0
  30. package/dist/introspection.mjs +4341 -0
  31. package/dist/json-CUZlv4HT.mjs +169 -0
  32. package/dist/migration.d.mts +215 -0
  33. package/dist/migration.mjs +1161 -0
  34. package/dist/mysql-DqkqXB6A.mjs +355 -0
  35. package/dist/mysql.d.mts +5 -0
  36. package/dist/mysql.mjs +50 -0
  37. package/dist/naming-QVCOnSj2.mjs +20 -0
  38. package/dist/omit-OxV58AwX.mjs +5 -0
  39. package/dist/on-conflict-BxnxubMb.mjs +143 -0
  40. package/dist/postgres-DEBBeh52.mjs +235 -0
  41. package/dist/postgres.d.mts +123 -0
  42. package/dist/postgres.mjs +52 -0
  43. package/dist/registry-BufIskVN.mjs +569 -0
  44. package/dist/relational-DCZrrNia.mjs +77 -0
  45. package/dist/runtime-BTr-MTlo.mjs +193 -0
  46. package/dist/schema.d.mts +2 -0
  47. package/dist/schema.mjs +5 -0
  48. package/dist/serialize-PF1cfH2P.mjs +556 -0
  49. package/dist/snapshot-CWPgzxNx.mjs +392 -0
  50. package/dist/snapshot.d.mts +4 -0
  51. package/dist/snapshot.mjs +8 -0
  52. package/dist/source-DUoJVXmL.mjs +68 -0
  53. package/dist/sqlite-BU6DBxef.mjs +320 -0
  54. package/dist/sqlite.d.mts +5 -0
  55. package/dist/sqlite.mjs +48 -0
  56. package/dist/standard-BTVYKh_F.mjs +12 -0
  57. package/dist/table-llv9tsZ8.mjs +384 -0
  58. package/dist/types-4Q076HKo.d.mts +3636 -0
  59. package/dist/types-BX0mckiU.d.mts +644 -0
  60. package/dist/types-Cec0xzo4.mjs +116 -0
  61. package/dist/types-H4vyCw8_.d.mts +45 -0
  62. package/dist/value-BvilP0oz.mjs +29 -0
  63. package/dist/vite/ambient.d.ts +449 -0
  64. package/dist/vite.d.mts +35 -0
  65. package/dist/vite.mjs +498 -0
  66. package/docs/config.json +21 -0
  67. package/docs/dialects-and-execution.md +427 -0
  68. package/docs/getting-started.md +96 -0
  69. package/docs/guides/compose-queries.md +225 -0
  70. package/docs/guides/drizzle.md +130 -0
  71. package/docs/guides/extensions/dialects.md +40 -0
  72. package/docs/guides/extensions/overview.md +36 -0
  73. package/docs/guides/extensions/sources-and-clauses.md +82 -0
  74. package/docs/guides/extensions/typed-expressions.md +94 -0
  75. package/docs/guides/extensions/unsafe-syntax.md +27 -0
  76. package/docs/guides/json.md +65 -0
  77. package/docs/guides/mutations.md +138 -0
  78. package/docs/guides/select/conditions.md +110 -0
  79. package/docs/guides/select/grouping-and-windows.md +82 -0
  80. package/docs/guides/select/ordering-and-pagination.md +78 -0
  81. package/docs/guides/select/overview.md +139 -0
  82. package/docs/guides/sql-templates.md +157 -0
  83. package/docs/guides/vite-plugin.md +92 -0
  84. package/docs/index.md +111 -0
  85. package/docs/query-model/fragments.md +109 -0
  86. package/docs/query-model/result-shapes.md +125 -0
  87. package/docs/query-model/source-scope.md +182 -0
  88. package/docs/reference/introspection-support.md +196 -0
  89. package/docs/reference/mysql-snapshot.md +55 -0
  90. package/docs/reference/postgres-snapshot.md +61 -0
  91. package/docs/reference/sqlite-snapshot.md +53 -0
  92. package/docs/reference/supported-surface.md +104 -0
  93. package/docs/schema/catalog-model.md +58 -0
  94. package/docs/schema/code-generation.md +139 -0
  95. package/docs/schema/columns-and-writes.md +130 -0
  96. package/docs/schema/constraints-and-indexes.md +180 -0
  97. package/docs/schema/ddl-emission.md +75 -0
  98. package/docs/schema/diff.md +75 -0
  99. package/docs/schema/introspection.md +214 -0
  100. package/docs/schema/migration-plans.md +76 -0
  101. package/docs/schema/snapshots.md +93 -0
  102. package/docs/schema/storage-and-schema-sql.md +104 -0
  103. package/docs/schema/tables-and-names.md +106 -0
  104. package/docs/sql-semantic-types.md +141 -0
  105. package/docs/troubleshooting.md +151 -0
  106. package/package.json +132 -10
  107. package/skills/qubu/SKILL.md +42 -0
  108. package/skills/qubu/agents/openai.yaml +6 -0
  109. package/readme.md +0 -1
@@ -0,0 +1,569 @@
1
+ import { t as standardDialect } from "./standard-BTVYKh_F.mjs";
2
+ import { d as markSchemaExpression, l as makeSchemaExpression, r as isColumnReference, s as isSchemaExpression } from "./column-CXMxx8Hq.mjs";
3
+ import { n as isValueExpression } from "./value-BvilP0oz.mjs";
4
+ import { n as snakeCaseIdentifier } from "./naming-QVCOnSj2.mjs";
5
+ //#region src/schema/metadata.ts
6
+ /** Error raised when relational metadata cannot be represented safely. */
7
+ var SchemaMetadataValidationError = class extends TypeError {
8
+ name = "SchemaMetadataValidationError";
9
+ diagnostics;
10
+ issues;
11
+ constructor(diagnostics) {
12
+ const frozenDiagnostics = Object.freeze(diagnostics.map((diagnostic) => Object.freeze({
13
+ ...diagnostic,
14
+ path: Object.freeze([...diagnostic.path]),
15
+ relatedPaths: diagnostic.relatedPaths ? Object.freeze(diagnostic.relatedPaths.map((path) => Object.freeze([...path]))) : void 0
16
+ })));
17
+ super(frozenDiagnostics.map((diagnostic) => diagnostic.message).join("\n"));
18
+ this.diagnostics = frozenDiagnostics;
19
+ this.issues = frozenDiagnostics;
20
+ }
21
+ };
22
+ /** Generate the version-one physical name for a relational object ID. */
23
+ function generatedSchemaObjectName(id) {
24
+ return snakeCaseIdentifier(id);
25
+ }
26
+ /** Deep-freeze plain metadata values without introducing executable nodes. */
27
+ function freezeSchemaMetadata(value) {
28
+ if (Array.isArray(value)) return Object.freeze(value.map((item) => freezeSchemaMetadata(item)));
29
+ if (typeof value !== "object" || value === null) return value;
30
+ const frozen = Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, freezeSchemaMetadata(nested)]));
31
+ return Object.freeze(frozen);
32
+ }
33
+ /** Check the portable identifier subset used for generated metadata names. */
34
+ function isValidSchemaObjectName(name) {
35
+ return name.length > 0 && name === name.trim() && !/[.\\/\u0000-\u001f\u007f"']/u.test(name);
36
+ }
37
+ /**
38
+ * Attach a record key and resolved physical name without changing the
39
+ * enumerable shape of legacy constraint/index values. The properties are
40
+ * still ordinary read-only runtime metadata and are available to snapshot
41
+ * traversals.
42
+ */
43
+ function materializeSchemaObjectIdentity(value, id, physicalName) {
44
+ const materialized = { ...value };
45
+ Object.defineProperties(materialized, {
46
+ id: {
47
+ configurable: false,
48
+ enumerable: false,
49
+ value: id,
50
+ writable: false
51
+ },
52
+ physicalName: {
53
+ configurable: false,
54
+ enumerable: false,
55
+ value: physicalName ?? generatedSchemaObjectName(id),
56
+ writable: false
57
+ }
58
+ });
59
+ return Object.freeze(materialized);
60
+ }
61
+ /**
62
+ * Resolve and validate names for one metadata record. The caller decides
63
+ * whether constraint and index names share a database namespace.
64
+ */
65
+ function materializeSchemaObjectRecord(record, kind) {
66
+ const diagnostics = [];
67
+ const names = /* @__PURE__ */ new Map();
68
+ const result = {};
69
+ for (const [id, value] of Object.entries(record)) {
70
+ const physicalName = value.physicalName ?? generatedSchemaObjectName(id);
71
+ const path = [kind === "constraint" ? "constraints" : "indexes", id];
72
+ if (!isValidSchemaObjectName(physicalName)) diagnostics.push({
73
+ code: "invalid-physical-name",
74
+ message: `The ${kind} "${id}" has invalid physical name "${physicalName}"`,
75
+ path: [...path, "physicalName"]
76
+ });
77
+ const previousId = names.get(physicalName);
78
+ if (previousId !== void 0) diagnostics.push({
79
+ code: "duplicate-physical-name",
80
+ message: `The ${kind}s "${previousId}" and "${id}" both use physical name "${physicalName}"`,
81
+ path: [...path, "physicalName"],
82
+ relatedPaths: [[
83
+ kind === "constraint" ? "constraints" : "indexes",
84
+ previousId,
85
+ "physicalName"
86
+ ]]
87
+ });
88
+ else names.set(physicalName, id);
89
+ result[id] = materializeSchemaObjectIdentity(value, id, physicalName);
90
+ }
91
+ if (diagnostics.length > 0) throw new SchemaMetadataValidationError(diagnostics);
92
+ return Object.freeze(result);
93
+ }
94
+ /** Return a diagnostic when a dialect extension is used by another adapter. */
95
+ function dialectMismatchDiagnostic(extension, dialect, path) {
96
+ if (extension.dialect === dialect) return void 0;
97
+ return {
98
+ code: "dialect-mismatch",
99
+ message: `Dialect extension belongs to "${extension.dialect}" but the active schema dialect is "${dialect}"`,
100
+ path,
101
+ dialect
102
+ };
103
+ }
104
+ /** Throw a structured error for one or more dialect capability findings. */
105
+ function assertSchemaDialectSupport(diagnostics) {
106
+ if (diagnostics.length > 0) throw new SchemaMetadataValidationError(diagnostics);
107
+ }
108
+ //#endregion
109
+ //#region src/schema/indexes.ts
110
+ /**
111
+ * Validate portable and dialect-owned index facts for one target adapter.
112
+ * Unsupported features are reported as data so a serializer can aggregate
113
+ * diagnostics instead of failing during traversal with an opaque exception.
114
+ */
115
+ function validateIndexDialect(indexMetadata, dialect, path = ["index"]) {
116
+ const diagnostics = [];
117
+ const extension = indexMetadata.dialect;
118
+ if (extension !== void 0) {
119
+ const mismatch = dialectMismatchDiagnostic(extension, dialect, [...path, "dialect"]);
120
+ if (mismatch !== void 0) diagnostics.push(mismatch);
121
+ }
122
+ if ((dialect === "sqlite" || dialect === "mysql") && indexMetadata.includedColumns !== void 0 && indexMetadata.includedColumns.length > 0) diagnostics.push({
123
+ code: "unsupported-dialect-option",
124
+ message: `${dialect} indexes do not support included columns`,
125
+ path: [...path, "includedColumns"],
126
+ dialect
127
+ });
128
+ const mysqlKeyBlockSize = extension?.dialect === "mysql" ? extension.keyBlockSize : void 0;
129
+ if (mysqlKeyBlockSize !== void 0 && (!Number.isInteger(mysqlKeyBlockSize) || mysqlKeyBlockSize <= 0)) diagnostics.push({
130
+ code: "unsupported-dialect-option",
131
+ message: "MySQL index keyBlockSize must be a positive integer",
132
+ path: [
133
+ ...path,
134
+ "dialect",
135
+ "keyBlockSize"
136
+ ],
137
+ dialect
138
+ });
139
+ return Object.freeze(diagnostics);
140
+ }
141
+ /** Declare a portable column or expression index. */
142
+ function index(terms, options) {
143
+ const resolvedOptions = options ?? {};
144
+ const candidateKey = resolvedOptions.unique === true && resolvedOptions.where === void 0 && terms.every((term) => {
145
+ return ("orderKind" in term ? term.expression : term).expressionKind === "column";
146
+ });
147
+ return Object.freeze({
148
+ kind: "index",
149
+ terms: Object.freeze([...terms]),
150
+ unique: resolvedOptions.unique === true,
151
+ predicate: resolvedOptions.where,
152
+ ...resolvedOptions.include !== void 0 ? { includedColumns: Object.freeze([...resolvedOptions.include]) } : {},
153
+ ...resolvedOptions.physicalName !== void 0 ? { physicalName: resolvedOptions.physicalName } : {},
154
+ ...resolvedOptions.dialect !== void 0 ? { dialect: freezeSchemaMetadata(resolvedOptions.dialect) } : {},
155
+ candidateKey
156
+ });
157
+ }
158
+ //#endregion
159
+ //#region src/schema/expressions.ts
160
+ /** Error raised before a schema expression can become persisted SQL. */
161
+ var SchemaExpressionError = class extends TypeError {
162
+ code;
163
+ mode;
164
+ constructor(code, message, mode) {
165
+ super(message);
166
+ this.name = "SchemaExpressionError";
167
+ this.code = code;
168
+ this.mode = mode;
169
+ }
170
+ };
171
+ /**
172
+ * Normalize only line endings. Whitespace, quoting, and every other byte of
173
+ * a raw schema expression remain under the extension author's control.
174
+ */
175
+ function normalizeSchemaSql(sql) {
176
+ return sql.replace(/\r\n?/g, "\n");
177
+ }
178
+ function schemaExpression(expression) {
179
+ return markSchemaExpression(expression);
180
+ }
181
+ /**
182
+ * Define an extension with the restricted schema context. This is the typed
183
+ * alternative to {@link unsafeSchemaSql} for deterministic custom syntax.
184
+ */
185
+ function defineSchemaExpression(kind, render) {
186
+ return makeSchemaExpression(kind, (context) => render(context));
187
+ }
188
+ function unsafeSchemaSql(dialectOrOptions, sql) {
189
+ const dialect = typeof dialectOrOptions === "string" ? dialectOrOptions : dialectOrOptions.dialect;
190
+ const source = typeof dialectOrOptions === "string" ? sql : dialectOrOptions.sql;
191
+ if (!dialect) throw new TypeError("unsafeSchemaSql() requires a dialect tag");
192
+ if (source === void 0) throw new TypeError("unsafeSchemaSql() requires SQL text");
193
+ const normalized = normalizeSchemaSql(source);
194
+ const expression = makeSchemaExpression("unsafe", (context) => context.append(normalized));
195
+ return Object.freeze({
196
+ ...expression,
197
+ schemaSqlDialect: dialect,
198
+ schemaSql: normalized
199
+ });
200
+ }
201
+ /** Identify a dialect-tagged raw schema expression. */
202
+ function isUnsafeSchemaSql(value) {
203
+ return isSchemaExpression(value) && value.expressionKind === "unsafe" && typeof value.schemaSqlDialect === "string" && typeof value.schemaSql === "string";
204
+ }
205
+ function renderSchemaExpression(expression, optionsOrMode, dialectOption) {
206
+ const options = typeof optionsOrMode === "string" ? {
207
+ mode: optionsOrMode,
208
+ dialect: dialectOption
209
+ } : optionsOrMode;
210
+ const dialect = options.dialect ?? standardDialect();
211
+ if (!isSchemaExpression(expression)) throw new SchemaExpressionError("not-deterministic", "Only branded deterministic expressions can be rendered as schema SQL", options.mode);
212
+ assertSupportedExpression(expression, options.mode);
213
+ let text = "";
214
+ const context = {
215
+ dialect,
216
+ projectionMode: "result",
217
+ schemaMode: options.mode,
218
+ append(value) {
219
+ text += value;
220
+ },
221
+ parameter() {
222
+ throw new SchemaExpressionError("parameter", "Schema expressions cannot render query parameters", options.mode);
223
+ },
224
+ literal(value) {
225
+ text += renderSchemaLiteral(dialect, value, options.mode);
226
+ },
227
+ renderColumnReference(columnName) {
228
+ if (options.mode === "default") throw new SchemaExpressionError("column-not-allowed", "Default expressions cannot reference table columns", options.mode);
229
+ text += dialect.quoteIdentifier(columnName);
230
+ },
231
+ render(part) {
232
+ renderSchemaPart(context, part, options.mode);
233
+ },
234
+ renderRelation() {
235
+ throw new SchemaExpressionError("unsupported-expression", "Schema expressions cannot contain subqueries", options.mode);
236
+ }
237
+ };
238
+ renderSchemaPart(context, expression, options.mode);
239
+ return Object.freeze({
240
+ text,
241
+ parameters: Object.freeze([])
242
+ });
243
+ }
244
+ /** Convenience form for callers that only need the SQL text. */
245
+ function renderSchemaSql(expression, options) {
246
+ return renderSchemaExpression(expression, options).text;
247
+ }
248
+ function renderSchemaPart(context, part, mode) {
249
+ if (isValueExpression(part)) {
250
+ context.literal(part.value);
251
+ return;
252
+ }
253
+ if (isColumnReference(part)) {
254
+ context.renderColumnReference(part.columnName);
255
+ return;
256
+ }
257
+ if (isUnsafeSchemaSql(part)) {
258
+ if (part.schemaSqlDialect !== context.dialect.name) throw new SchemaExpressionError("dialect-mismatch", `Schema SQL is tagged for "${part.schemaSqlDialect}" but rendered for "${context.dialect.name}"`, mode);
259
+ context.append(part.schemaSql);
260
+ return;
261
+ }
262
+ if (!isSchemaExpression(part)) throw new SchemaExpressionError("not-deterministic", "Schema expressions may only compose branded expressions, columns, and literals", mode);
263
+ assertSupportedExpression(part, mode);
264
+ part.render(context);
265
+ }
266
+ function assertSupportedExpression(expression, mode) {
267
+ if (expression.expressionKind === "subquery" || expression.expressionCategory) throw new SchemaExpressionError("unsupported-expression", "Aggregates, windows, and subqueries are not valid schema expressions", mode);
268
+ }
269
+ function renderSchemaLiteral(dialect, value, mode) {
270
+ if (dialect.renderSchemaLiteral) {
271
+ const rendered = dialect.renderSchemaLiteral(value);
272
+ if (typeof rendered !== "string" || rendered.includes("?")) throw new SchemaExpressionError("invalid-literal", "A schema literal renderer must return parameter-free SQL text", mode);
273
+ return rendered;
274
+ }
275
+ if (value === null) return "NULL";
276
+ if (typeof value === "boolean") return value ? "TRUE" : "FALSE";
277
+ if (typeof value === "string") return `'${value.replaceAll("'", "''")}'`;
278
+ if (typeof value === "bigint") return String(value);
279
+ if (typeof value === "number") {
280
+ if (!Number.isFinite(value)) throw new SchemaExpressionError("unsupported-value", "Schema literals require finite numbers", mode);
281
+ return Object.is(value, -0) ? "0" : String(value);
282
+ }
283
+ throw new SchemaExpressionError("unsupported-value", `Unsupported schema literal type: ${value === void 0 ? "undefined" : typeof value}`, mode);
284
+ }
285
+ //#endregion
286
+ //#region src/schema/constraints.ts
287
+ /**
288
+ * Validate one constraint against a schema adapter dialect. This is kept
289
+ * separate from construction because the same declaration can be inspected
290
+ * for more than one target dialect before a serializer is selected.
291
+ */
292
+ function validateConstraintDialect(constraint, dialect, path = ["constraint"]) {
293
+ const diagnostics = [];
294
+ const extension = constraint.dialect;
295
+ if (extension !== void 0) {
296
+ const mismatch = dialectMismatchDiagnostic(extension, dialect, [...path, "dialect"]);
297
+ if (mismatch !== void 0) diagnostics.push(mismatch);
298
+ if (extension.dialect === "postgresql" && "notValid" in extension && extension.notValid === true && (constraint.kind === "primary-key" || constraint.kind === "unique" || constraint.kind === "unique-constraint")) diagnostics.push({
299
+ code: "unsupported-dialect-option",
300
+ message: "PostgreSQL NOT VALID is not supported for key constraints",
301
+ path: [
302
+ ...path,
303
+ "dialect",
304
+ "notValid"
305
+ ],
306
+ dialect
307
+ });
308
+ if (extension.dialect === "sqlite" && "onConflict" in extension && extension.onConflict !== void 0 && constraint.kind === "foreign-key") diagnostics.push({
309
+ code: "unsupported-dialect-option",
310
+ message: "SQLite conflict policies do not apply to foreign keys",
311
+ path: [
312
+ ...path,
313
+ "dialect",
314
+ "onConflict"
315
+ ],
316
+ dialect
317
+ });
318
+ }
319
+ if (constraint.kind === "foreign-key" && constraint.match === "partial" && dialect === "mysql") diagnostics.push({
320
+ code: "unsupported-dialect-option",
321
+ message: "MySQL does not support MATCH PARTIAL foreign keys",
322
+ path: [...path, "match"],
323
+ dialect
324
+ });
325
+ if (constraint.kind === "foreign-key" && constraint.deferrable === true && dialect === "mysql") diagnostics.push({
326
+ code: "unsupported-dialect-option",
327
+ message: "MySQL foreign keys cannot be declared DEFERRABLE",
328
+ path: [...path, "deferrable"],
329
+ dialect
330
+ });
331
+ if (constraint.initially !== void 0 && constraint.deferrable !== true) diagnostics.push({
332
+ code: "unsupported-dialect-option",
333
+ message: "An initial constraint timing requires deferrable: true",
334
+ path: [...path, "initially"],
335
+ dialect
336
+ });
337
+ return Object.freeze(diagnostics);
338
+ }
339
+ function primaryKey(...columnsAndOptions) {
340
+ const last = columnsAndOptions.at(-1);
341
+ const options = last && typeof last === "object" && !("expressionKind" in last) ? last : void 0;
342
+ return freezeConstraint("primary-key", options ? columnsAndOptions.slice(0, -1) : columnsAndOptions, options);
343
+ }
344
+ function unique(...columnsAndOptions) {
345
+ const last = columnsAndOptions.at(-1);
346
+ const options = last && typeof last === "object" && !("expressionKind" in last) ? last : void 0;
347
+ return freezeConstraint("unique", options ? columnsAndOptions.slice(0, -1) : columnsAndOptions, options);
348
+ }
349
+ function uniqueConstraint(...columnsAndOptions) {
350
+ const last = columnsAndOptions.at(-1);
351
+ const options = last && typeof last === "object" && !("expressionKind" in last) ? last : void 0;
352
+ const columns = options ? columnsAndOptions.slice(0, -1) : columnsAndOptions;
353
+ const resolvedOptions = options ?? {};
354
+ return freezeConstraint("unique-constraint", columns, resolvedOptions, resolvedOptions.nulls ?? "distinct");
355
+ }
356
+ /** Pair a table with the exact columns targeted by a foreign key. */
357
+ function references(table, ...columns) {
358
+ return Object.freeze({
359
+ table,
360
+ columns: Object.freeze([...columns])
361
+ });
362
+ }
363
+ /** Declare a single-column or composite foreign key. */
364
+ function foreignKey(columns, target, options) {
365
+ return freezeConstraint("foreign-key", columns, options, target);
366
+ }
367
+ /**
368
+ * Reconstruct a foreign key proved by database catalog metadata.
369
+ *
370
+ * @remarks
371
+ * Use this helper for generated or introspection-owned declarations when one
372
+ * or both native SQL domains are unresolved. It accepts unresolved domains,
373
+ * but still rejects known domain mismatches, unequal tuple arity, and local
374
+ * columns from different sources. The enclosing `table()` declaration
375
+ * continues to verify target-column ownership and candidate-key metadata.
376
+ * Resolved targets also receive runtime shape, ownership, and arity checks.
377
+ * The returned value serializes as an ordinary foreign-key constraint.
378
+ */
379
+ function catalogForeignKey(columns, target, options) {
380
+ assertCatalogForeignKeyColumns(columns, "local");
381
+ return freezeConstraint("foreign-key", columns, options, validateCatalogForeignKeyTargetInput(target, columns.length));
382
+ }
383
+ /** Declare a boolean table invariant. */
384
+ function check(expression, options) {
385
+ return freezeConstraint("check", void 0, options, expression);
386
+ }
387
+ /**
388
+ * Reconstruct a boolean check from opaque SQL recovered from a database
389
+ * catalog.
390
+ *
391
+ * @remarks
392
+ * This helper records catalog origin as a narrow type-level proof. It
393
+ * gives the opaque expression the {@link SqlBoolean} semantic type without
394
+ * changing the ordinary {@link check} contract. Qubu does not parse or infer
395
+ * dependencies from the SQL. It preserves the text apart from normalizing
396
+ * line endings and retains the dialect tag in serialized schema metadata.
397
+ */
398
+ function catalogCheck(input, options) {
399
+ assertCatalogCheckSql(input);
400
+ return freezeConstraint("check", void 0, options, unsafeSchemaSql(input.dialect, input.sql));
401
+ }
402
+ function assertCatalogCheckSql(value) {
403
+ if (typeof value !== "object" || value === null) throw new TypeError("catalogCheck() requires dialect-tagged SQL data");
404
+ const input = value;
405
+ if (input.dialect !== "postgresql" && input.dialect !== "sqlite" && input.dialect !== "mysql") throw new TypeError(`catalogCheck() requires a supported catalog dialect, received "${String(input.dialect)}"`);
406
+ if (typeof input.sql !== "string" || input.sql.trim().length === 0) throw new TypeError("catalogCheck() requires non-empty SQL text");
407
+ }
408
+ function assertCatalogForeignKeyColumns(value, side) {
409
+ if (!Array.isArray(value) || value.length === 0) throw new TypeError(`catalogForeignKey() requires at least one ${side} column`);
410
+ if (!value.every(isColumnReference)) throw new TypeError(`catalogForeignKey() requires ${side} columns to be column references`);
411
+ }
412
+ function validateCatalogForeignKeyTargetInput(value, localArity) {
413
+ return typeof value === "function" ? () => validateCatalogForeignKeyTarget(value(), localArity) : validateCatalogForeignKeyTarget(value, localArity);
414
+ }
415
+ function validateCatalogForeignKeyTarget(value, localArity) {
416
+ if (typeof value !== "object" || value === null) throw new TypeError("catalogForeignKey() requires a foreign-key target");
417
+ const target = value;
418
+ assertCatalogForeignKeyColumns(target.columns, "target");
419
+ if (target.columns.length !== localArity) throw new TypeError(`catalogForeignKey() column arity differs: ${localArity} local and ${target.columns.length} target`);
420
+ const table = target.table;
421
+ if (typeof table !== "object" || table === null || typeof table.columns !== "object" || table.columns === null) throw new TypeError("catalogForeignKey() target must reference a table");
422
+ for (const column of target.columns) if (table.columns[column.fieldName] !== column) throw new TypeError(`catalogForeignKey() target column "${column.fieldName}" does not belong to its table`);
423
+ return target;
424
+ }
425
+ function freezeConstraint(kind, columns, options, extra) {
426
+ const value = { kind };
427
+ const optionValues = options;
428
+ if (columns !== void 0) value.columns = Object.freeze([...columns]);
429
+ if (kind === "check") value.expression = extra;
430
+ else if (kind === "foreign-key") value.target = extra;
431
+ else if (kind === "unique-constraint") value.nulls = extra;
432
+ if (optionValues?.physicalName !== void 0) value.physicalName = optionValues.physicalName;
433
+ if (optionValues?.dialect !== void 0) value.dialect = freezeSchemaMetadata(optionValues.dialect);
434
+ if (optionValues?.deferrable !== void 0) value.deferrable = optionValues.deferrable;
435
+ if (optionValues?.initially !== void 0) value.initially = optionValues.initially;
436
+ if (kind === "foreign-key") {
437
+ if (optionValues?.onUpdate !== void 0) value.onUpdate = optionValues.onUpdate;
438
+ if (optionValues?.onDelete !== void 0) value.onDelete = optionValues.onDelete;
439
+ if (optionValues?.match !== void 0) value.match = optionValues.match;
440
+ }
441
+ return Object.freeze(value);
442
+ }
443
+ //#endregion
444
+ //#region src/schema/registry.ts
445
+ /** The first naming-policy version used by schema metadata. */
446
+ const schemaNamingPolicyVersion = 1;
447
+ /**
448
+ * The built-in naming policy for schema-generated physical names.
449
+ *
450
+ * Explicit names supplied to `table()` remain unchanged. The policy is used
451
+ * by tooling when it needs a physical name for a logical table ID.
452
+ */
453
+ const defaultSchemaNamingPolicy = Object.freeze({
454
+ version: 1,
455
+ tableName: snakeCaseIdentifier
456
+ });
457
+ /** Error thrown when a root schema fails registry or naming validation. */
458
+ var SchemaValidationError = class extends Error {
459
+ name = "SchemaValidationError";
460
+ diagnostics;
461
+ /** Alias matching validation libraries that call findings "issues". */
462
+ issues;
463
+ constructor(diagnostics) {
464
+ const frozenDiagnostics = Object.freeze(diagnostics.map((diagnostic) => Object.freeze({
465
+ ...diagnostic,
466
+ path: Object.freeze([...diagnostic.path]),
467
+ relatedPaths: diagnostic.relatedPaths ? Object.freeze(diagnostic.relatedPaths.map((path) => Object.freeze([...path]))) : void 0
468
+ })));
469
+ super(frozenDiagnostics.map((diagnostic) => diagnostic.message).join("\n"));
470
+ this.diagnostics = frozenDiagnostics;
471
+ this.issues = frozenDiagnostics;
472
+ }
473
+ };
474
+ function entriesOf(input) {
475
+ if (Array.isArray(input)) return input;
476
+ return Object.entries(input);
477
+ }
478
+ function validLogicalId(id) {
479
+ return id.length > 0 && id === id.trim() && !/[.\\/\u0000-\u001f\u007f]/u.test(id);
480
+ }
481
+ function validNamespace(namespace) {
482
+ return namespace.length > 0 && namespace === namespace.trim() && !/[.\\/\u0000-\u001f\u007f"']/u.test(namespace);
483
+ }
484
+ function validateEntries(entries, namespace, namingPolicy) {
485
+ const diagnostics = [];
486
+ const ids = /* @__PURE__ */ new Map();
487
+ const physicalNames = /* @__PURE__ */ new Map();
488
+ const generatedNames = /* @__PURE__ */ new Map();
489
+ for (const [index, [id, table]] of entries.entries()) {
490
+ const path = ["tables", id];
491
+ const previousId = ids.get(id);
492
+ if (previousId !== void 0) diagnostics.push({
493
+ code: "duplicate-table-id",
494
+ message: `Table ID "${id}" is declared more than once`,
495
+ path,
496
+ relatedPaths: [["tables", entries[previousId][0]]]
497
+ });
498
+ else ids.set(id, index);
499
+ if (!validLogicalId(id)) diagnostics.push({
500
+ code: "invalid-table-id",
501
+ message: `Table ID "${id}" must be a non-empty logical identifier`,
502
+ path
503
+ });
504
+ const physicalName = table.tableName || namingPolicy.tableName(id);
505
+ const previousPhysicalName = physicalNames.get(physicalName);
506
+ if (previousPhysicalName !== void 0) diagnostics.push({
507
+ code: "duplicate-physical-name",
508
+ message: `Tables "${entries[previousPhysicalName][0]}" and "${id}" both use physical name "${physicalName}"`,
509
+ path: [...path, "physicalName"],
510
+ relatedPaths: [[
511
+ "tables",
512
+ entries[previousPhysicalName][0],
513
+ "physicalName"
514
+ ]]
515
+ });
516
+ else physicalNames.set(physicalName, index);
517
+ const generatedName = namingPolicy.tableName(id);
518
+ const previousGeneratedName = generatedNames.get(generatedName);
519
+ if (previousGeneratedName !== void 0) diagnostics.push({
520
+ code: "generated-name-collision",
521
+ message: `Logical table IDs "${entries[previousGeneratedName][0]}" and "${id}" generate the same physical name "${generatedName}"`,
522
+ path: [...path, "generatedName"],
523
+ relatedPaths: [[
524
+ "tables",
525
+ entries[previousGeneratedName][0],
526
+ "generatedName"
527
+ ]]
528
+ });
529
+ else generatedNames.set(generatedName, index);
530
+ }
531
+ if (namespace !== void 0 && !validNamespace(namespace)) diagnostics.push({
532
+ code: "invalid-namespace",
533
+ message: `Schema namespace "${namespace}" must be a non-empty identifier without qualification or control characters`,
534
+ path: ["namespace"]
535
+ });
536
+ return Object.freeze(diagnostics);
537
+ }
538
+ function freezeTableNames(entries, namingPolicy) {
539
+ return Object.freeze(Object.fromEntries(entries.map(([id, table]) => [id, table.tableName || namingPolicy.tableName(id)])));
540
+ }
541
+ function createSchema(entries, tables, options = {}) {
542
+ const namingPolicy = options.namingPolicy ?? defaultSchemaNamingPolicy;
543
+ const diagnostics = validateEntries(entries, options.namespace, namingPolicy);
544
+ if (diagnostics.length > 0) throw new SchemaValidationError(diagnostics);
545
+ const tableNames = freezeTableNames(entries, namingPolicy);
546
+ const registry = Object.freeze(Object.fromEntries(entries.map(([id, table]) => [id, Object.freeze({
547
+ id,
548
+ table,
549
+ physicalName: tableNames[id]
550
+ })])));
551
+ return Object.freeze({
552
+ schemaKind: "schema",
553
+ tables: Object.freeze({ ...tables }),
554
+ registry,
555
+ tableNames,
556
+ namespace: options.namespace,
557
+ namingPolicy: Object.freeze({ ...namingPolicy })
558
+ });
559
+ }
560
+ function schema(tables, options) {
561
+ const entries = entriesOf(tables);
562
+ return createSchema(entries, Object.fromEntries(entries), options);
563
+ }
564
+ /** Generate a v1 physical name for a logical table ID. */
565
+ function generatedTableName(logicalId, namingPolicy = defaultSchemaNamingPolicy) {
566
+ return namingPolicy.tableName(logicalId);
567
+ }
568
+ //#endregion
569
+ export { isValidSchemaObjectName as A, index as C, dialectMismatchDiagnostic as D, assertSchemaDialectSupport as E, materializeSchemaObjectRecord as M, freezeSchemaMetadata as O, unsafeSchemaSql as S, SchemaMetadataValidationError as T, isUnsafeSchemaSql as _, schemaNamingPolicyVersion as a, renderSchemaSql as b, check as c, references as d, unique as f, defineSchemaExpression as g, SchemaExpressionError as h, schema as i, materializeSchemaObjectIdentity as j, generatedSchemaObjectName as k, foreignKey as l, validateConstraintDialect as m, defaultSchemaNamingPolicy as n, catalogCheck as o, uniqueConstraint as p, generatedTableName as r, catalogForeignKey as s, SchemaValidationError as t, primaryKey as u, normalizeSchemaSql as v, validateIndexDialect as w, schemaExpression as x, renderSchemaExpression as y };
@@ -0,0 +1,77 @@
1
+ import { n as queryValidationError } from "./errors-Dxv73YJu.mjs";
2
+ import { l as makeSchemaExpression } from "./column-CXMxx8Hq.mjs";
3
+ import { n as isValueExpression, t as asValue } from "./value-BvilP0oz.mjs";
4
+ //#region src/expressions/operators/shared.ts
5
+ function isNullOperand(value) {
6
+ return value === null || isValueExpression(value) && value.value === null;
7
+ }
8
+ function expressionOperand(operand) {
9
+ return asValue(operand);
10
+ }
11
+ function renderOperands(context, operands, separator) {
12
+ operands.forEach((operand, index) => {
13
+ if (index > 0) context.append(separator);
14
+ context.render(operand);
15
+ });
16
+ }
17
+ //#endregion
18
+ //#region src/expressions/operators/comparison/relational.ts
19
+ function comparison(operator, left, right) {
20
+ if (isNullOperand(right)) {
21
+ if (operator === "=" || operator === "<>") {
22
+ const nullOperator = operator === "=" ? "IS NULL" : "IS NOT NULL";
23
+ return makeSchemaExpression("operator", (context) => {
24
+ context.append("(");
25
+ context.render(left);
26
+ context.append(` ${nullOperator})`);
27
+ });
28
+ }
29
+ if (operator !== "IS DISTINCT FROM" && operator !== "IS NOT DISTINCT FROM") throw queryValidationError({
30
+ code: "invalid-comparison",
31
+ context: "expression.comparison.null",
32
+ path: ["comparison", operator],
33
+ message: `Cannot compare NULL with ${operator}; use isNull(), isNotNull(), or a distinctness predicate`,
34
+ hint: "Use isNull(), isNotNull(), or a distinctness predicate for NULL comparisons."
35
+ });
36
+ }
37
+ const rightExpression = expressionOperand(right);
38
+ return makeSchemaExpression("operator", (context) => {
39
+ context.append("(");
40
+ context.render(left);
41
+ context.append(` ${operator} `);
42
+ context.render(rightExpression);
43
+ context.append(")");
44
+ });
45
+ }
46
+ function eq(left, right) {
47
+ return comparison("=", left, right);
48
+ }
49
+ function ne(left, right) {
50
+ return comparison("<>", left, right);
51
+ }
52
+ function lt(left, right) {
53
+ return comparison("<", left, right);
54
+ }
55
+ function lte(left, right) {
56
+ return comparison("<=", left, right);
57
+ }
58
+ function gt(left, right) {
59
+ return comparison(">", left, right);
60
+ }
61
+ function gte(left, right) {
62
+ return comparison(">=", left, right);
63
+ }
64
+ function like(left, pattern) {
65
+ return comparison("LIKE", left, pattern);
66
+ }
67
+ function notLike(left, pattern) {
68
+ return comparison("NOT LIKE", left, pattern);
69
+ }
70
+ function isDistinctFrom(left, right) {
71
+ return comparison("IS DISTINCT FROM", left, right);
72
+ }
73
+ function isNotDistinctFrom(left, right) {
74
+ return comparison("IS NOT DISTINCT FROM", left, right);
75
+ }
76
+ //#endregion
77
+ export { isDistinctFrom as a, lt as c, notLike as d, expressionOperand as f, gte as i, lte as l, renderOperands as m, eq as n, isNotDistinctFrom as o, isNullOperand as p, gt as r, like as s, comparison as t, ne as u };