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
@@ -1,64 +1,7 @@
1
- import * as VariantSchema from "@effect/experimental/VariantSchema";
2
1
  import type * as Brand from "effect/Brand";
3
2
  import * as Schema from "effect/Schema";
4
3
  import { type AnyColumnDefinition, type HasDefault, type InsertType, type IsGenerated, type IsNullable, type SelectType, type UpdateType } from "./column-state.js";
5
- /** Variant-schema helper used to derive select / insert / update schemas. */
6
- export declare const TableSchema: {
7
- readonly Struct: <const A extends VariantSchema.Struct.Fields>(fields: A & VariantSchema.Struct.Validate<A, "insert" | "select" | "update">) => VariantSchema.Struct<A>;
8
- readonly Field: <const A extends VariantSchema.Field.ConfigWithKeys<"insert" | "select" | "update">>(config: A & { readonly [K in Exclude<keyof A, "insert" | "select" | "update">]: never; }) => VariantSchema.Field<A>;
9
- readonly FieldOnly: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Keys[number]]: S; }>;
10
- readonly FieldExcept: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Exclude<"insert", Keys[number]> | Exclude<"select", Keys[number]> | Exclude<"update", Keys[number]>]: S; }>;
11
- readonly fieldEvolve: {
12
- <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
13
- readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
14
- readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
15
- readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
16
- }>(f: Mapping): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping ? Mapping[K] extends (arg: any) => any ? ReturnType<Mapping[K]> : S_1[K] : S_1[K]; } : {
17
- readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping ? Mapping[T] extends (arg: any) => any ? ReturnType<Mapping[T]> : Self : Self : never : never;
18
- readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping ? Mapping[T_1] extends (arg: any) => any ? ReturnType<Mapping[T_1]> : Self : Self : never : never;
19
- readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping ? Mapping[T_2] extends (arg: any) => any ? ReturnType<Mapping[T_2]> : Self : Self : never : never;
20
- }>;
21
- <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_1 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
22
- readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
23
- readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
24
- readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
25
- }>(self: Self, f: Mapping_1): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_1 ? Mapping_1[K] extends (arg: any) => any ? ReturnType<Mapping_1[K]> : S_1[K] : S_1[K]; } : {
26
- readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_1 ? Mapping_1[T] extends (arg: any) => any ? ReturnType<Mapping_1[T]> : Self : Self : never : never;
27
- readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_1 ? Mapping_1[T_1] extends (arg: any) => any ? ReturnType<Mapping_1[T_1]> : Self : Self : never : never;
28
- readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_1 ? Mapping_1[T_2] extends (arg: any) => any ? ReturnType<Mapping_1[T_2]> : Self : Self : never : never;
29
- }>;
30
- };
31
- readonly fieldFromKey: {
32
- <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_2 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
33
- readonly insert?: string | undefined;
34
- readonly select?: string | undefined;
35
- readonly update?: string | undefined;
36
- }>(mapping: Mapping_2): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_2 ? Mapping_2[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_2[K]> : S_1[K] : S_1[K]; } : {
37
- readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_2 ? Mapping_2[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T]> : Self : Self : never : never;
38
- readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_2 ? Mapping_2[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_1]> : Self : Self : never : never;
39
- readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_2 ? Mapping_2[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_2]> : Self : Self : never : never;
40
- }>;
41
- <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_3 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
42
- readonly insert?: string | undefined;
43
- readonly select?: string | undefined;
44
- readonly update?: string | undefined;
45
- }>(self: Self, mapping: Mapping_3): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_3 ? Mapping_3[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_3[K]> : S_1[K] : S_1[K]; } : {
46
- readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_3 ? Mapping_3[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T]> : Self : Self : never : never;
47
- readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_3 ? Mapping_3[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_1]> : Self : Self : never : never;
48
- readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_3 ? Mapping_3[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_2]> : Self : Self : never : never;
49
- }>;
50
- };
51
- readonly Class: <Self = never>(identifier: string) => <const Fields extends VariantSchema.Struct.Fields>(fields: Fields & VariantSchema.Struct.Validate<Fields, "insert" | "select" | "update">, annotations?: Schema.Annotations.Schema<Self, readonly []> | undefined) => [Self] extends [never] ? "Missing `Self` generic - use `class Self extends Class<Self>()({ ... })`" : VariantSchema.Class<Self, Fields, VariantSchema.ExtractFields<"select", Fields, true>, Schema.Struct.Type<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Struct.Encoded<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Schema.Context<VariantSchema.ExtractFields<"select", Fields, true>[keyof VariantSchema.ExtractFields<"select", Fields, true>]>, Schema.Struct.Constructor<VariantSchema.ExtractFields<"select", Fields, true>>> & {
52
- readonly insert: Schema.Struct<VariantSchema.ExtractFields<"insert", Fields, false> extends infer T ? { [K in keyof T]: T[K]; } : never>;
53
- readonly select: Schema.Struct<VariantSchema.ExtractFields<"select", Fields, false> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
54
- readonly update: Schema.Struct<VariantSchema.ExtractFields<"update", Fields, false> extends infer T_2 ? { [K in keyof T_2]: T_2[K]; } : never>;
55
- };
56
- readonly Union: <const Members extends readonly VariantSchema.Struct<any>[]>(...members: Members) => VariantSchema.Union<Members> & VariantSchema.Union.Variants<Members, "insert" | "select" | "update">;
57
- readonly extract: {
58
- <V extends "insert" | "select" | "update">(variant: V): <A extends VariantSchema.Struct<any>>(self: A) => VariantSchema.Extract<V, A, V extends "select" ? true : false>;
59
- <V extends "insert" | "select" | "update", A extends VariantSchema.Struct<any>>(self: A, variant: V): VariantSchema.Extract<V, A, V extends "select" ? true : false>;
60
- };
61
- };
4
+ export type TableSchemaVariant = "select" | "insert" | "update";
62
5
  /** Normalized field map used by table definitions. */
63
6
  export type TableFieldMap = Record<string, AnyColumnDefinition>;
64
7
  type GeneratedKeys<Fields extends TableFieldMap> = {
@@ -91,15 +34,23 @@ export type InsertRow<TableName extends string, Fields extends TableFieldMap> =
91
34
  export type UpdateRow<TableName extends string, Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Simplify<Partial<{
92
35
  [K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>;
93
36
  }>>;
37
+ type SchemaOfVariant<Variant extends TableSchemaVariant, TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string> = Variant extends "select" ? Schema.Decoder<SelectRow<TableName, Fields>, never> : Variant extends "insert" ? Schema.Decoder<InsertRow<TableName, Fields>, never> : Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never>;
38
+ export declare const deriveSchema: <Variant extends TableSchemaVariant, TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(variant: Variant, tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns>;
39
+ export declare const deriveSelectSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Decoder<SelectRow<TableName, Fields>, never>;
40
+ export declare const deriveInsertSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Decoder<InsertRow<TableName, Fields>, never>;
41
+ export declare const deriveUpdateSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never>;
94
42
  /**
95
43
  * Derives the `select`, `insert`, and `update` schemas for a table.
96
44
  *
97
45
  * This is the central place where the column capability flags are turned into
98
46
  * real runtime schemas.
47
+ *
48
+ * @deprecated Prefer `deriveSelectSchema`, `deriveInsertSchema`, and
49
+ * `deriveUpdateSchema` so individual variants are derived lazily.
99
50
  */
100
51
  export declare const deriveSchemas: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => {
101
- readonly select: Schema.Schema<{ [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, { [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, never>;
102
- readonly insert: Schema.Schema<{ [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, { [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, never>;
103
- readonly update: Schema.Schema<Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, never>;
52
+ readonly select: Schema.Decoder<SelectRow<TableName, Fields>, never>;
53
+ readonly insert: Schema.Decoder<InsertRow<TableName, Fields>, never>;
54
+ readonly update: Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never>;
104
55
  };
105
56
  export {};
@@ -1,4 +1,3 @@
1
- import * as VariantSchema from "@effect/experimental/VariantSchema"
2
1
  import type * as Brand from "effect/Brand"
3
2
  import * as Schema from "effect/Schema"
4
3
 
@@ -12,13 +11,7 @@ import {
12
11
  type UpdateType
13
12
  } from "./column-state.js"
14
13
 
15
- /** Variant-schema helper used to derive select / insert / update schemas. */
16
- export const TableSchema = VariantSchema.make({
17
- variants: ["select", "insert", "update"] as const,
18
- defaultVariant: "select"
19
- })
20
-
21
- type Variants = "select" | "insert" | "update"
14
+ export type TableSchemaVariant = "select" | "insert" | "update"
22
15
 
23
16
  /** Normalized field map used by table definitions. */
24
17
  export type TableFieldMap = Record<string, AnyColumnDefinition>
@@ -112,7 +105,7 @@ const maybeBrandSchema = (
112
105
  column: AnyColumnDefinition,
113
106
  tableName: string,
114
107
  columnName: string
115
- ): Schema.Schema.Any =>
108
+ ): Schema.Top =>
116
109
  column.metadata.brand === true
117
110
  ? Schema.brand(`${tableName}.${columnName}`)(column.schema)
118
111
  : column.schema
@@ -121,7 +114,7 @@ const selectSchema = (
121
114
  column: AnyColumnDefinition,
122
115
  tableName: string,
123
116
  columnName: string
124
- ): Schema.Schema.Any =>
117
+ ): Schema.Top =>
125
118
  column.metadata.nullable ? Schema.NullOr(maybeBrandSchema(column, tableName, columnName)) : maybeBrandSchema(column, tableName, columnName)
126
119
 
127
120
  const insertSchema = (
@@ -153,11 +146,95 @@ const updateSchema = (
153
146
  return Schema.optional(base)
154
147
  }
155
148
 
149
+ type SchemaOfVariant<
150
+ Variant extends TableSchemaVariant,
151
+ TableName extends string,
152
+ Fields extends TableFieldMap,
153
+ PrimaryKeyColumns extends keyof Fields & string
154
+ > = Variant extends "select" ? Schema.Decoder<SelectRow<TableName, Fields>, never>
155
+ : Variant extends "insert" ? Schema.Decoder<InsertRow<TableName, Fields>, never>
156
+ : Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never>
157
+
158
+ const fieldSchemaForVariant = (
159
+ variant: TableSchemaVariant,
160
+ column: AnyColumnDefinition,
161
+ tableName: string,
162
+ columnName: string,
163
+ primaryKeySet: ReadonlySet<string>
164
+ ): any | undefined => {
165
+ switch (variant) {
166
+ case "select":
167
+ return selectSchema(column, tableName, columnName)
168
+ case "insert":
169
+ return insertSchema(column, tableName, columnName)
170
+ case "update":
171
+ return updateSchema(column, tableName, columnName, primaryKeySet.has(columnName))
172
+ }
173
+ }
174
+
175
+ export const deriveSchema = <
176
+ Variant extends TableSchemaVariant,
177
+ TableName extends string,
178
+ Fields extends TableFieldMap,
179
+ PrimaryKeyColumns extends keyof Fields & string
180
+ >(
181
+ variant: Variant,
182
+ tableName: TableName,
183
+ fields: Fields,
184
+ primaryKeyColumns: readonly PrimaryKeyColumns[]
185
+ ): SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns> => {
186
+ const primaryKeySet = new Set<string>(primaryKeyColumns)
187
+ const structFields: Record<string, any> = {}
188
+ for (const [key, column] of Object.entries(fields)) {
189
+ const schema = fieldSchemaForVariant(variant, column, tableName, key, primaryKeySet)
190
+ if (schema !== undefined) {
191
+ structFields[key] = schema
192
+ }
193
+ }
194
+ return Schema.Struct(structFields) as unknown as SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns>
195
+ }
196
+
197
+ export const deriveSelectSchema = <
198
+ TableName extends string,
199
+ Fields extends TableFieldMap,
200
+ PrimaryKeyColumns extends keyof Fields & string
201
+ >(
202
+ tableName: TableName,
203
+ fields: Fields,
204
+ primaryKeyColumns: readonly PrimaryKeyColumns[]
205
+ ): Schema.Decoder<SelectRow<TableName, Fields>, never> =>
206
+ deriveSchema("select", tableName, fields, primaryKeyColumns)
207
+
208
+ export const deriveInsertSchema = <
209
+ TableName extends string,
210
+ Fields extends TableFieldMap,
211
+ PrimaryKeyColumns extends keyof Fields & string
212
+ >(
213
+ tableName: TableName,
214
+ fields: Fields,
215
+ primaryKeyColumns: readonly PrimaryKeyColumns[]
216
+ ): Schema.Decoder<InsertRow<TableName, Fields>, never> =>
217
+ deriveSchema("insert", tableName, fields, primaryKeyColumns)
218
+
219
+ export const deriveUpdateSchema = <
220
+ TableName extends string,
221
+ Fields extends TableFieldMap,
222
+ PrimaryKeyColumns extends keyof Fields & string
223
+ >(
224
+ tableName: TableName,
225
+ fields: Fields,
226
+ primaryKeyColumns: readonly PrimaryKeyColumns[]
227
+ ): Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never> =>
228
+ deriveSchema("update", tableName, fields, primaryKeyColumns)
229
+
156
230
  /**
157
231
  * Derives the `select`, `insert`, and `update` schemas for a table.
158
232
  *
159
233
  * This is the central place where the column capability flags are turned into
160
234
  * real runtime schemas.
235
+ *
236
+ * @deprecated Prefer `deriveSelectSchema`, `deriveInsertSchema`, and
237
+ * `deriveUpdateSchema` so individual variants are derived lazily.
161
238
  */
162
239
  export const deriveSchemas = <
163
240
  TableName extends string,
@@ -168,36 +245,11 @@ export const deriveSchemas = <
168
245
  fields: Fields,
169
246
  primaryKeyColumns: readonly PrimaryKeyColumns[]
170
247
  ): {
171
- readonly select: Schema.Schema<SelectRow<TableName, Fields>>
172
- readonly insert: Schema.Schema<InsertRow<TableName, Fields>>
173
- readonly update: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
174
- } => {
175
- const primaryKeySet = new Set<string>(primaryKeyColumns)
176
- const variants: Record<string, VariantSchema.Field<any>> = {}
177
- for (const [key, column] of Object.entries(fields)) {
178
- const config: Record<Variants, any> = {
179
- select: selectSchema(column, tableName, key),
180
- insert: undefined,
181
- update: undefined
182
- }
183
- const insert = insertSchema(column, tableName, key)
184
- const update = updateSchema(column, tableName, key, primaryKeySet.has(key))
185
- if (insert !== undefined) {
186
- config.insert = insert
187
- } else {
188
- delete config.insert
189
- }
190
- if (update !== undefined) {
191
- config.update = update
192
- } else {
193
- delete config.update
194
- }
195
- variants[key] = TableSchema.Field(config)
196
- }
197
- const struct = TableSchema.Struct(variants as any)
198
- return {
199
- select: TableSchema.extract(struct, "select") as unknown as Schema.Schema<SelectRow<TableName, Fields>>,
200
- insert: TableSchema.extract(struct, "insert") as unknown as Schema.Schema<InsertRow<TableName, Fields>>,
201
- update: TableSchema.extract(struct, "update") as unknown as Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
202
- }
203
- }
248
+ readonly select: Schema.Decoder<SelectRow<TableName, Fields>, never>
249
+ readonly insert: Schema.Decoder<InsertRow<TableName, Fields>, never>
250
+ readonly update: Schema.Decoder<UpdateRow<TableName, Fields, PrimaryKeyColumns>, never>
251
+ } => ({
252
+ select: deriveSelectSchema(tableName, fields, primaryKeyColumns),
253
+ insert: deriveInsertSchema(tableName, fields, primaryKeyColumns),
254
+ update: deriveUpdateSchema(tableName, fields, primaryKeyColumns)
255
+ })
@@ -15,6 +15,30 @@ export type DdlExpressionLike = AnyExpression | AnySchemaExpression
15
15
 
16
16
  export type ReferentialAction = "noAction" | "restrict" | "cascade" | "setNull" | "setDefault"
17
17
 
18
+ const referentialActionError = "Foreign key action must be noAction, restrict, cascade, setNull, or setDefault"
19
+
20
+ export const renderReferentialAction = (action: unknown): string => {
21
+ switch (action) {
22
+ case "noAction":
23
+ return "no action"
24
+ case "restrict":
25
+ return "restrict"
26
+ case "cascade":
27
+ return "cascade"
28
+ case "setNull":
29
+ return "set null"
30
+ case "setDefault":
31
+ return "set default"
32
+ }
33
+ throw new Error(referentialActionError)
34
+ }
35
+
36
+ const validateReferentialAction = (action: unknown): void => {
37
+ if (action !== undefined) {
38
+ renderReferentialAction(action)
39
+ }
40
+ }
41
+
18
42
  export type IndexKeySpec =
19
43
  | {
20
44
  readonly kind: "column"
@@ -107,6 +131,18 @@ type TupleFromColumns<Columns> = Columns extends readonly [infer Head extends st
107
131
  ? readonly [Columns]
108
132
  : never
109
133
 
134
+ export type NonEmptyColumnInput<Columns extends string | readonly string[]> =
135
+ TupleFromColumns<Columns> extends never ? never : Columns
136
+
137
+ export type MatchingColumnArityInput<
138
+ Left extends string | readonly string[],
139
+ Right extends string | readonly string[]
140
+ > = TupleFromColumns<Left>["length"] extends TupleFromColumns<Right>["length"]
141
+ ? TupleFromColumns<Right>["length"] extends TupleFromColumns<Left>["length"]
142
+ ? unknown
143
+ : never
144
+ : never
145
+
110
146
  type AssertKnownColumns<Fields extends TableFieldMap, Columns extends readonly string[]> = Exclude<
111
147
  Columns[number],
112
148
  ColumnNameUnion<Fields>
@@ -114,6 +150,47 @@ type AssertKnownColumns<Fields extends TableFieldMap, Columns extends readonly s
114
150
  ? Columns
115
151
  : never
116
152
 
153
+ type IndexKeyColumnNames<Keys> = Keys extends readonly (infer Key)[]
154
+ ? Key extends { readonly kind: "column"; readonly column: infer Column extends string }
155
+ ? Column
156
+ : never
157
+ : never
158
+
159
+ type IndexOptionColumnNames<Spec> =
160
+ | (Spec extends { readonly columns: infer Columns extends readonly string[] } ? Columns[number] : never)
161
+ | (Spec extends { readonly include: infer Include extends readonly string[] } ? Include[number] : never)
162
+ | (Spec extends { readonly keys: infer Keys } ? IndexKeyColumnNames<Keys> : never)
163
+
164
+ type ForeignKeyReferencedColumnNames<Spec> = Spec extends { readonly references: () => infer Reference }
165
+ ? Reference extends { readonly columns: infer Columns extends readonly string[] }
166
+ ? Columns[number]
167
+ : never
168
+ : never
169
+
170
+ type ForeignKeyKnownReferencedColumnNames<Spec> = Spec extends { readonly references: () => infer Reference }
171
+ ? Reference extends { readonly knownColumns: infer KnownColumns extends readonly string[] }
172
+ ? KnownColumns[number]
173
+ : string
174
+ : string
175
+
176
+ type AssertKnownColumnNames<Fields extends TableFieldMap, Columns extends string> = [Columns] extends [never]
177
+ ? true
178
+ : string extends Columns
179
+ ? true
180
+ : Exclude<Columns, ColumnNameUnion<Fields>> extends never
181
+ ? true
182
+ : false
183
+
184
+ type AssertKnownReferenceColumnNames<KnownColumns extends string, Columns extends string> = [Columns] extends [never]
185
+ ? true
186
+ : string extends Columns
187
+ ? true
188
+ : string extends KnownColumns
189
+ ? true
190
+ : Exclude<Columns, KnownColumns> extends never
191
+ ? true
192
+ : false
193
+
117
194
  type AssertPrimaryKeyColumns<
118
195
  Fields extends TableFieldMap,
119
196
  Columns extends readonly string[]
@@ -159,6 +236,8 @@ export const collectInlineOptions = <Fields extends TableFieldMap>(
159
236
  })
160
237
  }
161
238
  if (column.metadata.references) {
239
+ validateReferentialAction(column.metadata.references.onUpdate)
240
+ validateReferentialAction(column.metadata.references.onDelete)
162
241
  const local = [columnName] as ColumnList
163
242
  options.push({
164
243
  kind: "foreignKey",
@@ -254,6 +333,8 @@ export const validateOptions = <Fields extends TableFieldMap>(
254
333
  }
255
334
  }
256
335
  if (option.kind === "foreignKey") {
336
+ validateReferentialAction(option.onUpdate)
337
+ validateReferentialAction(option.onDelete)
257
338
  const reference = option.references()
258
339
  if (reference.columns.length !== columns.length) {
259
340
  throw new Error(`Foreign key on table '${tableName}' must reference the same number of columns`)
@@ -278,7 +359,7 @@ export const validateOptions = <Fields extends TableFieldMap>(
278
359
  throw new Error(`Unknown index key column '${key.column}' on table '${tableName}'`)
279
360
  }
280
361
  }
281
- if (option.columns === undefined && (option.keys === undefined || option.keys.length === 0)) {
362
+ if (columns.length === 0 && (option.keys === undefined || option.keys.length === 0)) {
282
363
  throw new Error(`Index on table '${tableName}' requires at least one column or key`)
283
364
  }
284
365
  }
@@ -308,5 +389,31 @@ export type ValidatePrimaryKeyColumns<
308
389
  Columns extends readonly string[]
309
390
  > = AssertPrimaryKeyColumns<Fields, AssertKnownColumns<Fields, Columns>>
310
391
 
392
+ /** Compile-time validation that index columns, included columns, and column keys exist on the table. */
393
+ export type ValidateIndexOptionColumns<
394
+ Fields extends TableFieldMap,
395
+ Spec
396
+ > = AssertKnownColumnNames<Fields, IndexOptionColumnNames<Spec>> extends true ? Spec : never
397
+
398
+ /** Compile-time validation that foreign keys reference known local and target columns. */
399
+ export type ValidateForeignKeyOptionColumns<
400
+ Fields extends TableFieldMap,
401
+ Spec
402
+ > = Spec extends { readonly columns: infer Columns extends readonly string[] }
403
+ ? AssertKnownColumns<Fields, Columns> extends never
404
+ ? never
405
+ : AssertKnownReferenceColumnNames<
406
+ ForeignKeyKnownReferencedColumnNames<Spec>,
407
+ ForeignKeyReferencedColumnNames<Spec>
408
+ > extends true
409
+ ? Spec
410
+ : never
411
+ : AssertKnownReferenceColumnNames<
412
+ ForeignKeyKnownReferencedColumnNames<Spec>,
413
+ ForeignKeyReferencedColumnNames<Spec>
414
+ > extends true
415
+ ? Spec
416
+ : never
417
+
311
418
  /** Normalizes a public column input into the internal tuple form. */
312
419
  export type NormalizeColumns<Columns extends string | readonly string[]> = TupleFromColumns<Columns>
@@ -47,9 +47,9 @@ export type BoundColumns<Name extends string, Fields extends TableFieldMap> = {
47
47
  };
48
48
  /** Derived runtime schemas exposed by a table definition. */
49
49
  export interface TableSchemas<Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string> {
50
- readonly select: Schema.Schema<SelectRow<Name, Fields>>;
51
- readonly insert: Schema.Schema<InsertRow<Name, Fields>>;
52
- readonly update: Schema.Schema<UpdateRow<Name, Fields, PrimaryKeyColumns>>;
50
+ readonly select: Schema.Decoder<SelectRow<Name, Fields>, never>;
51
+ readonly insert: Schema.Decoder<InsertRow<Name, Fields>, never>;
52
+ readonly update: Schema.Decoder<UpdateRow<Name, Fields, PrimaryKeyColumns>, never>;
53
53
  }
54
54
  interface TableState<Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string, Kind extends TableKind = "schema", SchemaName extends string | undefined = DefaultSchemaName> {
55
55
  readonly name: Name;
@@ -92,7 +92,10 @@ export type TableClassStatic<Name extends string, Fields extends TableFieldMap,
92
92
  readonly tableName: Name;
93
93
  } & BoundColumns<Name, Fields> & Plan.RowSet<BoundColumns<Name, Fields>, never, Record<Name, Plan.Source<Name, "required", TrueFormula>>, TableDialect<Fields>>;
94
94
  /** Minimal structural table-like contract used across helper APIs. */
95
- export type AnyTable = TableDefinition<any, any, any, any, any> | TableClassStatic<any, any, any, any>;
95
+ export type AnyTable<Dialect extends string = string> = {
96
+ readonly [TypeId]: TableState<string, TableFieldMap, string, TableKind, string | undefined>;
97
+ readonly [OptionsSymbol]: readonly TableOptionSpec[];
98
+ } & Plan.RowSet<any, any, Record<string, Plan.AnySource>, Dialect>;
96
99
  /** Public table-option builder type used by `Table.index`, `Table.primaryKey`, and friends. */
97
100
  export type TableOption<Spec extends TableOptionSpec = TableOptionSpec> = {
98
101
  <Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(table: OptionInputTable<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", any>, Spec>): ApplyOption<TableDefinition<Name, Fields, PrimaryKeyColumns, "schema", any>, Spec>;
@@ -114,6 +117,12 @@ export declare const schema: <SchemaName extends string>(schemaName: SchemaName)
114
117
  * downstream SQL rendering work.
115
118
  */
116
119
  export declare const alias: <Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string, SchemaName extends string, AliasName extends string>(table: TableClassStatic<Name, Fields, PrimaryKeyColumns, SchemaName> | TableDefinition<Name, Fields, PrimaryKeyColumns, any, SchemaName>, aliasName: AliasName) => TableDefinition<AliasName, Fields, PrimaryKeyColumns, "alias", SchemaName>;
120
+ /** Returns the lazily derived select schema for a table. */
121
+ export declare function selectSchema<Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>): Schema.Decoder<SelectRow<Name, Fields>, never>;
122
+ /** Returns the lazily derived insert schema for a table. */
123
+ export declare function insertSchema<Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>): Schema.Decoder<InsertRow<Name, Fields>, never>;
124
+ /** Returns the lazily derived update schema for a table. */
125
+ export declare function updateSchema<Name extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(table: TableDefinition<Name, Fields, PrimaryKeyColumns, any, any> | TableClassStatic<Name, Fields, PrimaryKeyColumns, any>): Schema.Decoder<UpdateRow<Name, Fields, PrimaryKeyColumns>, never>;
117
126
  /**
118
127
  * Class-based table constructor mirroring `Schema.Class`.
119
128
  *
@@ -153,21 +162,19 @@ export declare const check: <Name extends string>(name: Name, predicate: DdlExpr
153
162
  readonly name: Name;
154
163
  readonly predicate: DdlExpressionLike;
155
164
  }>;
156
- /** Extracts the row type of a table's select schema. */
157
- export type SelectOf<Table extends {
158
- readonly schemas: {
159
- readonly select: Schema.Schema<any>;
160
- };
161
- }> = Schema.Schema.Type<Table["schemas"]["select"]>;
162
- /** Extracts the payload type of a table's insert schema. */
163
- export type InsertOf<Table extends {
164
- readonly schemas: {
165
- readonly insert: Schema.Schema<any>;
166
- };
167
- }> = Schema.Schema.Type<Table["schemas"]["insert"]>;
168
- /** Extracts the payload type of a table's update schema. */
169
- export type UpdateOf<Table extends {
170
- readonly schemas: {
171
- readonly update: Schema.Schema<any>;
172
- };
173
- }> = Schema.Schema.Type<Table["schemas"]["update"]>;
165
+ /** Extracts the row type produced by `selectSchema(table)`. */
166
+ export type SelectOf<Table extends AnyTable> = Table[typeof TypeId] extends {
167
+ readonly name: infer Name extends string;
168
+ readonly fields: infer Fields extends TableFieldMap;
169
+ } ? SelectRow<Name, Fields> : never;
170
+ /** Extracts the payload type produced by `insertSchema(table)`. */
171
+ export type InsertOf<Table extends AnyTable> = Table[typeof TypeId] extends {
172
+ readonly name: infer Name extends string;
173
+ readonly fields: infer Fields extends TableFieldMap;
174
+ } ? InsertRow<Name, Fields> : never;
175
+ /** Extracts the payload type produced by `updateSchema(table)`. */
176
+ export type UpdateOf<Table extends AnyTable> = Table[typeof TypeId] extends {
177
+ readonly name: infer Name extends string;
178
+ readonly fields: infer Fields extends TableFieldMap;
179
+ readonly primaryKey: readonly (infer PrimaryKeyColumns)[];
180
+ } ? UpdateRow<Name, Fields, Extract<PrimaryKeyColumns, keyof Fields & string>> : never;