effect-qb 0.16.0 → 4.0.0-beta.66

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 (88) hide show
  1. package/README.md +7 -0
  2. package/dist/mysql.js +1858 -715
  3. package/dist/postgres/metadata.js +2036 -172
  4. package/dist/postgres.js +8011 -6849
  5. package/dist/sqlite.js +8433 -0
  6. package/package.json +7 -4
  7. package/src/internal/column-state.d.ts +3 -3
  8. package/src/internal/column-state.ts +3 -3
  9. package/src/internal/column.ts +8 -8
  10. package/src/internal/derived-table.ts +29 -3
  11. package/src/internal/dialect.ts +3 -1
  12. package/src/internal/dsl-mutation-runtime.ts +173 -4
  13. package/src/internal/dsl-plan-runtime.ts +165 -20
  14. package/src/internal/dsl-query-runtime.ts +60 -6
  15. package/src/internal/dsl-transaction-ddl-runtime.ts +72 -2
  16. package/src/internal/executor.ts +100 -43
  17. package/src/internal/expression-ast.ts +3 -2
  18. package/src/internal/grouping-key.ts +141 -1
  19. package/src/internal/implication-runtime.ts +2 -1
  20. package/src/internal/json/types.ts +155 -40
  21. package/src/internal/predicate/context.ts +14 -1
  22. package/src/internal/predicate/key.ts +19 -2
  23. package/src/internal/predicate/runtime.ts +27 -3
  24. package/src/internal/query.d.ts +1 -1
  25. package/src/internal/query.ts +253 -31
  26. package/src/internal/renderer.ts +35 -2
  27. package/src/internal/runtime/driver-value-mapping.ts +60 -2
  28. package/src/internal/runtime/normalize.ts +62 -38
  29. package/src/internal/runtime/schema.ts +32 -40
  30. package/src/internal/runtime/value.ts +159 -39
  31. package/src/internal/scalar.d.ts +1 -1
  32. package/src/internal/scalar.ts +1 -1
  33. package/src/internal/schema-derivation.d.ts +12 -61
  34. package/src/internal/schema-derivation.ts +95 -43
  35. package/src/internal/table-options.ts +108 -1
  36. package/src/internal/table.d.ts +29 -22
  37. package/src/internal/table.ts +260 -53
  38. package/src/mysql/column.ts +24 -8
  39. package/src/mysql/datatypes/index.ts +21 -0
  40. package/src/mysql/errors/catalog.ts +5 -5
  41. package/src/mysql/errors/normalize.ts +2 -2
  42. package/src/mysql/executor.ts +4 -4
  43. package/src/mysql/function/temporal.ts +1 -1
  44. package/src/mysql/internal/dsl.ts +759 -235
  45. package/src/mysql/internal/renderer.ts +2 -1
  46. package/src/mysql/internal/sql-expression-renderer.ts +486 -130
  47. package/src/mysql/query.ts +9 -2
  48. package/src/mysql/table.ts +64 -35
  49. package/src/postgres/column.ts +14 -12
  50. package/src/postgres/errors/normalize.ts +2 -2
  51. package/src/postgres/executor.ts +52 -9
  52. package/src/postgres/function/core.ts +19 -1
  53. package/src/postgres/function/temporal.ts +1 -1
  54. package/src/postgres/internal/dsl.ts +705 -256
  55. package/src/postgres/internal/renderer.ts +2 -1
  56. package/src/postgres/internal/schema-ddl.ts +2 -1
  57. package/src/postgres/internal/schema-model.ts +6 -3
  58. package/src/postgres/internal/sql-expression-renderer.ts +420 -91
  59. package/src/postgres/json.ts +57 -17
  60. package/src/postgres/query.ts +9 -2
  61. package/src/postgres/schema-management.ts +92 -6
  62. package/src/postgres/schema.ts +1 -1
  63. package/src/postgres/table.ts +203 -75
  64. package/src/sqlite/column.ts +128 -0
  65. package/src/sqlite/datatypes/index.ts +79 -0
  66. package/src/sqlite/datatypes/spec.ts +98 -0
  67. package/src/sqlite/errors/catalog.ts +103 -0
  68. package/src/sqlite/errors/fields.ts +19 -0
  69. package/src/sqlite/errors/index.ts +19 -0
  70. package/src/sqlite/errors/normalize.ts +229 -0
  71. package/src/sqlite/errors/requirements.ts +71 -0
  72. package/src/sqlite/errors/types.ts +29 -0
  73. package/src/sqlite/executor.ts +227 -0
  74. package/src/sqlite/function/aggregate.ts +2 -0
  75. package/src/sqlite/function/core.ts +2 -0
  76. package/src/sqlite/function/index.ts +19 -0
  77. package/src/sqlite/function/string.ts +2 -0
  78. package/src/sqlite/function/temporal.ts +100 -0
  79. package/src/sqlite/function/window.ts +2 -0
  80. package/src/sqlite/internal/dialect.ts +37 -0
  81. package/src/sqlite/internal/dsl.ts +6927 -0
  82. package/src/sqlite/internal/renderer.ts +47 -0
  83. package/src/sqlite/internal/sql-expression-renderer.ts +1821 -0
  84. package/src/sqlite/json.ts +2 -0
  85. package/src/sqlite/query.ts +196 -0
  86. package/src/sqlite/renderer.ts +24 -0
  87. package/src/sqlite/table.ts +175 -0
  88. package/src/sqlite.ts +22 -0
@@ -12,18 +12,25 @@ import {
12
12
  resolvePrimaryKeyColumns,
13
13
  type DdlExpressionLike,
14
14
  type IndexKeySpec,
15
+ type MatchingColumnArityInput,
16
+ type NonEmptyColumnInput,
15
17
  type NormalizeColumns,
16
18
  type ReferentialAction,
17
19
  type TableOptionSpec,
20
+ type ValidateForeignKeyOptionColumns,
21
+ type ValidateIndexOptionColumns,
18
22
  type ValidateKnownColumns,
19
23
  type ValidatePrimaryKeyColumns,
20
24
  validateOptions
21
25
  } from "./table-options.js"
22
26
  import {
23
- deriveSchemas,
27
+ deriveInsertSchema,
28
+ deriveSelectSchema,
29
+ deriveUpdateSchema,
24
30
  type InsertRow,
25
31
  type SelectRow,
26
32
  type TableFieldMap,
33
+ type TableSchemaVariant,
27
34
  type UpdateRow
28
35
  } from "./schema-derivation.js"
29
36
 
@@ -35,6 +42,7 @@ export const OptionsSymbol: unique symbol = Symbol.for("effect-qb/Table/normaliz
35
42
  export const options: unique symbol = Symbol.for("effect-qb/Table/declaredOptions")
36
43
 
37
44
  const CacheSymbol: unique symbol = Symbol.for("effect-qb/Table/cache")
45
+ const SchemaCacheSymbol: unique symbol = Symbol.for("effect-qb/Table/schemaCache")
38
46
  const DeclaredOptionsSymbol: unique symbol = Symbol.for("effect-qb/Table/factoryDeclaredOptions")
39
47
 
40
48
  type InlinePrimaryKeyKeys<Fields extends TableFieldMap> = Extract<{
@@ -44,18 +52,32 @@ type InlinePrimaryKeyKeys<Fields extends TableFieldMap> = Extract<{
44
52
  type TableDialect<Fields extends TableFieldMap> = Fields[keyof Fields][typeof import("./column-state.js").ColumnTypeId]["dbType"]["dialect"]
45
53
  type TableKind = "schema" | "alias"
46
54
  type DefaultSchemaName = "public"
47
- type ClassOptionSpec = Exclude<TableOptionSpec, { readonly kind: "primaryKey" }>
55
+ type FieldColumnName<Fields extends TableFieldMap> = Extract<keyof Fields, string>
56
+ type FieldColumnList<Fields extends TableFieldMap> = readonly [FieldColumnName<Fields>, ...FieldColumnName<Fields>[]]
57
+ type FieldIndexKeySpec<Fields extends TableFieldMap> =
58
+ | (Extract<IndexKeySpec, { readonly kind: "column" }> & { readonly column: FieldColumnName<Fields> })
59
+ | Extract<IndexKeySpec, { readonly kind: "expression" }>
60
+ type ClassOptionSpec<Fields extends TableFieldMap = TableFieldMap> =
61
+ | (Omit<Extract<TableOptionSpec, { readonly kind: "index" }>, "columns" | "include" | "keys"> & {
62
+ readonly columns?: FieldColumnList<Fields>
63
+ readonly include?: readonly FieldColumnName<Fields>[]
64
+ readonly keys?: readonly [FieldIndexKeySpec<Fields>, ...FieldIndexKeySpec<Fields>[]]
65
+ })
66
+ | (Omit<Extract<TableOptionSpec, { readonly kind: "unique" }>, "columns"> & {
67
+ readonly columns: FieldColumnList<Fields>
68
+ })
69
+ | (Omit<Extract<TableOptionSpec, { readonly kind: "foreignKey" }>, "columns"> & {
70
+ readonly columns: FieldColumnList<Fields>
71
+ })
72
+ | Extract<TableOptionSpec, { readonly kind: "check" }>
48
73
  interface TableOptionBuilderLike<
49
74
  Spec extends TableOptionSpec = TableOptionSpec
50
75
  > {
51
- (
52
- table: TableDefinition<any, any, any, "schema", any>
53
- ): TableDefinition<any, any, any, "schema", any>
54
76
  readonly option: Spec
55
77
  }
56
78
 
57
- type ClassTableOption = TableOptionBuilderLike<ClassOptionSpec>
58
- type ClassDeclaredTableOptions = readonly ClassTableOption[]
79
+ type ClassTableOption<Fields extends TableFieldMap> = TableOptionBuilderLike<ClassOptionSpec<Fields>>
80
+ type ClassDeclaredTableOptions<Fields extends TableFieldMap> = readonly ClassTableOption<Fields>[]
59
81
 
60
82
  type BuildPrimaryKey<
61
83
  Table extends TableDefinition<any, any, any, "schema", any>,
@@ -69,9 +91,13 @@ type OptionInputTable<
69
91
  Spec extends TableOptionSpec
70
92
  > = Spec extends { readonly kind: "primaryKey"; readonly columns: infer Columns extends readonly string[] }
71
93
  ? ValidatePrimaryKeyColumns<Table[typeof TypeId]["fields"], Columns> extends never ? never : Table
72
- : Spec extends { readonly columns: infer Columns extends readonly string[] }
73
- ? ValidateKnownColumns<Table[typeof TypeId]["fields"], Columns> extends never ? never : Table
74
- : Table
94
+ : Spec extends { readonly kind: "index" }
95
+ ? ValidateIndexOptionColumns<Table[typeof TypeId]["fields"], Spec> extends never ? never : Table
96
+ : Spec extends { readonly kind: "foreignKey" }
97
+ ? ValidateForeignKeyOptionColumns<Table[typeof TypeId]["fields"], Spec> extends never ? never : Table
98
+ : Spec extends { readonly columns: infer Columns extends readonly string[] }
99
+ ? ValidateKnownColumns<Table[typeof TypeId]["fields"], Columns> extends never ? never : Table
100
+ : Table
75
101
 
76
102
  type ApplyOption<
77
103
  Table extends TableDefinition<any, any, any, "schema", any>,
@@ -90,6 +116,26 @@ type ApplyOption<
90
116
  "schema"
91
117
  >
92
118
 
119
+ export type ValidateDeclaredOptions<
120
+ Table extends TableDefinition<any, any, any, "schema", any>,
121
+ Options extends DeclaredTableOptions
122
+ > = {
123
+ readonly [K in keyof Options]: Options[K] extends TableOptionBuilderLike<infer Spec>
124
+ ? OptionInputTable<Table, Spec> extends never ? never : Options[K]
125
+ : never
126
+ }
127
+
128
+ export type ApplyDeclaredOptions<
129
+ Table extends TableDefinition<any, any, any, "schema", any>,
130
+ Options extends DeclaredTableOptions
131
+ > = Options extends readonly [infer Head, ...infer Tail]
132
+ ? Head extends TableOptionBuilderLike<infer Spec>
133
+ ? Tail extends DeclaredTableOptions
134
+ ? ApplyDeclaredOptions<ApplyOption<Table, Spec>, Tail>
135
+ : ApplyOption<Table, Spec>
136
+ : Table
137
+ : Table
138
+
93
139
  export type MissingSelfGeneric = "Missing `Self` generic - use `class Self extends Table.Class<Self>(...) {}`"
94
140
 
95
141
  /** Bound columns keyed by field name for a particular table. */
@@ -106,9 +152,17 @@ export interface TableSchemas<
106
152
  Fields extends TableFieldMap,
107
153
  PrimaryKeyColumns extends keyof Fields & string
108
154
  > {
109
- readonly select: Schema.Schema<SelectRow<Name, Fields>>
110
- readonly insert: Schema.Schema<InsertRow<Name, Fields>>
111
- readonly update: Schema.Schema<UpdateRow<Name, Fields, PrimaryKeyColumns>>
155
+ readonly select: Schema.Decoder<SelectRow<Name, Fields>, never>
156
+ readonly insert: Schema.Decoder<InsertRow<Name, Fields>, never>
157
+ readonly update: Schema.Decoder<UpdateRow<Name, Fields, PrimaryKeyColumns>, never>
158
+ }
159
+
160
+ type TableSchemaCache<
161
+ Name extends string,
162
+ Fields extends TableFieldMap,
163
+ PrimaryKeyColumns extends keyof Fields & string
164
+ > = Partial<TableSchemas<Name, Fields, PrimaryKeyColumns>> & {
165
+ schemas?: TableSchemas<Name, Fields, PrimaryKeyColumns>
112
166
  }
113
167
 
114
168
  interface TableState<
@@ -132,16 +186,17 @@ export interface TableSchemaNamespace<SchemaName extends string> {
132
186
  readonly table: <
133
187
  Name extends string,
134
188
  Fields extends TableFieldMap,
189
+ const Options extends DeclaredTableOptions,
135
190
  PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>
136
191
  >(
137
192
  name: Name,
138
193
  fields: Fields,
139
- ...options: DeclaredTableOptions
140
- ) => TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>
194
+ ...options: Options & ValidateDeclaredOptions<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>, Options>
195
+ ) => ApplyDeclaredOptions<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>, Options>
141
196
  }
142
197
 
143
198
  export type DeclaredTableOptions = readonly TableOptionBuilderLike[]
144
- export type { DdlExpressionLike, IndexKeySpec, NormalizeColumns, ReferentialAction } from "./table-options.js"
199
+ export type { DdlExpressionLike, IndexKeySpec, MatchingColumnArityInput, NonEmptyColumnInput, NormalizeColumns, ReferentialAction } from "./table-options.js"
145
200
 
146
201
  export type TableDefinition<
147
202
  Name extends string,
@@ -192,7 +247,7 @@ export type TableClassStatic<
192
247
  >
193
248
  readonly [OptionsSymbol]: readonly TableOptionSpec[]
194
249
  readonly [DeclaredOptionsSymbol]?: readonly TableOptionSpec[]
195
- readonly [options]?: ClassDeclaredTableOptions
250
+ readonly [options]?: ClassDeclaredTableOptions<Fields>
196
251
  readonly tableName: Name
197
252
  } & BoundColumns<Name, Fields> & Plan.RowSet<
198
253
  BoundColumns<Name, Fields>,
@@ -202,7 +257,14 @@ export type TableClassStatic<
202
257
  >
203
258
 
204
259
  /** Minimal structural table-like contract used across helper APIs. */
205
- export type AnyTable = TableDefinition<any, any, any, any, any> | TableClassStatic<any, any, any, any>
260
+ export type AnyTable<Dialect extends string = string> = {
261
+ readonly [TypeId]: TableState<string, TableFieldMap, string, TableKind, string | undefined>
262
+ readonly [OptionsSymbol]: readonly TableOptionSpec[]
263
+ } & Plan.RowSet<any, any, Record<string, Plan.AnySource>, Dialect>
264
+
265
+ type FieldsOfAnyTable<Table extends AnyTable> = Table[typeof TypeId]["fields"]
266
+
267
+ type ColumnNamesOfAnyTable<Table extends AnyTable> = Extract<keyof FieldsOfAnyTable<Table>, string>
206
268
 
207
269
  /** Public table-option builder type used by `Table.index`, `Table.primaryKey`, and friends. */
208
270
  export type TableOption<
@@ -241,7 +303,6 @@ type BuildArtifacts<
241
303
  PrimaryKeyColumns extends keyof Fields & string
242
304
  > = {
243
305
  readonly columns: BoundColumns<Name, Fields>
244
- readonly schemas: TableSchemas<Name, Fields, PrimaryKeyColumns>
245
306
  readonly normalizedOptions: readonly TableOptionSpec[]
246
307
  readonly primaryKey: readonly PrimaryKeyColumns[]
247
308
  }
@@ -263,15 +324,149 @@ const buildArtifacts = <
263
324
  const columns = Object.fromEntries(
264
325
  Object.entries(fields).map(([key, column]) => [key, bindColumn(name, key, column, name, schemaName)])
265
326
  ) as BoundColumns<Name, Fields>
266
- const schemas = deriveSchemas(name, fields, primaryKey)
267
327
  return {
268
328
  columns,
269
- schemas,
270
329
  normalizedOptions,
271
330
  primaryKey
272
331
  }
273
332
  }
274
333
 
334
+ const getSchemaCache = <
335
+ Name extends string,
336
+ Fields extends TableFieldMap,
337
+ PrimaryKeyColumns extends keyof Fields & string
338
+ >(
339
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>
340
+ ): TableSchemaCache<Name, Fields, PrimaryKeyColumns> => {
341
+ const target = table as unknown as {
342
+ [SchemaCacheSymbol]?: TableSchemaCache<Name, Fields, PrimaryKeyColumns>
343
+ }
344
+ if (target[SchemaCacheSymbol] !== undefined) {
345
+ return target[SchemaCacheSymbol]
346
+ }
347
+ const cache: TableSchemaCache<Name, Fields, PrimaryKeyColumns> = {}
348
+ Object.defineProperty(table, SchemaCacheSymbol, {
349
+ configurable: true,
350
+ value: cache
351
+ })
352
+ return cache
353
+ }
354
+
355
+ const deriveTableSchema = <
356
+ Variant extends TableSchemaVariant,
357
+ Name extends string,
358
+ Fields extends TableFieldMap,
359
+ PrimaryKeyColumns extends keyof Fields & string
360
+ >(
361
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>,
362
+ variant: Variant
363
+ ): TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant] => {
364
+ const state = table[TypeId]
365
+ switch (variant) {
366
+ case "select":
367
+ return deriveSelectSchema(state.name, state.fields, state.primaryKey) as TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant]
368
+ case "insert":
369
+ return deriveInsertSchema(state.name, state.fields, state.primaryKey) as TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant]
370
+ case "update":
371
+ return deriveUpdateSchema(state.name, state.fields, state.primaryKey) as TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant]
372
+ }
373
+ }
374
+
375
+ const schemaFor = <
376
+ Variant extends TableSchemaVariant,
377
+ Name extends string,
378
+ Fields extends TableFieldMap,
379
+ PrimaryKeyColumns extends keyof Fields & string
380
+ >(
381
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>,
382
+ variant: Variant
383
+ ): TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant] => {
384
+ const cache = getSchemaCache(table)
385
+ const cached = cache[variant]
386
+ if (cached !== undefined) {
387
+ return cached as TableSchemas<Name, Fields, PrimaryKeyColumns>[Variant]
388
+ }
389
+ const schema = deriveTableSchema(table, variant)
390
+ cache[variant] = schema as any
391
+ return schema
392
+ }
393
+
394
+ export function selectSchema<
395
+ Name extends string,
396
+ Fields extends TableFieldMap,
397
+ PrimaryKeyColumns extends keyof Fields & string
398
+ >(
399
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>
400
+ ): Schema.Decoder<SelectRow<Name, Fields>, never> {
401
+ return schemaFor(table, "select") as Schema.Decoder<SelectRow<Name, Fields>, never>
402
+ }
403
+
404
+ export function insertSchema<
405
+ Name extends string,
406
+ Fields extends TableFieldMap,
407
+ PrimaryKeyColumns extends keyof Fields & string
408
+ >(
409
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>
410
+ ): Schema.Decoder<InsertRow<Name, Fields>, never> {
411
+ return schemaFor(table, "insert") as Schema.Decoder<InsertRow<Name, Fields>, never>
412
+ }
413
+
414
+ export function updateSchema<
415
+ Name extends string,
416
+ Fields extends TableFieldMap,
417
+ PrimaryKeyColumns extends keyof Fields & string
418
+ >(
419
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>
420
+ ): Schema.Decoder<UpdateRow<Name, Fields, PrimaryKeyColumns>, never> {
421
+ return schemaFor(table, "update") as Schema.Decoder<UpdateRow<Name, Fields, PrimaryKeyColumns>, never>
422
+ }
423
+
424
+ const schemasFor = <
425
+ Name extends string,
426
+ Fields extends TableFieldMap,
427
+ PrimaryKeyColumns extends keyof Fields & string
428
+ >(
429
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>
430
+ ): TableSchemas<Name, Fields, PrimaryKeyColumns> => {
431
+ const cache = getSchemaCache(table)
432
+ if (cache.schemas !== undefined) {
433
+ return cache.schemas
434
+ }
435
+ const schemas = {} as TableSchemas<Name, Fields, PrimaryKeyColumns>
436
+ Object.defineProperties(schemas, {
437
+ select: {
438
+ enumerable: true,
439
+ get: () => selectSchema(table)
440
+ },
441
+ insert: {
442
+ enumerable: true,
443
+ get: () => insertSchema(table)
444
+ },
445
+ update: {
446
+ enumerable: true,
447
+ get: () => updateSchema(table)
448
+ }
449
+ })
450
+ cache.schemas = schemas
451
+ return schemas
452
+ }
453
+
454
+ const defineSchemasGetter = <
455
+ Name extends string,
456
+ Fields extends TableFieldMap,
457
+ PrimaryKeyColumns extends keyof Fields & string
458
+ >(
459
+ table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any>
460
+ ): void => {
461
+ Object.defineProperty(table, "schemas", {
462
+ configurable: true,
463
+ enumerable: true,
464
+ get() {
465
+ return schemasFor(table)
466
+ }
467
+ })
468
+ }
469
+
275
470
  const makeTable = <
276
471
  Name extends string,
277
472
  Fields extends TableFieldMap,
@@ -295,7 +490,7 @@ const makeTable = <
295
490
  const table = attachPipe(Object.create(TableProto))
296
491
  table.name = name
297
492
  table.columns = artifacts.columns
298
- table.schemas = artifacts.schemas
493
+ defineSchemasGetter(table)
299
494
  table[TypeId] = {
300
495
  name,
301
496
  baseName,
@@ -341,7 +536,10 @@ const applyDeclaredOptions = <
341
536
  return table
342
537
  }
343
538
  return declaredOptions.reduce<TableDefinition<any, any, any, "schema", any>>(
344
- (current, option) => option(current),
539
+ (current, option) =>
540
+ (option as unknown as (
541
+ table: TableDefinition<any, any, any, "schema", any>
542
+ ) => TableDefinition<any, any, any, "schema", any>)(current),
345
543
  table
346
544
  ) as unknown as Table
347
545
  }
@@ -403,7 +601,6 @@ const ensureClassArtifacts = <
403
601
  )
404
602
  const artifacts = {
405
603
  columns: table.columns,
406
- schemas: table.schemas,
407
604
  normalizedOptions: table[OptionsSymbol],
408
605
  primaryKey: table[TypeId].primaryKey as readonly PrimaryKeyColumns[]
409
606
  } satisfies BuildArtifacts<Name, Fields, PrimaryKeyColumns>
@@ -491,17 +688,17 @@ export function make<
491
688
  */
492
689
  export const schema = <SchemaName extends string>(
493
690
  schemaName: SchemaName
494
- ): TableSchemaNamespace<SchemaName> => ({
495
- schemaName,
496
- table: <
691
+ ): TableSchemaNamespace<SchemaName> => {
692
+ const table = <
497
693
  Name extends string,
498
694
  Fields extends TableFieldMap,
695
+ const Options extends DeclaredTableOptions,
499
696
  PrimaryKeyColumns extends keyof Fields & string = InlinePrimaryKeyKeys<Fields>
500
697
  >(
501
698
  name: Name,
502
699
  fields: Fields,
503
- ...options: DeclaredTableOptions
504
- ): TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName> =>
700
+ ...options: Options & ValidateDeclaredOptions<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>, Options>
701
+ ): ApplyDeclaredOptions<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>, Options> =>
505
702
  applyDeclaredOptions(
506
703
  makeTable(
507
704
  name,
@@ -512,9 +709,13 @@ export const schema = <SchemaName extends string>(
512
709
  schemaName,
513
710
  "explicit"
514
711
  ) as TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>,
515
- options
516
- )
517
- })
712
+ options as unknown as Options
713
+ ) as ApplyDeclaredOptions<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", SchemaName>, Options>
714
+ return {
715
+ schemaName,
716
+ table
717
+ } as unknown as TableSchemaNamespace<SchemaName>
718
+ }
518
719
 
519
720
  /**
520
721
  * Creates an aliased source from an existing table definition.
@@ -546,7 +747,7 @@ export const alias = <
546
747
  const aliased = attachPipe(Object.create(TableProto))
547
748
  aliased.name = aliasName
548
749
  aliased.columns = columns
549
- aliased.schemas = deriveSchemas(aliasName, state.fields, state.primaryKey)
750
+ defineSchemasGetter(aliased)
550
751
  aliased[TypeId] = {
551
752
  name: aliasName,
552
753
  baseName: state.baseName,
@@ -605,7 +806,7 @@ export function Class<
605
806
  }
606
807
 
607
808
  static get schemas() {
608
- return ensureClassArtifacts(this as any).schemas
809
+ return schemasFor(this as any)
609
810
  }
610
811
 
611
812
  static get [TypeId]() {
@@ -664,7 +865,7 @@ export function Class<
664
865
  export const primaryKey = <
665
866
  const Columns extends string | readonly string[]
666
867
  >(
667
- columns: Columns
868
+ columns: Columns & NonEmptyColumnInput<Columns>
668
869
  ): TableOption<{
669
870
  readonly kind: "primaryKey"
670
871
  readonly columns: NormalizeColumns<Columns>
@@ -677,7 +878,7 @@ export const primaryKey = <
677
878
  export const unique = <
678
879
  const Columns extends string | readonly string[]
679
880
  >(
680
- columns: Columns
881
+ columns: Columns & NonEmptyColumnInput<Columns>
681
882
  ): TableOption<{
682
883
  readonly kind: "unique"
683
884
  readonly columns: NormalizeColumns<Columns>
@@ -690,7 +891,7 @@ export const unique = <
690
891
  export const index = <
691
892
  const Columns extends string | readonly string[]
692
893
  >(
693
- columns: Columns
894
+ columns: Columns & NonEmptyColumnInput<Columns>
694
895
  ): TableOption<{
695
896
  readonly kind: "index"
696
897
  readonly columns: NormalizeColumns<Columns>
@@ -705,9 +906,9 @@ export const foreignKey = <
705
906
  TargetTable extends AnyTable,
706
907
  const TargetColumns extends string | readonly string[]
707
908
  >(
708
- columns: LocalColumns,
909
+ columns: LocalColumns & NonEmptyColumnInput<LocalColumns>,
709
910
  target: () => TargetTable,
710
- referencedColumns: TargetColumns
911
+ referencedColumns: TargetColumns & NonEmptyColumnInput<TargetColumns> & MatchingColumnArityInput<LocalColumns, TargetColumns>
711
912
  ): TableOption<{
712
913
  readonly kind: "foreignKey"
713
914
  readonly columns: NormalizeColumns<LocalColumns>
@@ -715,7 +916,7 @@ export const foreignKey = <
715
916
  readonly tableName: string
716
917
  readonly schemaName?: string
717
918
  readonly columns: NormalizeColumns<TargetColumns>
718
- readonly knownColumns: readonly string[]
919
+ readonly knownColumns: readonly ColumnNamesOfAnyTable<TargetTable>[]
719
920
  }
720
921
  }> => makeOption({
721
922
  kind: "foreignKey",
@@ -724,7 +925,7 @@ export const foreignKey = <
724
925
  tableName: target()[TypeId].baseName,
725
926
  schemaName: target()[TypeId].schemaName,
726
927
  columns: normalizeColumnList(referencedColumns) as NormalizeColumns<TargetColumns>,
727
- knownColumns: Object.keys(target()[TypeId].fields)
928
+ knownColumns: Object.keys(target()[TypeId].fields) as unknown as readonly ColumnNamesOfAnyTable<TargetTable>[]
728
929
  })
729
930
  })
730
931
 
@@ -742,15 +943,21 @@ export const check = <Name extends string>(
742
943
  predicate
743
944
  })
744
945
 
745
- /** Extracts the row type of a table's select schema. */
746
- export type SelectOf<Table extends { readonly schemas: { readonly select: Schema.Schema<any> } }> = Schema.Schema.Type<
747
- Table["schemas"]["select"]
748
- >
749
- /** Extracts the payload type of a table's insert schema. */
750
- export type InsertOf<Table extends { readonly schemas: { readonly insert: Schema.Schema<any> } }> = Schema.Schema.Type<
751
- Table["schemas"]["insert"]
752
- >
753
- /** Extracts the payload type of a table's update schema. */
754
- export type UpdateOf<Table extends { readonly schemas: { readonly update: Schema.Schema<any> } }> = Schema.Schema.Type<
755
- Table["schemas"]["update"]
756
- >
946
+ /** Extracts the row type produced by `selectSchema(table)`. */
947
+ export type SelectOf<Table extends AnyTable> = Table[typeof TypeId] extends {
948
+ readonly name: infer Name extends string
949
+ readonly fields: infer Fields extends TableFieldMap
950
+ } ? SelectRow<Name, Fields> : never
951
+
952
+ /** Extracts the payload type produced by `insertSchema(table)`. */
953
+ export type InsertOf<Table extends AnyTable> = Table[typeof TypeId] extends {
954
+ readonly name: infer Name extends string
955
+ readonly fields: infer Fields extends TableFieldMap
956
+ } ? InsertRow<Name, Fields> : never
957
+
958
+ /** Extracts the payload type produced by `updateSchema(table)`. */
959
+ export type UpdateOf<Table extends AnyTable> = Table[typeof TypeId] extends {
960
+ readonly name: infer Name extends string
961
+ readonly fields: infer Fields extends TableFieldMap
962
+ readonly primaryKey: readonly (infer PrimaryKeyColumns)[]
963
+ } ? UpdateRow<Name, Fields, Extract<PrimaryKeyColumns, keyof Fields & string>> : never
@@ -1,7 +1,7 @@
1
1
  import * as Schema from "effect/Schema"
2
2
 
3
3
  import * as BaseColumn from "../internal/column.js"
4
- import { makeColumnDefinition, type ColumnDefinition } from "../internal/column-state.js"
4
+ import { makeColumnDefinition, type AnyColumnDefinition, type ColumnDefinition } from "../internal/column-state.js"
5
5
  import type * as Expression from "../internal/scalar.js"
6
6
  import {
7
7
  DecimalStringSchema,
@@ -21,7 +21,7 @@ const enrichDbType = <Db extends Expression.DbType.Any>(dbType: Db): Db => {
21
21
  }
22
22
 
23
23
  const primitive = <Type, Db extends Expression.DbType.Any>(
24
- schema: Schema.Schema<Type, any, any>,
24
+ schema: Schema.Schema<Type>,
25
25
  dbType: Db
26
26
  ): ColumnDefinition<Type, Type, Type, Db, false, false, false, false, false, undefined> =>
27
27
  makeColumnDefinition(schema as Schema.Schema<NonNullable<Type>>, {
@@ -46,11 +46,11 @@ const renderNumericDdlType = (
46
46
  : `${kind}(${options.precision},${options.scale})`
47
47
  }
48
48
 
49
- export const custom = <SchemaType extends Schema.Schema.Any, Db extends Expression.DbType.Any>(
49
+ export const custom = <SchemaType extends Schema.Top, Db extends Expression.DbType.Any>(
50
50
  schema: SchemaType,
51
51
  dbType: Db
52
52
  ) =>
53
- makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>, any, any>, {
53
+ makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>>, {
54
54
  dbType: enrichDbType(dbType),
55
55
  nullable: false,
56
56
  hasDefault: false,
@@ -62,7 +62,7 @@ export const custom = <SchemaType extends Schema.Schema.Any, Db extends Expressi
62
62
  identity: undefined
63
63
  })
64
64
 
65
- export const uuid = () => primitive(Schema.UUID, mysqlDatatypes.uuid())
65
+ export const uuid = () => primitive(Schema.String.check(Schema.isUUID()), mysqlDatatypes.uuid())
66
66
  export const text = () => primitive(Schema.String, mysqlDatatypes.text())
67
67
  export const int = () => primitive(Schema.Int, mysqlDatatypes.int())
68
68
  export const number = (options?: BaseColumn.NumericOptions) =>
@@ -81,8 +81,8 @@ export const boolean = () => primitive(Schema.Boolean, mysqlDatatypes.boolean())
81
81
  export const date = () => primitive(LocalDateStringSchema, mysqlDatatypes.date())
82
82
  export const datetime = () => primitive(LocalDateTimeStringSchema, mysqlDatatypes.datetime())
83
83
  export const timestamp = () => primitive(LocalDateTimeStringSchema, mysqlDatatypes.timestamp())
84
- export const json = <SchemaType extends Schema.Schema.Any>(schema: SchemaType) =>
85
- makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>, any, any>, {
84
+ export const json = <SchemaType extends Schema.Top>(schema: SchemaType) =>
85
+ makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>>, {
86
86
  dbType: { ...mysqlDatatypes.json(), variant: "json" } as Expression.DbType.Json<"mysql", "json">,
87
87
  nullable: false,
88
88
  hasDefault: false,
@@ -97,7 +97,23 @@ export const json = <SchemaType extends Schema.Schema.Any>(schema: SchemaType) =
97
97
  export const nullable = BaseColumn.nullable
98
98
  export const brand = BaseColumn.brand
99
99
  export const primaryKey = BaseColumn.primaryKey
100
- export const unique = BaseColumn.unique
100
+ type UniqueColumn<Column extends AnyColumnDefinition> = ReturnType<typeof BaseColumn.unique<Column>>
101
+
102
+ type MysqlUniqueOptions = {
103
+ readonly name?: string
104
+ readonly nullsNotDistinct?: never
105
+ readonly deferrable?: never
106
+ readonly initiallyDeferred?: never
107
+ }
108
+
109
+ type UniqueModifier = {
110
+ <Column extends AnyColumnDefinition>(column: Column): UniqueColumn<Column>
111
+ readonly options: <const Options extends MysqlUniqueOptions>(
112
+ options: Options
113
+ ) => <Column extends AnyColumnDefinition>(column: Column) => UniqueColumn<Column>
114
+ }
115
+
116
+ export const unique = BaseColumn.unique as UniqueModifier
101
117
  const default_ = BaseColumn.default_
102
118
  export const generated = BaseColumn.generated
103
119
  export const driverValueMapping = BaseColumn.driverValueMapping
@@ -50,12 +50,33 @@ type MysqlUuidWitness = Expression.DbType.Base<"mysql", "uuid"> & {
50
50
  }
51
51
  }
52
52
 
53
+ type MysqlJsonWitness = Expression.DbType.Base<"mysql", "json"> & {
54
+ readonly family: "json"
55
+ readonly runtime: "json"
56
+ readonly compareGroup: "json"
57
+ readonly castTargets: readonly ["json", "text"]
58
+ readonly driverValueMapping: {
59
+ readonly toDriver: (value: unknown) => unknown
60
+ }
61
+ }
62
+
63
+ mysqlDatatypeModule.json = () => ({
64
+ ...withMetadata("json"),
65
+ driverValueMapping: {
66
+ toDriver: (value: unknown) =>
67
+ value !== null && typeof value === "object"
68
+ ? JSON.stringify(value)
69
+ : value
70
+ }
71
+ }) as MysqlJsonWitness
72
+
53
73
  export const mysqlDatatypes = mysqlDatatypeModule as DatatypeModule<
54
74
  "mysql",
55
75
  typeof mysqlDatatypeKinds,
56
76
  typeof mysqlDatatypeFamilies
57
77
  > & {
58
78
  readonly uuid: () => MysqlUuidWitness
79
+ readonly json: () => MysqlJsonWitness
59
80
  }
60
81
 
61
82
  export type MysqlDatatypeModule = typeof mysqlDatatypes
@@ -51636,17 +51636,17 @@ export const mysqlErrorCatalogByNumber = {
51636
51636
  "MY-015153": [mysqlErrorCatalogBySymbol["ER_WARN_AUDIT_LOG_FILTER_RECOVERY_LOGGING_DISABLED_LOG"]!],
51637
51637
  } as const
51638
51638
 
51639
- const mysqlSymbolPattern = /^(?:[A-Z][A-Z0-9_]*|MY-\d+)$/
51640
- const mysqlNumberPattern = /^(?:\d+|MY-\d+)$/
51641
-
51642
51639
  export type MysqlErrorSymbol = keyof typeof mysqlErrorCatalogBySymbol
51643
51640
  export type MysqlErrorDescriptor<Symbol extends MysqlErrorSymbol = MysqlErrorSymbol> = (typeof mysqlErrorCatalogBySymbol)[Symbol]
51644
51641
  export type MysqlErrorNumber = keyof typeof mysqlErrorCatalogByNumber
51645
51642
  export type MysqlErrorTag<Symbol extends MysqlErrorSymbol = MysqlErrorSymbol> = MysqlErrorDescriptor<Symbol>["tag"]
51646
51643
  export type MysqlErrorDescriptorsByNumber<Number extends MysqlErrorNumber = MysqlErrorNumber> = (typeof mysqlErrorCatalogByNumber)[Number]
51647
51644
 
51648
- export const isMysqlErrorSymbol = (value: string): value is MysqlErrorSymbol => mysqlSymbolPattern.test(value)
51649
- export const isMysqlErrorNumber = (value: string): value is MysqlErrorNumber => mysqlNumberPattern.test(value)
51645
+ export const isMysqlErrorSymbol = (value: string): value is MysqlErrorSymbol =>
51646
+ value in mysqlErrorCatalogBySymbol
51647
+
51648
+ export const isMysqlErrorNumber = (value: string): value is MysqlErrorNumber =>
51649
+ value in mysqlErrorCatalogByNumber
51650
51650
 
51651
51651
  export const getMysqlErrorDescriptor = <Symbol extends MysqlErrorSymbol>(symbol: Symbol): MysqlErrorDescriptor<Symbol> =>
51652
51652
  mysqlErrorCatalogBySymbol[symbol]
@@ -48,8 +48,8 @@ const asNumber = (value: unknown): number | undefined => {
48
48
  if (typeof value === "number" && Number.isFinite(value)) {
49
49
  return value
50
50
  }
51
- if (typeof value === "string" && value.trim() !== "") {
52
- const parsed = Number(value)
51
+ if (typeof value === "string" && /^[+-]?\d+$/.test(value.trim())) {
52
+ const parsed = Number(value.trim())
53
53
  return Number.isFinite(parsed) ? parsed : undefined
54
54
  }
55
55
  return undefined