effect-qb 0.12.3

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 (81) hide show
  1. package/README.md +1294 -0
  2. package/dist/mysql.js +57575 -0
  3. package/dist/postgres.js +6303 -0
  4. package/package.json +42 -0
  5. package/src/internal/aggregation-validation.ts +57 -0
  6. package/src/internal/case-analysis.ts +50 -0
  7. package/src/internal/coercion-analysis.ts +30 -0
  8. package/src/internal/coercion-errors.ts +29 -0
  9. package/src/internal/coercion-kind.ts +32 -0
  10. package/src/internal/coercion-normalize.ts +7 -0
  11. package/src/internal/coercion-rules.ts +25 -0
  12. package/src/internal/column-state.ts +453 -0
  13. package/src/internal/column.ts +417 -0
  14. package/src/internal/datatypes/define.ts +44 -0
  15. package/src/internal/datatypes/lookup.ts +280 -0
  16. package/src/internal/datatypes/shape.ts +72 -0
  17. package/src/internal/derived-table.ts +149 -0
  18. package/src/internal/dialect.ts +30 -0
  19. package/src/internal/executor.ts +390 -0
  20. package/src/internal/expression-ast.ts +349 -0
  21. package/src/internal/expression.ts +325 -0
  22. package/src/internal/grouping-key.ts +82 -0
  23. package/src/internal/json/ast.ts +63 -0
  24. package/src/internal/json/errors.ts +13 -0
  25. package/src/internal/json/path.ts +227 -0
  26. package/src/internal/json/shape.ts +1 -0
  27. package/src/internal/json/types.ts +386 -0
  28. package/src/internal/mysql-dialect.ts +39 -0
  29. package/src/internal/mysql-renderer.ts +37 -0
  30. package/src/internal/plan.ts +64 -0
  31. package/src/internal/postgres-dialect.ts +34 -0
  32. package/src/internal/postgres-renderer.ts +40 -0
  33. package/src/internal/predicate-analysis.ts +71 -0
  34. package/src/internal/predicate-atom.ts +43 -0
  35. package/src/internal/predicate-branches.ts +40 -0
  36. package/src/internal/predicate-context.ts +279 -0
  37. package/src/internal/predicate-formula.ts +100 -0
  38. package/src/internal/predicate-key.ts +28 -0
  39. package/src/internal/predicate-nnf.ts +12 -0
  40. package/src/internal/predicate-normalize.ts +202 -0
  41. package/src/internal/projection-alias.ts +15 -0
  42. package/src/internal/projections.ts +101 -0
  43. package/src/internal/query-ast.ts +297 -0
  44. package/src/internal/query-factory.ts +6757 -0
  45. package/src/internal/query-requirements.ts +40 -0
  46. package/src/internal/query.ts +1590 -0
  47. package/src/internal/renderer.ts +102 -0
  48. package/src/internal/runtime-normalize.ts +344 -0
  49. package/src/internal/runtime-schema.ts +428 -0
  50. package/src/internal/runtime-value.ts +85 -0
  51. package/src/internal/schema-derivation.ts +131 -0
  52. package/src/internal/sql-expression-renderer.ts +1353 -0
  53. package/src/internal/table-options.ts +225 -0
  54. package/src/internal/table.ts +674 -0
  55. package/src/mysql/column.ts +30 -0
  56. package/src/mysql/datatypes/index.ts +6 -0
  57. package/src/mysql/datatypes/spec.ts +180 -0
  58. package/src/mysql/errors/catalog.ts +51662 -0
  59. package/src/mysql/errors/fields.ts +21 -0
  60. package/src/mysql/errors/index.ts +18 -0
  61. package/src/mysql/errors/normalize.ts +232 -0
  62. package/src/mysql/errors/requirements.ts +73 -0
  63. package/src/mysql/executor.ts +134 -0
  64. package/src/mysql/query.ts +189 -0
  65. package/src/mysql/renderer.ts +19 -0
  66. package/src/mysql/table.ts +157 -0
  67. package/src/mysql.ts +18 -0
  68. package/src/postgres/column.ts +20 -0
  69. package/src/postgres/datatypes/index.ts +8 -0
  70. package/src/postgres/datatypes/spec.ts +264 -0
  71. package/src/postgres/errors/catalog.ts +452 -0
  72. package/src/postgres/errors/fields.ts +48 -0
  73. package/src/postgres/errors/index.ts +4 -0
  74. package/src/postgres/errors/normalize.ts +209 -0
  75. package/src/postgres/errors/requirements.ts +65 -0
  76. package/src/postgres/errors/types.ts +38 -0
  77. package/src/postgres/executor.ts +131 -0
  78. package/src/postgres/query.ts +189 -0
  79. package/src/postgres/renderer.ts +29 -0
  80. package/src/postgres/table.ts +157 -0
  81. package/src/postgres.ts +18 -0
@@ -0,0 +1,674 @@
1
+ import { pipeArguments, type Pipeable } from "effect/Pipeable"
2
+ import * as Schema from "effect/Schema"
3
+
4
+ import * as Plan from "./plan.js"
5
+ import type { BoundColumnFrom } from "./column-state.js"
6
+ import { bindColumn, type AnyColumnDefinition } from "./column-state.js"
7
+ import {
8
+ collectInlineOptions,
9
+ normalizeColumnList,
10
+ resolvePrimaryKeyColumns,
11
+ type DeclaredTableOptions as InternalDeclaredTableOptions,
12
+ type NormalizeColumns,
13
+ type TableOptionSpec,
14
+ type ValidateKnownColumns,
15
+ type ValidatePrimaryKeyColumns,
16
+ validateOptions
17
+ } from "./table-options.js"
18
+ import {
19
+ deriveSchemas,
20
+ type InsertRow,
21
+ type SelectRow,
22
+ type TableFieldMap,
23
+ type UpdateRow
24
+ } from "./schema-derivation.js"
25
+
26
+ /** Symbol used to attach table-definition metadata. */
27
+ export const TypeId: unique symbol = Symbol.for("effect-qb/Table")
28
+ /** Symbol for the normalized table option list. */
29
+ export const OptionsSymbol: unique symbol = Symbol.for("effect-qb/Table/normalizedOptions")
30
+ /** Symbol used by `Table.Class` to declare table-level options. */
31
+ export const options: unique symbol = Symbol.for("effect-qb/Table/declaredOptions")
32
+
33
+ const CacheSymbol: unique symbol = Symbol.for("effect-qb/Table/cache")
34
+ const DeclaredOptionsSymbol: unique symbol = Symbol.for("effect-qb/Table/factoryDeclaredOptions")
35
+
36
+ type InlinePrimaryKeyKeys<Fields extends TableFieldMap> = Extract<{
37
+ [K in keyof Fields]: Fields[K]["metadata"]["primaryKey"] extends true ? K : never
38
+ }[keyof Fields], string>
39
+
40
+ type TableDialect<Fields extends TableFieldMap> = Fields[keyof Fields][typeof import("./column-state.js").ColumnTypeId]["dbType"]["dialect"]
41
+ type TableKind = "schema" | "alias"
42
+ type DefaultSchemaName = "public"
43
+ type ClassOptionSpec = Exclude<TableOptionSpec, { readonly kind: "primaryKey" }>
44
+ type ClassTableOption = TableOption<ClassOptionSpec>
45
+ type ClassDeclaredTableOptions = readonly ClassTableOption[]
46
+
47
+ type BuildPrimaryKey<
48
+ Table extends TableDefinition<any, any, any, "schema", any>,
49
+ Spec extends TableOptionSpec
50
+ > = Spec extends { readonly kind: "primaryKey"; readonly columns: infer Columns extends readonly string[] }
51
+ ? Columns[number] & keyof Table[typeof TypeId]["fields"] & string
52
+ : Table[typeof TypeId]["primaryKey"][number]
53
+
54
+ type OptionInputTable<
55
+ Table extends TableDefinition<any, any, any, "schema", any>,
56
+ Spec extends TableOptionSpec
57
+ > = Spec extends { readonly kind: "primaryKey"; readonly columns: infer Columns extends readonly string[] }
58
+ ? ValidatePrimaryKeyColumns<Table[typeof TypeId]["fields"], Columns> extends never ? never : Table
59
+ : Spec extends { readonly columns: infer Columns extends readonly string[] }
60
+ ? ValidateKnownColumns<Table[typeof TypeId]["fields"], Columns> extends never ? never : Table
61
+ : Table
62
+
63
+ type ApplyOption<
64
+ Table extends TableDefinition<any, any, any, "schema", any>,
65
+ Spec extends TableOptionSpec
66
+ > = TableDefinition<
67
+ Table[typeof TypeId]["name"],
68
+ Table[typeof TypeId]["fields"],
69
+ BuildPrimaryKey<Table, Spec>,
70
+ "schema"
71
+ >
72
+
73
+ export type MissingSelfGeneric = "Missing `Self` generic - use `class Self extends Table.Class<Self>(...) {}`"
74
+
75
+ /** Bound columns keyed by field name for a particular table. */
76
+ export type BoundColumns<
77
+ Name extends string,
78
+ Fields extends TableFieldMap
79
+ > = {
80
+ readonly [K in keyof Fields]: BoundColumnFrom<Fields[K], Name, Extract<K, string>>
81
+ }
82
+
83
+ /** Derived runtime schemas exposed by a table definition. */
84
+ export interface TableSchemas<
85
+ Fields extends TableFieldMap,
86
+ PrimaryKeyColumns extends keyof Fields & string
87
+ > {
88
+ readonly select: Schema.Schema<SelectRow<Fields>>
89
+ readonly insert: Schema.Schema<InsertRow<Fields>>
90
+ readonly update: Schema.Schema<UpdateRow<Fields, PrimaryKeyColumns>>
91
+ }
92
+
93
+ interface TableState<
94
+ Name extends string,
95
+ Fields extends TableFieldMap,
96
+ PrimaryKeyColumns extends keyof Fields & string,
97
+ Kind extends TableKind = "schema",
98
+ SchemaName extends string | undefined = DefaultSchemaName
99
+ > {
100
+ readonly name: Name
101
+ readonly baseName: string
102
+ readonly schemaName: SchemaName
103
+ readonly fields: Fields
104
+ readonly primaryKey: readonly PrimaryKeyColumns[]
105
+ readonly kind: Kind
106
+ }
107
+
108
+ /** Namespace-scoped table builder. */
109
+ export interface TableSchemaNamespace<SchemaName extends string> {
110
+ readonly schemaName: SchemaName
111
+ readonly table: <
112
+ Name extends string,
113
+ Fields extends TableFieldMap,
114
+ PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>
115
+ >(
116
+ name: Name,
117
+ fields: Fields,
118
+ ...options: InternalDeclaredTableOptions
119
+ ) => TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>
120
+ }
121
+
122
+ export type DeclaredTableOptions = InternalDeclaredTableOptions
123
+
124
+ export type TableDefinition<
125
+ Name extends string,
126
+ Fields extends TableFieldMap,
127
+ PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>,
128
+ Kind extends TableKind = "schema",
129
+ SchemaName extends string | undefined = DefaultSchemaName
130
+ > = Pipeable & {
131
+ readonly name: Name
132
+ readonly columns: BoundColumns<Name, Fields>
133
+ readonly schemas: TableSchemas<Fields, PrimaryKeyColumns>
134
+ readonly [TypeId]: TableState<Name, Fields, PrimaryKeyColumns, Kind, SchemaName>
135
+ readonly [Plan.TypeId]: Plan.State<
136
+ BoundColumns<Name, Fields>,
137
+ never,
138
+ Record<Name, Plan.Source<Name>>,
139
+ TableDialect<Fields>
140
+ >
141
+ readonly [OptionsSymbol]: readonly TableOptionSpec[]
142
+ readonly [DeclaredOptionsSymbol]: readonly TableOptionSpec[]
143
+ } & BoundColumns<Name, Fields> & Plan.Plan<
144
+ BoundColumns<Name, Fields>,
145
+ never,
146
+ Record<Name, Plan.Source<Name>>,
147
+ TableDialect<Fields>
148
+ >
149
+
150
+ /**
151
+ * Static class-based table definition.
152
+ *
153
+ * The class object itself acts as the table definition, exposing static bound
154
+ * columns, derived schemas, and plan metadata.
155
+ */
156
+ export type TableClassStatic<
157
+ Name extends string,
158
+ Fields extends TableFieldMap,
159
+ PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>,
160
+ SchemaName extends string | undefined = DefaultSchemaName
161
+ > = (abstract new (...args: any[]) => any) & Pipeable & {
162
+ readonly columns: BoundColumns<Name, Fields>
163
+ readonly schemas: TableSchemas<Fields, PrimaryKeyColumns>
164
+ readonly [TypeId]: TableState<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>
165
+ readonly [Plan.TypeId]: Plan.State<
166
+ BoundColumns<Name, Fields>,
167
+ never,
168
+ Record<Name, Plan.Source<Name>>,
169
+ TableDialect<Fields>
170
+ >
171
+ readonly [OptionsSymbol]: readonly TableOptionSpec[]
172
+ readonly [DeclaredOptionsSymbol]?: readonly TableOptionSpec[]
173
+ readonly [options]?: ClassDeclaredTableOptions
174
+ readonly tableName: Name
175
+ } & BoundColumns<Name, Fields> & Plan.Plan<
176
+ BoundColumns<Name, Fields>,
177
+ never,
178
+ Record<Name, Plan.Source<Name>>,
179
+ TableDialect<Fields>
180
+ >
181
+
182
+ /** Minimal structural table-like contract used across helper APIs. */
183
+ export type AnyTable = TableDefinition<any, any, any, any, any> | TableClassStatic<any, any, any, any>
184
+
185
+ /** Public table-option builder type used by `Table.index`, `Table.primaryKey`, and friends. */
186
+ export type TableOption<
187
+ Spec extends TableOptionSpec = TableOptionSpec
188
+ > = {
189
+ <
190
+ Name extends string,
191
+ Fields extends TableFieldMap,
192
+ PrimaryKeyColumns extends keyof Fields & string
193
+ >(
194
+ table: OptionInputTable<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", any>, Spec>
195
+ ): ApplyOption<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", any>, Spec>
196
+ readonly option: Spec
197
+ }
198
+
199
+ const TableProto = {
200
+ pipe(this: unknown) {
201
+ return pipeArguments(this, arguments)
202
+ }
203
+ }
204
+
205
+ type BuildArtifacts<
206
+ Name extends string,
207
+ Fields extends TableFieldMap,
208
+ PrimaryKeyColumns extends keyof Fields & string
209
+ > = {
210
+ readonly columns: BoundColumns<Name, Fields>
211
+ readonly schemas: TableSchemas<Fields, PrimaryKeyColumns>
212
+ readonly normalizedOptions: readonly TableOptionSpec[]
213
+ readonly primaryKey: readonly PrimaryKeyColumns[]
214
+ }
215
+
216
+ const buildArtifacts = <
217
+ Name extends string,
218
+ Fields extends TableFieldMap,
219
+ SchemaName extends string | undefined
220
+ >(
221
+ name: Name,
222
+ fields: Fields,
223
+ declaredOptions: readonly TableOptionSpec[],
224
+ schemaName: SchemaName
225
+ ): BuildArtifacts<Name, Fields, keyof Fields & string> => {
226
+ const normalizedOptions = [...collectInlineOptions(fields), ...declaredOptions]
227
+ validateFieldDialects(name, fields)
228
+ validateOptions(name, fields, declaredOptions)
229
+ const primaryKey = resolvePrimaryKeyColumns(fields, declaredOptions) as readonly (keyof Fields & string)[]
230
+ const columns = Object.fromEntries(
231
+ Object.entries(fields).map(([key, column]) => [key, bindColumn(name, key, column, name, schemaName)])
232
+ ) as BoundColumns<Name, Fields>
233
+ const schemas = deriveSchemas(fields, primaryKey)
234
+ return {
235
+ columns,
236
+ schemas,
237
+ normalizedOptions,
238
+ primaryKey
239
+ }
240
+ }
241
+
242
+ const makeTable = <
243
+ Name extends string,
244
+ Fields extends TableFieldMap,
245
+ PrimaryKeyColumns extends keyof Fields & string,
246
+ Kind extends TableKind = "schema",
247
+ SchemaName extends string | undefined = DefaultSchemaName
248
+ >(
249
+ name: Name,
250
+ fields: Fields,
251
+ declaredOptions: readonly TableOptionSpec[],
252
+ baseName: string = name,
253
+ kind: Kind = "schema" as Kind,
254
+ schemaName?: SchemaName,
255
+ schemaMode: "default" | "explicit" = "default"
256
+ ): TableDefinition<Name, Fields, PrimaryKeyColumns, Kind, SchemaName> => {
257
+ const resolvedSchemaName = schemaMode === "explicit"
258
+ ? schemaName
259
+ : ("public" as SchemaName)
260
+ const artifacts = buildArtifacts(name, fields, declaredOptions, resolvedSchemaName)
261
+ const dialect = resolveFieldDialect(fields)
262
+ const table = Object.create(TableProto)
263
+ table.name = name
264
+ table.columns = artifacts.columns
265
+ table.schemas = artifacts.schemas
266
+ table[TypeId] = {
267
+ name,
268
+ baseName,
269
+ schemaName: resolvedSchemaName,
270
+ fields,
271
+ primaryKey: artifacts.primaryKey,
272
+ kind
273
+ }
274
+ table[Plan.TypeId] = {
275
+ selection: artifacts.columns,
276
+ required: undefined as never,
277
+ available: {
278
+ [name]: {
279
+ name,
280
+ mode: "required",
281
+ baseName
282
+ }
283
+ },
284
+ dialect
285
+ }
286
+ table[OptionsSymbol] = artifacts.normalizedOptions
287
+ table[DeclaredOptionsSymbol] = declaredOptions
288
+ for (const [key, value] of Object.entries(artifacts.columns)) {
289
+ Object.defineProperty(table, key, {
290
+ enumerable: true,
291
+ value
292
+ })
293
+ }
294
+ return table
295
+ }
296
+
297
+ const extractDeclaredOptions = (
298
+ declaredOptions: DeclaredTableOptions | undefined
299
+ ): readonly TableOptionSpec[] => declaredOptions?.map((option) => option.option) ?? []
300
+
301
+ const validateClassOptions = (declaredOptions: readonly TableOptionSpec[]): void => {
302
+ for (const option of declaredOptions) {
303
+ if (option.kind === "primaryKey") {
304
+ throw new Error("Table.Class does not support table-level primary keys; declare primary keys inline on columns")
305
+ }
306
+ }
307
+ }
308
+
309
+ const resolveFieldDialect = (fields: TableFieldMap): string => {
310
+ const dialects = [...new Set(Object.values(fields).map((field) => field.metadata.dbType.dialect))]
311
+ if (dialects.length === 0) {
312
+ return "postgres"
313
+ }
314
+ if (dialects.length > 1) {
315
+ throw new Error(`Mixed table dialects are not supported: ${dialects.join(", ")}`)
316
+ }
317
+ return dialects[0]!
318
+ }
319
+
320
+ const validateFieldDialects = (tableName: string, fields: TableFieldMap): void => {
321
+ try {
322
+ resolveFieldDialect(fields)
323
+ } catch (error) {
324
+ throw new Error(`Invalid dialects for table '${tableName}': ${(error as Error).message}`)
325
+ }
326
+ }
327
+
328
+ const ensureClassArtifacts = <
329
+ Name extends string,
330
+ Fields extends TableFieldMap,
331
+ PrimaryKeyColumns extends keyof Fields & string
332
+ >(
333
+ self: TableClassStatic<Name, Fields, PrimaryKeyColumns> & {
334
+ readonly [CacheSymbol]?: BuildArtifacts<Name, Fields, PrimaryKeyColumns>
335
+ }
336
+ ): BuildArtifacts<Name, Fields, PrimaryKeyColumns> => {
337
+ const cached = self[CacheSymbol]
338
+ if (cached) {
339
+ return cached
340
+ }
341
+ const state = self[TypeId]
342
+ const declaredOptions = extractDeclaredOptions(self[options])
343
+ validateClassOptions(declaredOptions)
344
+ const artifacts = buildArtifacts(
345
+ state.name,
346
+ state.fields,
347
+ declaredOptions,
348
+ state.schemaName
349
+ ) as BuildArtifacts<Name, Fields, PrimaryKeyColumns>
350
+ Object.defineProperty(self, CacheSymbol, {
351
+ configurable: true,
352
+ value: artifacts
353
+ })
354
+ return artifacts
355
+ }
356
+
357
+ const appendOption = <
358
+ Table extends TableDefinition<any, any, any, "schema", any>,
359
+ Spec extends TableOptionSpec
360
+ >(
361
+ table: Table,
362
+ option: Spec
363
+ ): ApplyOption<Table, Spec> => {
364
+ const state = table[TypeId]
365
+ if (state.kind !== "schema") {
366
+ throw new Error("Table options can only be applied to schema tables, not aliased query sources")
367
+ }
368
+ return makeTable(
369
+ state.name,
370
+ state.fields,
371
+ [...table[DeclaredOptionsSymbol], option],
372
+ state.baseName,
373
+ state.kind,
374
+ state.schemaName,
375
+ "explicit"
376
+ ) as unknown as ApplyOption<Table, Spec>
377
+ }
378
+
379
+ const makeOption = <Spec extends TableOptionSpec>(option: Spec): TableOption<Spec> => {
380
+ const builder = ((table: TableDefinition<any, any, any, "schema", any>) =>
381
+ appendOption(table, option)) as unknown as TableOption<Spec>
382
+ ;(builder as { option: Spec }).option = option
383
+ return builder
384
+ }
385
+
386
+ /** Creates a table definition from a name and field map. */
387
+ export function make<
388
+ Name extends string,
389
+ Fields extends TableFieldMap,
390
+ SchemaName extends string | undefined = DefaultSchemaName
391
+ >(
392
+ name: Name,
393
+ fields: Fields,
394
+ schemaName?: SchemaName
395
+ ): TableDefinition<Name, Fields, InlinePrimaryKeyKeys<Fields>, "schema", SchemaName> {
396
+ const resolvedSchemaName = arguments.length >= 3
397
+ ? schemaName
398
+ : ("public" as SchemaName)
399
+ return makeTable(
400
+ name,
401
+ fields,
402
+ [],
403
+ name,
404
+ "schema",
405
+ resolvedSchemaName,
406
+ arguments.length >= 3 ? "explicit" : "default"
407
+ )
408
+ }
409
+
410
+ /**
411
+ * Creates a namespace-scoped builder for a concrete SQL schema/database.
412
+ */
413
+ export const schema = <SchemaName extends string>(
414
+ schemaName: SchemaName
415
+ ): TableSchemaNamespace<SchemaName> => ({
416
+ schemaName,
417
+ table: <
418
+ Name extends string,
419
+ Fields extends TableFieldMap,
420
+ PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>
421
+ >(
422
+ name: Name,
423
+ fields: Fields,
424
+ ...options: InternalDeclaredTableOptions
425
+ ): TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName> =>
426
+ makeTable(
427
+ name,
428
+ fields,
429
+ extractDeclaredOptions(options),
430
+ name,
431
+ "schema",
432
+ schemaName,
433
+ "explicit"
434
+ ) as TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>
435
+ })
436
+
437
+ /**
438
+ * Creates an aliased source from an existing table definition.
439
+ *
440
+ * The alias becomes the logical source identity used by the query layer while
441
+ * the original physical table name is retained in bound-column provenance for
442
+ * downstream SQL rendering work.
443
+ */
444
+ export const alias = <
445
+ Name extends string,
446
+ Fields extends TableFieldMap,
447
+ PrimaryKeyColumns extends keyof Fields & string,
448
+ SchemaName extends string,
449
+ AliasName extends string
450
+ >(
451
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, SchemaName> | TableClassStatic<Name, Fields, PrimaryKeyColumns, SchemaName>,
452
+ aliasName: AliasName
453
+ ): TableDefinition<
454
+ AliasName,
455
+ Fields,
456
+ PrimaryKeyColumns,
457
+ "alias",
458
+ SchemaName
459
+ > => {
460
+ const state = table[TypeId]
461
+ const columns = Object.fromEntries(
462
+ Object.entries(state.fields).map(([key, column]) => [key, bindColumn(aliasName, key, column as AnyColumnDefinition, state.baseName, state.schemaName)])
463
+ ) as BoundColumns<AliasName, Fields>
464
+ const aliased = Object.create(TableProto)
465
+ aliased.name = aliasName
466
+ aliased.columns = columns
467
+ aliased.schemas = table.schemas
468
+ aliased[TypeId] = {
469
+ name: aliasName,
470
+ baseName: state.baseName,
471
+ schemaName: state.schemaName,
472
+ fields: state.fields,
473
+ primaryKey: state.primaryKey,
474
+ kind: "alias"
475
+ }
476
+ aliased[Plan.TypeId] = {
477
+ selection: columns,
478
+ required: undefined as never,
479
+ available: {
480
+ [aliasName]: {
481
+ name: aliasName,
482
+ mode: "required",
483
+ baseName: state.baseName
484
+ }
485
+ },
486
+ dialect: table[Plan.TypeId].dialect
487
+ }
488
+ aliased[OptionsSymbol] = table[OptionsSymbol]
489
+ aliased[DeclaredOptionsSymbol] = table[DeclaredOptionsSymbol]
490
+ for (const [key, value] of Object.entries(columns)) {
491
+ Object.defineProperty(aliased, key, {
492
+ enumerable: true,
493
+ value
494
+ })
495
+ }
496
+ return aliased
497
+ }
498
+
499
+ /**
500
+ * Class-based table constructor mirroring `Schema.Class`.
501
+ *
502
+ * The returned base class can be extended and configured with
503
+ * `static readonly [Table.options]`.
504
+ */
505
+ export function Class<
506
+ Self = never,
507
+ SchemaName extends string | undefined = DefaultSchemaName
508
+ >(
509
+ name: string,
510
+ schemaName?: SchemaName
511
+ ) {
512
+ const resolvedSchemaName = arguments.length >= 2
513
+ ? schemaName
514
+ : ("public" as SchemaName)
515
+ return <Fields extends TableFieldMap>(fields: Fields): [Self] extends [never]
516
+ ? MissingSelfGeneric
517
+ : TableClassStatic<typeof name, Fields, InlinePrimaryKeyKeys<Fields>, SchemaName> => {
518
+ abstract class TableClassBase {
519
+ static readonly tableName = name
520
+
521
+ static get columns() {
522
+ return ensureClassArtifacts(this as any).columns
523
+ }
524
+
525
+ static get schemas() {
526
+ return ensureClassArtifacts(this as any).schemas
527
+ }
528
+
529
+ static get [TypeId]() {
530
+ const declaredOptions = extractDeclaredOptions((this as unknown as TableClassStatic<typeof name, Fields>)[options])
531
+ validateClassOptions(declaredOptions)
532
+ return {
533
+ name,
534
+ baseName: name,
535
+ schemaName: resolvedSchemaName,
536
+ fields,
537
+ primaryKey: resolvePrimaryKeyColumns(fields, collectInlineOptions(fields)),
538
+ kind: "schema"
539
+ }
540
+ }
541
+
542
+ static get [Plan.TypeId]() {
543
+ const artifacts = ensureClassArtifacts(this as any)
544
+ return {
545
+ selection: artifacts.columns,
546
+ required: undefined as never,
547
+ available: {
548
+ [name]: {
549
+ name,
550
+ mode: "required",
551
+ baseName: name
552
+ }
553
+ },
554
+ dialect: resolveFieldDialect(fields)
555
+ }
556
+ }
557
+
558
+ static get [OptionsSymbol]() {
559
+ return ensureClassArtifacts(this as any).normalizedOptions
560
+ }
561
+
562
+ static pipe(this: unknown) {
563
+ return pipeArguments(this, arguments)
564
+ }
565
+ }
566
+
567
+ for (const key of Object.keys(fields)) {
568
+ Object.defineProperty(TableClassBase, key, {
569
+ enumerable: true,
570
+ configurable: true,
571
+ get() {
572
+ return (ensureClassArtifacts(this as any).columns as unknown as Record<string, AnyColumnDefinition>)[key]
573
+ }
574
+ })
575
+ }
576
+
577
+ return TableClassBase as any
578
+ }
579
+ }
580
+
581
+ /** Declares a table-level primary key. */
582
+ export const primaryKey = <
583
+ Columns extends string | readonly string[]
584
+ >(
585
+ columns: Columns
586
+ ): TableOption<{
587
+ readonly kind: "primaryKey"
588
+ readonly columns: NormalizeColumns<Columns>
589
+ }> => makeOption({
590
+ kind: "primaryKey",
591
+ columns: normalizeColumnList(columns) as NormalizeColumns<Columns>
592
+ })
593
+
594
+ /** Declares a table-level unique constraint. */
595
+ export const unique = <
596
+ Columns extends string | readonly string[]
597
+ >(
598
+ columns: Columns
599
+ ): TableOption<{
600
+ readonly kind: "unique"
601
+ readonly columns: NormalizeColumns<Columns>
602
+ }> => makeOption({
603
+ kind: "unique",
604
+ columns: normalizeColumnList(columns) as NormalizeColumns<Columns>
605
+ })
606
+
607
+ /** Declares a table-level index. */
608
+ export const index = <
609
+ Columns extends string | readonly string[]
610
+ >(
611
+ columns: Columns
612
+ ): TableOption<{
613
+ readonly kind: "index"
614
+ readonly columns: NormalizeColumns<Columns>
615
+ }> => makeOption({
616
+ kind: "index",
617
+ columns: normalizeColumnList(columns) as NormalizeColumns<Columns>
618
+ })
619
+
620
+ /** Declares a table-level foreign key. */
621
+ export const foreignKey = <
622
+ LocalColumns extends string | readonly string[],
623
+ TargetTable extends AnyTable,
624
+ TargetColumns extends string | readonly string[]
625
+ >(
626
+ columns: LocalColumns,
627
+ target: () => TargetTable,
628
+ referencedColumns: TargetColumns
629
+ ): TableOption<{
630
+ readonly kind: "foreignKey"
631
+ readonly columns: NormalizeColumns<LocalColumns>
632
+ readonly references: () => {
633
+ readonly tableName: string
634
+ readonly schemaName?: string
635
+ readonly columns: NormalizeColumns<TargetColumns>
636
+ readonly knownColumns: readonly string[]
637
+ }
638
+ }> => makeOption({
639
+ kind: "foreignKey",
640
+ columns: normalizeColumnList(columns) as NormalizeColumns<LocalColumns>,
641
+ references: () => ({
642
+ tableName: target()[TypeId].baseName,
643
+ schemaName: target()[TypeId].schemaName,
644
+ columns: normalizeColumnList(referencedColumns) as NormalizeColumns<TargetColumns>,
645
+ knownColumns: Object.keys(target()[TypeId].fields)
646
+ })
647
+ })
648
+
649
+ /** Declares a metadata-only check constraint placeholder. */
650
+ export const check = <Name extends string>(
651
+ name: Name,
652
+ predicate: unknown
653
+ ): TableOption<{
654
+ readonly kind: "check"
655
+ readonly name: Name
656
+ readonly predicate: unknown
657
+ }> => makeOption({
658
+ kind: "check",
659
+ name,
660
+ predicate
661
+ })
662
+
663
+ /** Extracts the row type of a table's select schema. */
664
+ export type SelectOf<Table extends { readonly schemas: { readonly select: Schema.Schema<any> } }> = Schema.Schema.Type<
665
+ Table["schemas"]["select"]
666
+ >
667
+ /** Extracts the payload type of a table's insert schema. */
668
+ export type InsertOf<Table extends { readonly schemas: { readonly insert: Schema.Schema<any> } }> = Schema.Schema.Type<
669
+ Table["schemas"]["insert"]
670
+ >
671
+ /** Extracts the payload type of a table's update schema. */
672
+ export type UpdateOf<Table extends { readonly schemas: { readonly update: Schema.Schema<any> } }> = Schema.Schema.Type<
673
+ Table["schemas"]["update"]
674
+ >
@@ -0,0 +1,30 @@
1
+ import * as BaseColumn from "../internal/column.js"
2
+ import * as Expression from "../internal/expression.js"
3
+ import { LocalDateTimeStringSchema } from "../internal/runtime-value.js"
4
+
5
+ /** MySQL-specialized column-definition DSL. */
6
+ export const uuid = BaseColumn.mysql.uuid
7
+ export const text = BaseColumn.mysql.text
8
+ export const int = BaseColumn.mysql.int
9
+ export const number = BaseColumn.mysql.number
10
+ export const boolean = BaseColumn.mysql.boolean
11
+ export const date = BaseColumn.mysql.date
12
+ export const datetime = () =>
13
+ BaseColumn.mysql.custom(
14
+ LocalDateTimeStringSchema,
15
+ { dialect: "mysql", kind: "datetime" } as Expression.DbType.MySqlDatetime
16
+ )
17
+ export const timestamp = BaseColumn.mysql.timestamp
18
+ export const json = BaseColumn.mysql.json
19
+ export const custom = BaseColumn.mysql.custom
20
+
21
+ export const nullable = BaseColumn.nullable
22
+ export const primaryKey = BaseColumn.primaryKey
23
+ export const unique = BaseColumn.unique
24
+ export const hasDefault = BaseColumn.hasDefault
25
+ export const generated = BaseColumn.generated
26
+ export const references = BaseColumn.references
27
+ export const schema = BaseColumn.schema
28
+
29
+ export type Any = BaseColumn.Any
30
+ export type AnyBound = BaseColumn.AnyBound
@@ -0,0 +1,6 @@
1
+ import { makeDatatypeModule } from "../../internal/datatypes/define.js"
2
+ import { mysqlDatatypeKinds } from "./spec.js"
3
+
4
+ export const mysqlDatatypes = makeDatatypeModule("mysql", mysqlDatatypeKinds)
5
+
6
+ export type MysqlDatatypeModule = typeof mysqlDatatypes