effect-qb 0.17.0 → 0.20.0

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 (137) hide show
  1. package/README.md +11 -1
  2. package/dist/index.js +9376 -0
  3. package/dist/mysql.js +4092 -2671
  4. package/dist/postgres/metadata.js +2589 -1402
  5. package/dist/postgres.js +3953 -3583
  6. package/dist/sqlite.js +5527 -4088
  7. package/dist/standard.js +9330 -0
  8. package/package.json +9 -4
  9. package/src/casing.ts +71 -0
  10. package/src/index.ts +2 -0
  11. package/src/internal/casing.ts +89 -0
  12. package/src/internal/coercion/rules.ts +13 -1
  13. package/src/internal/column-state.d.ts +3 -3
  14. package/src/internal/column-state.ts +24 -18
  15. package/src/internal/column.ts +52 -15
  16. package/src/internal/datatypes/define.ts +7 -1
  17. package/src/internal/datatypes/enrich.ts +23 -0
  18. package/src/internal/datatypes/lookup.ts +81 -25
  19. package/src/internal/datatypes/matrix.ts +903 -0
  20. package/src/internal/datatypes/shape.ts +2 -0
  21. package/src/internal/derived-table.ts +4 -36
  22. package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/mysql.ts} +552 -361
  23. package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +657 -400
  24. package/src/{sqlite/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +505 -347
  25. package/src/internal/dialect.ts +36 -1
  26. package/src/internal/dsl-mutation-runtime.ts +12 -162
  27. package/src/internal/dsl-plan-runtime.ts +10 -138
  28. package/src/internal/dsl-query-runtime.ts +5 -79
  29. package/src/internal/dsl-transaction-ddl-runtime.ts +41 -65
  30. package/src/internal/executor.ts +66 -49
  31. package/src/internal/grouping-key.ts +87 -20
  32. package/src/internal/implication-runtime.ts +1 -1
  33. package/src/internal/json/path-access.ts +351 -0
  34. package/src/internal/predicate/runtime.ts +3 -0
  35. package/src/internal/query.d.ts +39 -12
  36. package/src/internal/query.ts +65 -26
  37. package/src/internal/renderer.ts +26 -14
  38. package/src/internal/runtime/driver-value-mapping.ts +3 -3
  39. package/src/internal/runtime/normalize.ts +12 -5
  40. package/src/internal/runtime/schema.ts +28 -38
  41. package/src/internal/runtime/value.ts +20 -23
  42. package/src/internal/scalar.d.ts +1 -1
  43. package/src/internal/scalar.ts +8 -2
  44. package/src/internal/schema-derivation.d.ts +12 -61
  45. package/src/internal/schema-derivation.ts +95 -43
  46. package/src/internal/schema-expression.ts +2 -2
  47. package/src/internal/sql-expression-renderer.ts +19 -0
  48. package/src/internal/standard-dsl.ts +6978 -0
  49. package/src/internal/table-options.ts +126 -66
  50. package/src/internal/table.ts +819 -237
  51. package/src/mysql/column-extension.ts +3 -0
  52. package/src/mysql/column.ts +14 -15
  53. package/src/mysql/datatypes/index.ts +4 -2
  54. package/src/mysql/datatypes/spec.ts +6 -176
  55. package/src/mysql/errors/normalize.ts +0 -1
  56. package/src/mysql/executor.ts +11 -11
  57. package/src/mysql/function/temporal.ts +1 -1
  58. package/src/mysql/internal/dialect.ts +9 -4
  59. package/src/mysql/internal/dsl.ts +334 -170
  60. package/src/mysql/internal/renderer.ts +6 -2
  61. package/src/mysql/json.ts +7 -2
  62. package/src/mysql/query-extension.ts +16 -0
  63. package/src/mysql/renderer.ts +37 -3
  64. package/src/mysql/type.ts +60 -0
  65. package/src/mysql.ts +7 -13
  66. package/src/postgres/check.ts +1 -0
  67. package/src/postgres/column-extension.ts +28 -0
  68. package/src/postgres/column.ts +13 -19
  69. package/src/postgres/datatypes/index.d.ts +2 -1
  70. package/src/postgres/datatypes/index.ts +4 -2
  71. package/src/postgres/datatypes/spec.ts +6 -260
  72. package/src/postgres/errors/normalize.ts +0 -1
  73. package/src/postgres/executor.ts +11 -11
  74. package/src/postgres/foreign-key.ts +24 -0
  75. package/src/postgres/function/core.ts +1 -3
  76. package/src/postgres/function/index.ts +1 -17
  77. package/src/postgres/function/temporal.ts +1 -1
  78. package/src/postgres/index.ts +1 -0
  79. package/src/postgres/internal/dialect.ts +9 -4
  80. package/src/postgres/internal/dsl.ts +328 -179
  81. package/src/postgres/internal/renderer.ts +6 -2
  82. package/src/postgres/internal/schema-ddl.ts +22 -10
  83. package/src/postgres/internal/schema-model.ts +238 -7
  84. package/src/postgres/json-extension.ts +7 -0
  85. package/src/postgres/json.ts +762 -173
  86. package/src/postgres/jsonb.ts +37 -0
  87. package/src/postgres/primary-key.ts +24 -0
  88. package/src/postgres/query-extension.ts +2 -0
  89. package/src/postgres/renderer.ts +37 -3
  90. package/src/postgres/schema-management.ts +13 -13
  91. package/src/postgres/schema.ts +106 -15
  92. package/src/postgres/table.ts +205 -538
  93. package/src/postgres/type.ts +93 -10
  94. package/src/postgres/unique.ts +32 -0
  95. package/src/postgres.ts +20 -16
  96. package/src/sqlite/column-extension.ts +3 -0
  97. package/src/sqlite/column.ts +14 -15
  98. package/src/sqlite/datatypes/index.ts +4 -2
  99. package/src/sqlite/datatypes/spec.ts +6 -94
  100. package/src/sqlite/errors/normalize.ts +0 -1
  101. package/src/sqlite/executor.ts +11 -11
  102. package/src/sqlite/function/temporal.ts +1 -1
  103. package/src/sqlite/internal/dialect.ts +9 -4
  104. package/src/sqlite/internal/dsl.ts +307 -159
  105. package/src/sqlite/internal/renderer.ts +6 -2
  106. package/src/sqlite/json.ts +8 -2
  107. package/src/sqlite/query-extension.ts +2 -0
  108. package/src/sqlite/renderer.ts +37 -3
  109. package/src/sqlite/type.ts +40 -0
  110. package/src/sqlite.ts +7 -13
  111. package/src/standard/cast.ts +113 -0
  112. package/src/standard/check.ts +17 -0
  113. package/src/standard/column.ts +163 -0
  114. package/src/standard/datatypes/index.ts +83 -0
  115. package/src/standard/datatypes/spec.ts +12 -0
  116. package/src/standard/dialect.ts +40 -0
  117. package/src/standard/foreign-key.ts +37 -0
  118. package/src/standard/function/aggregate.ts +2 -0
  119. package/src/standard/function/core.ts +2 -0
  120. package/src/standard/function/index.ts +18 -0
  121. package/src/standard/function/string.ts +2 -0
  122. package/src/standard/function/temporal.ts +78 -0
  123. package/src/standard/function/window.ts +2 -0
  124. package/src/standard/index.ts +17 -0
  125. package/src/standard/internal/renderer.ts +45 -0
  126. package/src/standard/json.ts +883 -0
  127. package/src/standard/primary-key.ts +17 -0
  128. package/src/standard/query.ts +152 -0
  129. package/src/standard/renderer.ts +49 -0
  130. package/src/standard/table.ts +151 -0
  131. package/src/standard/unique.ts +17 -0
  132. package/src/standard.ts +32 -0
  133. package/src/internal/aggregation-validation.ts +0 -57
  134. package/src/internal/table.d.ts +0 -173
  135. package/src/mysql/table.ts +0 -183
  136. package/src/postgres/cast.ts +0 -45
  137. package/src/sqlite/table.ts +0 -183
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-qb",
3
- "version": "0.17.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -21,6 +21,10 @@
21
21
  "README.md"
22
22
  ],
23
23
  "exports": {
24
+ ".": {
25
+ "types": "./src/index.ts",
26
+ "import": "./dist/index.js"
27
+ },
24
28
  "./postgres": {
25
29
  "types": "./src/postgres.ts",
26
30
  "import": "./dist/postgres.js"
@@ -40,6 +44,7 @@
40
44
  "./package.json": "./package.json"
41
45
  },
42
46
  "imports": {
47
+ "#standard": "./src/standard.ts",
43
48
  "#postgres": "./src/postgres.ts",
44
49
  "#mysql": "./src/mysql.ts",
45
50
  "#sqlite": "./src/sqlite.ts",
@@ -57,9 +62,9 @@
57
62
  "@typescript/native-preview": "beta"
58
63
  },
59
64
  "dependencies": {
60
- "@effect/experimental": "^0.57.0",
61
- "@effect/sql": "^0.48.0",
62
- "effect": "^3.19.3",
63
65
  "pgsql-ast-parser": "^12.0.2"
66
+ },
67
+ "peerDependencies": {
68
+ "effect": "4.0.0-beta.98"
64
69
  }
65
70
  }
package/src/casing.ts ADDED
@@ -0,0 +1,71 @@
1
+ import * as InternalCasing from "./internal/casing.js"
2
+ import * as BaseTable from "./internal/table.js"
3
+ import * as Table from "./standard/table.js"
4
+
5
+ export type Style = InternalCasing.Style
6
+ export type Options = InternalCasing.Options
7
+ export type Input = Options | Style
8
+
9
+ export interface TableFactory {
10
+ readonly table: typeof Table.make
11
+ readonly [InternalCasing.TypeId]: InternalCasing.State
12
+ readonly withCasing: (options: Input) => TableFactory
13
+ }
14
+
15
+ type CasingTarget =
16
+ | BaseTable.TableDefinition<any, any, any, any, any>
17
+ | {
18
+ readonly [InternalCasing.TypeId]: InternalCasing.State
19
+ readonly withCasing: (options: Options) => CasingTarget
20
+ }
21
+
22
+ const isTable = (value: unknown): value is BaseTable.TableDefinition<any, any, any, any, any> =>
23
+ typeof value === "object" && value !== null && BaseTable.TypeId in value
24
+
25
+ const allCategories = (style: Style): Options => ({
26
+ tables: style,
27
+ columns: style,
28
+ schemas: style,
29
+ indexes: style,
30
+ constraints: style,
31
+ types: style,
32
+ sequences: style
33
+ })
34
+
35
+ const normalize = (input: Input): Options =>
36
+ typeof input === "string" || typeof input === "function" ? allCategories(input) : input
37
+
38
+ export function withCasing(options: Style): <Value extends CasingTarget>(value: Value) => Value
39
+ export function withCasing(options: Options): <Value extends CasingTarget>(value: Value) => Value
40
+ export function withCasing(options: Input) {
41
+ return <Value extends CasingTarget>(value: Value): Value => {
42
+ const normalized = normalize(options)
43
+ if (isTable(value)) {
44
+ return BaseTable.withCasing(value, normalized) as Value
45
+ }
46
+ return (value as Exclude<CasingTarget, BaseTable.TableDefinition<any, any, any, any, any>>).withCasing(normalized) as Value
47
+ }
48
+ }
49
+
50
+ export function make(options: Style): TableFactory
51
+ export function make(options: Options): TableFactory
52
+ export function make(options: Input): TableFactory {
53
+ const normalized = normalize(options)
54
+ const withFactoryCasing = withCasing(normalized)
55
+ const table = ((name: string, fields: any, schemaName?: string) =>
56
+ schemaName === undefined
57
+ ? Table.make(name, fields).pipe(withFactoryCasing)
58
+ : Table.make(name, fields, schemaName).pipe(withFactoryCasing)) as typeof Table.make
59
+ const factory = {
60
+ table,
61
+ [InternalCasing.TypeId]: {
62
+ casing: normalized
63
+ },
64
+ withCasing: (override: Input) => make(InternalCasing.merge(normalized, normalize(override)) ?? {})
65
+ }
66
+ return factory
67
+ }
68
+
69
+ export const apply = InternalCasing.apply
70
+ export const applyCategory = InternalCasing.applyCategory
71
+ export const merge = InternalCasing.merge
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./standard.js"
2
+ export * as Casing from "./casing.js"
@@ -0,0 +1,89 @@
1
+ export const TypeId: unique symbol = Symbol.for("effect-qb/Casing")
2
+
3
+ export type Style =
4
+ | "preserve"
5
+ | "snake_case"
6
+ | "camelCase"
7
+ | "PascalCase"
8
+ | "kebab-case"
9
+ | "SCREAMING_SNAKE_CASE"
10
+ | ((name: string) => string)
11
+
12
+ export interface Options {
13
+ readonly tables?: Style
14
+ readonly columns?: Style
15
+ readonly schemas?: Style
16
+ readonly indexes?: Style
17
+ readonly constraints?: Style
18
+ readonly types?: Style
19
+ readonly sequences?: Style
20
+ }
21
+
22
+ export type Category = keyof Options
23
+
24
+ export interface State {
25
+ readonly casing?: Options
26
+ }
27
+
28
+ export const merge = (
29
+ base: Options | undefined,
30
+ override: Options | undefined
31
+ ): Options | undefined => {
32
+ if (base === undefined) {
33
+ return override
34
+ }
35
+ if (override === undefined) {
36
+ return base
37
+ }
38
+ return { ...base, ...override }
39
+ }
40
+
41
+ const words = (name: string): readonly string[] =>
42
+ name
43
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
44
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
45
+ .split(/[^A-Za-z0-9]+/)
46
+ .filter((part) => part.length > 0)
47
+
48
+ const capitalize = (value: string): string =>
49
+ value.length === 0 ? value : `${value[0]!.toUpperCase()}${value.slice(1)}`
50
+
51
+ const lowerWords = (name: string): readonly string[] =>
52
+ words(name).map((part) => part.toLowerCase())
53
+
54
+ const applyNamedStyle = (style: Exclude<Style, (name: string) => string>, name: string): string => {
55
+ switch (style) {
56
+ case "preserve":
57
+ return name
58
+ case "snake_case":
59
+ return lowerWords(name).join("_")
60
+ case "camelCase": {
61
+ const parts = lowerWords(name)
62
+ const [head, ...tail] = parts
63
+ return head === undefined ? "" : `${head}${tail.map(capitalize).join("")}`
64
+ }
65
+ case "PascalCase":
66
+ return lowerWords(name).map(capitalize).join("")
67
+ case "kebab-case":
68
+ return lowerWords(name).join("-")
69
+ case "SCREAMING_SNAKE_CASE":
70
+ return lowerWords(name).join("_").toUpperCase()
71
+ }
72
+ }
73
+
74
+ export const apply = (
75
+ style: Style | undefined,
76
+ name: string
77
+ ): string => {
78
+ if (style === undefined) {
79
+ return name
80
+ }
81
+ return typeof style === "function" ? style(name) : applyNamedStyle(style, name)
82
+ }
83
+
84
+ export const applyCategory = (
85
+ options: Options | undefined,
86
+ category: Category,
87
+ name: string
88
+ ): string => apply(options?.[category], name)
89
+
@@ -1,5 +1,11 @@
1
1
  import type * as Expression from "../scalar.js"
2
- import type { CanCastDbType as LookupCanCastDbType, CanCompareDbTypes as LookupCanCompareDbTypes, CanContainDbTypes as LookupCanContainDbTypes, CanTextuallyCoerceDbType as LookupCanTextuallyCoerceDbType } from "../datatypes/lookup.js"
2
+ import type {
3
+ CanCastDbType as LookupCanCastDbType,
4
+ CanCompareDbTypes as LookupCanCompareDbTypes,
5
+ CanContainDbTypes as LookupCanContainDbTypes,
6
+ CanImplicitlyConvertDbType as LookupCanImplicitlyConvertDbType,
7
+ CanTextuallyCoerceDbType as LookupCanTextuallyCoerceDbType
8
+ } from "../datatypes/lookup.js"
3
9
 
4
10
  export type CanCompareDbTypes<
5
11
  Left extends Expression.DbType.Any,
@@ -18,6 +24,12 @@ export type CanTextuallyCoerceDbType<
18
24
  Dialect extends string
19
25
  > = LookupCanTextuallyCoerceDbType<Db, Dialect>
20
26
 
27
+ export type CanImplicitlyConvertDbType<
28
+ Source extends Expression.DbType.Any,
29
+ Target extends Expression.DbType.Any,
30
+ Dialect extends string
31
+ > = LookupCanImplicitlyConvertDbType<Source, Target, Dialect>
32
+
21
33
  export type CanCastDbType<
22
34
  Source extends Expression.DbType.Any,
23
35
  Target extends Expression.DbType.Any,
@@ -70,7 +70,7 @@ export interface ColumnState<Select, Insert, Update, Db extends Expression.DbTyp
70
70
  export interface ColumnDefinition<Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends Expression.BindingId = never> extends Pipeable, Expression.Scalar<Select, Db, Nullable extends true ? "maybe" : "never", Db["dialect"], "scalar", Dependencies> {
71
71
  readonly pipe: Pipeable["pipe"];
72
72
  readonly [ColumnTypeId]: ColumnState<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>;
73
- readonly schema: Schema.Schema<NonNullable<Select>, any, any>;
73
+ readonly schema: Schema.Schema<NonNullable<Select>>;
74
74
  readonly metadata: {
75
75
  readonly dbType: Db;
76
76
  readonly nullable: Nullable;
@@ -111,7 +111,7 @@ export type AnyColumnDefinition = ColumnDefinition<any, any, any, Expression.DbT
111
111
  /** Convenience alias for any bound column. */
112
112
  export type AnyBoundColumn = BoundColumn<any, any, any, Expression.DbType.Any, boolean, boolean, boolean, boolean, boolean, any, string, string, string>;
113
113
  /** Constructs a runtime column-definition object from schema and metadata. */
114
- export declare const makeColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(schema: Schema.Schema<NonNullable<Select>, any, any>, metadata: {
114
+ export declare const makeColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(schema: Schema.Schema<NonNullable<Select>>, metadata: {
115
115
  readonly dbType: Db;
116
116
  readonly nullable: Nullable;
117
117
  readonly hasDefault: HasDefault;
@@ -135,7 +135,7 @@ export declare const makeColumnDefinition: <Select, Insert, Update, Db extends E
135
135
  } | undefined;
136
136
  }) => ColumnDefinition<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>;
137
137
  export declare const remapColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(column: ColumnDefinition<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>, options?: {
138
- readonly schema?: Schema.Schema.Any | undefined;
138
+ readonly schema?: Schema.Top | undefined;
139
139
  readonly metadata?: {
140
140
  readonly dbType: Db;
141
141
  readonly nullable: Nullable;
@@ -4,6 +4,8 @@ import * as Schema from "effect/Schema"
4
4
 
5
5
  import * as Expression from "./scalar.js"
6
6
  import * as ExpressionAst from "./expression-ast.js"
7
+ import { withJsonPathAccess, type WithJsonPathAccess } from "./json/path-access.js"
8
+ import type * as Casing from "./casing.js"
7
9
  import type * as SchemaExpression from "./schema-expression.js"
8
10
 
9
11
  /** Symbol used to attach column-definition metadata. */
@@ -123,7 +125,7 @@ export interface ColumnDefinition<
123
125
  Ref,
124
126
  Dependencies
125
127
  >
126
- readonly schema: Schema.Schema<NonNullable<Select>, any, any>
128
+ readonly schema: Schema.Schema<NonNullable<Select>>
127
129
  readonly metadata: {
128
130
  readonly dbType: Db
129
131
  readonly nullable: Nullable
@@ -183,6 +185,7 @@ export interface BoundColumn<
183
185
  readonly columnName: ColumnName
184
186
  readonly baseTableName: BaseTableName
185
187
  readonly schemaName?: string
188
+ readonly casing?: Casing.Options
186
189
  }
187
190
  readonly [Expression.TypeId]: Expression.State<
188
191
  Select,
@@ -227,7 +230,7 @@ export type AnyBoundColumn = BoundColumn<
227
230
  >
228
231
 
229
232
  const ColumnProto = {
230
- pipe(this: unknown) {
233
+ pipe(this: Pipeable) {
231
234
  return pipeArguments(this, arguments)
232
235
  }
233
236
  }
@@ -236,7 +239,7 @@ const attachPipe = <Value extends object>(value: Value): Value => {
236
239
  Object.defineProperty(value, "pipe", {
237
240
  configurable: true,
238
241
  writable: true,
239
- value: function(this: unknown) {
242
+ value: function(this: Value) {
240
243
  return pipeArguments(value, arguments)
241
244
  }
242
245
  })
@@ -257,7 +260,7 @@ export const makeColumnDefinition = <
257
260
  Ref,
258
261
  Dependencies extends Expression.BindingId = never
259
262
  >(
260
- schema: Schema.Schema<NonNullable<Select>, any, any>,
263
+ schema: Schema.Schema<NonNullable<Select>>,
261
264
  metadata: ColumnDefinition<
262
265
  Select,
263
266
  Insert,
@@ -271,7 +274,7 @@ export const makeColumnDefinition = <
271
274
  Ref,
272
275
  Dependencies
273
276
  >["metadata"]
274
- ): ColumnDefinition<
277
+ ): WithJsonPathAccess<ColumnDefinition<
275
278
  Select,
276
279
  Insert,
277
280
  Update,
@@ -283,7 +286,7 @@ export const makeColumnDefinition = <
283
286
  Unique,
284
287
  Ref,
285
288
  Dependencies
286
- > => {
289
+ >> => {
287
290
  const column = attachPipe(Object.create(ColumnProto))
288
291
  column.schema = schema
289
292
  column.metadata = metadata
@@ -315,7 +318,7 @@ export const makeColumnDefinition = <
315
318
  identity: metadata.identity,
316
319
  enum: metadata.enum
317
320
  }
318
- return column
321
+ return withJsonPathAccess(column)
319
322
  }
320
323
 
321
324
  export const remapColumnDefinition = <
@@ -345,7 +348,7 @@ export const remapColumnDefinition = <
345
348
  Dependencies
346
349
  >,
347
350
  options: {
348
- readonly schema?: Schema.Schema.Any
351
+ readonly schema?: Schema.Top
349
352
  readonly metadata?: ColumnDefinition<
350
353
  Select,
351
354
  Insert,
@@ -360,7 +363,7 @@ export const remapColumnDefinition = <
360
363
  Dependencies
361
364
  >["metadata"]
362
365
  } = {}
363
- ): ColumnDefinition<
366
+ ): WithJsonPathAccess<ColumnDefinition<
364
367
  Select,
365
368
  Insert,
366
369
  Update,
@@ -372,7 +375,7 @@ export const remapColumnDefinition = <
372
375
  Unique,
373
376
  Ref,
374
377
  Dependencies
375
- > => {
378
+ >> => {
376
379
  const schema = options.schema ?? column.schema
377
380
  const metadata = options.metadata ?? column.metadata
378
381
  const next = attachPipe(Object.create(ColumnProto))
@@ -407,21 +410,22 @@ export const remapColumnDefinition = <
407
410
  enum: metadata.enum
408
411
  }
409
412
  if (ExpressionAst.TypeId in column) {
410
- next[ExpressionAst.TypeId] = (column as unknown as {
413
+ next[ExpressionAst.TypeId] = (column as {
411
414
  readonly [ExpressionAst.TypeId]: ExpressionAst.Any
412
415
  })[ExpressionAst.TypeId]
413
416
  }
414
417
  if (BoundColumnTypeId in column) {
415
- next[BoundColumnTypeId] = (column as unknown as {
418
+ next[BoundColumnTypeId] = (column as {
416
419
  readonly [BoundColumnTypeId]: {
417
420
  readonly tableName: string
418
421
  readonly columnName: string
419
422
  readonly baseTableName: string
420
423
  readonly schemaName?: string
424
+ readonly casing?: Casing.Options
421
425
  }
422
426
  })[BoundColumnTypeId]
423
427
  }
424
- return next
428
+ return withJsonPathAccess(next)
425
429
  }
426
430
 
427
431
  /** Attaches table/column provenance to an existing column definition. */
@@ -436,7 +440,8 @@ export const bindColumn = <
436
440
  columnName: ColumnName,
437
441
  column: Column,
438
442
  baseTableName: BaseTableName,
439
- schemaName?: SchemaName
443
+ schemaName?: SchemaName,
444
+ casing?: Casing.Options
440
445
  ): BoundColumnFrom<Column, TableName, ColumnName, BaseTableName> => {
441
446
  const brandName = `${tableName}.${columnName}`
442
447
  const schema = column.metadata.brand === true
@@ -467,9 +472,10 @@ export const bindColumn = <
467
472
  tableName,
468
473
  columnName,
469
474
  baseTableName,
470
- schemaName
475
+ schemaName,
476
+ casing
471
477
  }
472
- return bound
478
+ return withJsonPathAccess(bound) as BoundColumnFrom<Column, TableName, ColumnName, BaseTableName>
473
479
  }
474
480
 
475
481
  /** Extracts the internal state record for a column. */
@@ -508,7 +514,7 @@ export type BoundColumnFrom<
508
514
  TableName extends string,
509
515
  ColumnName extends string,
510
516
  BaseTableName extends string = TableName
511
- > = BoundColumn<
517
+ > = WithJsonPathAccess<BoundColumn<
512
518
  Column["metadata"]["brand"] extends true
513
519
  ? BrandedValue<SelectType<Column>, `${TableName}.${ColumnName}`>
514
520
  : SelectType<Column>,
@@ -528,4 +534,4 @@ export type BoundColumnFrom<
528
534
  TableName,
529
535
  ColumnName,
530
536
  BaseTableName
531
- >
537
+ >>
@@ -42,6 +42,7 @@ import {
42
42
  type SelectType,
43
43
  type UpdateType
44
44
  } from "./column-state.js"
45
+ import type { NonEmptyStringInput } from "./table-options.js"
45
46
 
46
47
  type ReferentialAction = "noAction" | "restrict" | "cascade" | "setNull" | "setDefault"
47
48
 
@@ -223,23 +224,53 @@ type ForeignKeyOptions<Target extends AnyBoundColumn> = {
223
224
  readonly initiallyDeferred?: boolean
224
225
  }
225
226
 
227
+ type NonEmptyOptionNameInput<Options> = Options extends { readonly name: infer Name extends string }
228
+ ? NonEmptyStringInput<Name> extends never ? never : unknown
229
+ : unknown
230
+
231
+ type NonEmptyStringArrayInput<Values extends readonly string[]> =
232
+ [Extract<Values[number], "">] extends [never] ? unknown : never
233
+
234
+ type NonEmptyIndexMethodInput<Options> = Options extends { readonly method: infer Method extends string }
235
+ ? NonEmptyStringInput<Method> extends never ? never : unknown
236
+ : unknown
237
+
238
+ type NonEmptyIndexIncludeInput<Options> = Options extends { readonly include: infer Include extends readonly string[] }
239
+ ? NonEmptyStringArrayInput<Include>
240
+ : unknown
241
+
242
+ type NonEmptyIndexOperatorClassInput<Options> = Options extends { readonly operatorClass: infer OperatorClass extends string }
243
+ ? NonEmptyStringInput<OperatorClass> extends never ? never : unknown
244
+ : unknown
245
+
246
+ type NonEmptyIndexCollationInput<Options> = Options extends { readonly collation: infer Collation extends string }
247
+ ? NonEmptyStringInput<Collation> extends never ? never : unknown
248
+ : unknown
249
+
250
+ type NonEmptyIndexMetadataInput<Options> =
251
+ & NonEmptyOptionNameInput<Options>
252
+ & NonEmptyIndexMethodInput<Options>
253
+ & NonEmptyIndexIncludeInput<Options>
254
+ & NonEmptyIndexOperatorClassInput<Options>
255
+ & NonEmptyIndexCollationInput<Options>
256
+
226
257
  type SchemaCompatibleColumn<
227
258
  Column extends AnyColumnDefinition,
228
- SchemaType extends Schema.Schema.Any
229
- > = [BaseSelectType<Column>] extends [Schema.Schema.Encoded<SchemaType>]
259
+ SchemaType extends Schema.Top
260
+ > = [BaseSelectType<Column>] extends [Schema.Codec.Encoded<SchemaType>]
230
261
  ? Column
231
262
  : never
232
263
 
233
264
  type ColumnSchemaOutput<
234
265
  Column extends AnyColumnDefinition,
235
- SchemaType extends Schema.Schema.Any
266
+ SchemaType extends Schema.Top
236
267
  > = IsNullable<Column> extends true
237
268
  ? Schema.Schema.Type<SchemaType> | null
238
269
  : Schema.Schema.Type<SchemaType>
239
270
 
240
271
  type ColumnWithSchema<
241
272
  Column extends AnyColumnDefinition,
242
- SchemaType extends Schema.Schema.Any
273
+ SchemaType extends Schema.Top
243
274
  > = ColumnDefinition<
244
275
  ColumnSchemaOutput<Column, SchemaType>,
245
276
  ColumnSchemaOutput<Column, SchemaType>,
@@ -376,7 +407,7 @@ const isColumnDefinitionValue = (value: unknown): value is AnyColumnDefinition =
376
407
  typeof value === "object" && value !== null && ColumnTypeId in value
377
408
 
378
409
  const primitive = <Type, Db extends Expression.DbType.Any>(
379
- schema: Schema.Schema<Type, any, any>,
410
+ schema: Schema.Schema<Type>,
380
411
  dbType: Db
381
412
  ): ColumnDefinition<Type, Type, Type, Db, false, false, false, false, false, undefined> =>
382
413
  makeColumnDefinition(schema as Schema.Schema<NonNullable<Type>>, {
@@ -401,7 +432,7 @@ type ColumnModule<
401
432
  JsonKind extends string
402
433
  > = {
403
434
  readonly custom: <
404
- SchemaType extends Schema.Schema.Any,
435
+ SchemaType extends Schema.Top,
405
436
  Db extends Expression.DbType.Any
406
437
  >(
407
438
  schema: SchemaType,
@@ -425,7 +456,7 @@ type ColumnModule<
425
456
  readonly boolean: () => ColumnDefinition<boolean, boolean, boolean, Expression.DbType.Base<Dialect, BooleanKind>, false, false, false, false, false, undefined>
426
457
  readonly date: () => ColumnDefinition<LocalDateString, LocalDateString, LocalDateString, Expression.DbType.Base<Dialect, DateKind>, false, false, false, false, false, undefined>
427
458
  readonly timestamp: () => ColumnDefinition<LocalDateTimeString, LocalDateTimeString, LocalDateTimeString, Expression.DbType.Base<Dialect, TimestampKind>, false, false, false, false, false, undefined>
428
- readonly json: <SchemaType extends Schema.Schema.Any>(
459
+ readonly json: <SchemaType extends Schema.Top>(
429
460
  schema: SchemaType
430
461
  ) => ColumnDefinition<
431
462
  Schema.Schema.Type<SchemaType>,
@@ -442,7 +473,7 @@ type ColumnModule<
442
473
  }
443
474
 
444
475
  /** Replaces a column's runtime schema while preserving its SQL type metadata. */
445
- export const schema = <SchemaType extends Schema.Schema.Any>(nextSchema: SchemaType) =>
476
+ export const schema = <SchemaType extends Schema.Top>(nextSchema: SchemaType) =>
446
477
  <Column extends AnyColumnDefinition>(
447
478
  column: SchemaCompatibleColumn<Column, SchemaType>
448
479
  ): ColumnWithSchema<Column, SchemaType> =>
@@ -500,7 +531,7 @@ export const primaryKey = <Column extends AnyColumnDefinition>(
500
531
  type UniqueModifier = {
501
532
  <Column extends AnyColumnDefinition>(column: Column): UniqueColumn<Column>
502
533
  readonly options: <const Options extends ColumnUniqueOptions>(
503
- options: Options
534
+ options: Options & NonEmptyOptionNameInput<Options>
504
535
  ) => <Column extends AnyColumnDefinition>(column: Column) => UniqueColumn<Column>
505
536
  }
506
537
 
@@ -550,11 +581,11 @@ export const generated = <Value extends DdlExpression>(value: Value) =>
550
581
  }) as GeneratedColumn<Column>
551
582
 
552
583
  /** Preserves the exact SQL type used for DDL rendering. */
553
- export const ddlType = <SqlType extends string>(sqlType: SqlType) =>
584
+ export const ddlType = <SqlType extends string>(sqlType: NonEmptyStringInput<SqlType>) =>
554
585
  <Column extends AnyColumnDefinition>(column: Column): DdlTypedColumn<Column> =>
555
586
  mapColumn(column, {
556
587
  ...column.metadata,
557
- ddlType: sqlType
588
+ ddlType: sqlType as SqlType
558
589
  }) as DdlTypedColumn<Column>
559
590
 
560
591
  /** Overrides how a column crosses the SQL driver boundary. */
@@ -590,13 +621,15 @@ export const array = <Options extends ArrayOptions | undefined = undefined>(
590
621
  }) as ArrayColumn<Column, Options>
591
622
 
592
623
  /** Marks a column as indexed. */
624
+ type IndexPipe = <Column extends AnyColumnDefinition>(column: Column) => IndexedColumn<Column>
625
+
593
626
  export function index<Column extends AnyColumnDefinition>(
594
627
  column: Column
595
628
  ): IndexedColumn<Column>
596
629
  export function index<const Options extends ColumnIndexOptions>(
597
- options: Options
630
+ options: Options & NonEmptyIndexMetadataInput<Options>
598
631
  ): <Column extends AnyColumnDefinition>(column: Column) => IndexedColumn<Column>
599
- export function index(arg: unknown): unknown {
632
+ export function index(arg: AnyColumnDefinition | ColumnIndexOptions): IndexedColumn<AnyColumnDefinition> | IndexPipe {
600
633
  if (isColumnDefinitionValue(arg)) {
601
634
  return mapColumn(arg, {
602
635
  ...arg.metadata,
@@ -648,17 +681,21 @@ export const identityAlways = <Column extends AnyColumnDefinition>(
648
681
  *
649
682
  * The base, non-null select types must match.
650
683
  */
684
+ type ForeignKeyPipe<Target extends AnyBoundColumn = AnyBoundColumn> = <Column extends AnyColumnDefinition>(
685
+ column: CompatibleReference<Column, Target>
686
+ ) => ReferencingColumn<Column, Target>
687
+
651
688
  export function foreignKey<Target extends AnyBoundColumn>(
652
689
  target: () => Target
653
690
  ): <Column extends AnyColumnDefinition>(
654
691
  column: CompatibleReference<Column, Target>
655
692
  ) => ReferencingColumn<Column, Target>
656
693
  export function foreignKey<const Options extends ForeignKeyOptions<AnyBoundColumn>>(
657
- options: Options
694
+ options: Options & NonEmptyOptionNameInput<Options>
658
695
  ): <Column extends AnyColumnDefinition>(
659
696
  column: CompatibleReference<Column, ReturnType<Options["target"]>>
660
697
  ) => ReferencingColumn<Column, ReturnType<Options["target"]>>
661
- export function foreignKey(arg: unknown): unknown {
698
+ export function foreignKey(arg: (() => AnyBoundColumn) | ForeignKeyOptions<AnyBoundColumn>): ForeignKeyPipe {
662
699
  if (typeof arg === "function") {
663
700
  const target = arg as () => AnyBoundColumn
664
701
  return <Column extends AnyColumnDefinition>(
@@ -1,6 +1,11 @@
1
1
  import type * as Expression from "../scalar.js"
2
+ import type { NonEmptyStringInput } from "../table-options.js"
2
3
  import type { DatatypeFamilySpec, DatatypeKindSpec } from "./shape.js"
3
4
 
5
+ type ImplicitTargetsOf<Family> = Family extends { readonly implicitTargets: infer Targets extends readonly string[] }
6
+ ? Targets
7
+ : readonly []
8
+
4
9
  type DatatypeWitness<
5
10
  Dialect extends string,
6
11
  Kinds extends Record<string, DatatypeKindSpec>,
@@ -11,6 +16,7 @@ type DatatypeWitness<
11
16
  readonly runtime: Kinds[Kind]["runtime"]
12
17
  readonly compareGroup: Families[Kinds[Kind]["family"]]["compareGroup"]
13
18
  readonly castTargets: Families[Kinds[Kind]["family"]]["castTargets"]
19
+ readonly implicitTargets: ImplicitTargetsOf<Families[Kinds[Kind]["family"]]>
14
20
  readonly traits: Families[Kinds[Kind]["family"]]["traits"]
15
21
  }
16
22
 
@@ -20,7 +26,7 @@ export type DatatypeModule<
20
26
  Families extends Record<string, DatatypeFamilySpec>,
21
27
  Aliases extends Record<string, string> = Record<never, never>
22
28
  > = {
23
- readonly custom: <Kind extends string>(kind: Kind) => Expression.DbType.Base<Dialect, Kind>
29
+ readonly custom: <Kind extends string>(kind: NonEmptyStringInput<Kind>) => Expression.DbType.Base<Dialect, Kind>
24
30
  } & {
25
31
  readonly [Kind in keyof Kinds]: () => DatatypeWitness<Dialect, Kinds, Families, Kind & string>
26
32
  } & {
@@ -0,0 +1,23 @@
1
+ import type * as Expression from "../scalar.js"
2
+
3
+ type DatatypeLookup = Readonly<Record<string, (() => Expression.DbType.Any) | undefined>>
4
+
5
+ export const enrichDbType = <
6
+ Module extends object,
7
+ Db extends Expression.DbType.Any
8
+ >(
9
+ datatypes: Module,
10
+ dbType: Db
11
+ ): Db => {
12
+ if (dbType.kind === "custom") {
13
+ return dbType
14
+ }
15
+ const lookup = datatypes as DatatypeLookup
16
+ if (!(dbType.kind in lookup)) {
17
+ return dbType
18
+ }
19
+ const candidate = lookup[dbType.kind]
20
+ return typeof candidate === "function"
21
+ ? { ...candidate(), ...dbType } as Db
22
+ : dbType
23
+ }