effect-qb 0.16.0 → 0.19.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 (128) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +8065 -0
  3. package/dist/mysql.js +4036 -2418
  4. package/dist/postgres/metadata.js +2536 -625
  5. package/dist/postgres.js +8248 -7857
  6. package/dist/sqlite.js +8854 -0
  7. package/dist/standard.js +8019 -0
  8. package/package.json +15 -3
  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/column-state.ts +11 -6
  13. package/src/internal/column.ts +44 -7
  14. package/src/internal/datatypes/define.ts +2 -1
  15. package/src/internal/datatypes/enrich.ts +23 -0
  16. package/src/internal/datatypes/lookup.ts +14 -7
  17. package/src/internal/derived-table.ts +7 -13
  18. package/src/internal/dialect-renderers/mysql.ts +2046 -0
  19. package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +867 -283
  20. package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +834 -358
  21. package/src/internal/dialect.ts +37 -0
  22. package/src/internal/dsl-mutation-runtime.ts +29 -10
  23. package/src/internal/dsl-plan-runtime.ts +41 -24
  24. package/src/internal/dsl-query-runtime.ts +11 -31
  25. package/src/internal/dsl-transaction-ddl-runtime.ts +61 -15
  26. package/src/internal/executor.ts +57 -15
  27. package/src/internal/expression-ast.ts +3 -2
  28. package/src/internal/grouping-key.ts +216 -9
  29. package/src/internal/implication-runtime.ts +3 -2
  30. package/src/internal/json/types.ts +155 -40
  31. package/src/internal/predicate/context.ts +14 -1
  32. package/src/internal/predicate/key.ts +19 -2
  33. package/src/internal/predicate/runtime.ts +30 -3
  34. package/src/internal/query.d.ts +38 -11
  35. package/src/internal/query.ts +315 -54
  36. package/src/internal/renderer.ts +51 -6
  37. package/src/internal/runtime/driver-value-mapping.ts +58 -0
  38. package/src/internal/runtime/normalize.ts +74 -43
  39. package/src/internal/runtime/schema.ts +5 -3
  40. package/src/internal/runtime/value.ts +153 -30
  41. package/src/internal/scalar.ts +6 -1
  42. package/src/internal/schema-derivation.d.ts +12 -61
  43. package/src/internal/schema-derivation.ts +90 -38
  44. package/src/internal/schema-expression.ts +2 -2
  45. package/src/internal/sql-expression-renderer.ts +19 -0
  46. package/src/internal/standard-dsl.ts +6885 -0
  47. package/src/internal/table-options.ts +229 -62
  48. package/src/internal/table.d.ts +33 -32
  49. package/src/internal/table.ts +469 -160
  50. package/src/mysql/column-extension.ts +3 -0
  51. package/src/mysql/column.ts +27 -12
  52. package/src/mysql/datatypes/index.ts +24 -2
  53. package/src/mysql/errors/catalog.ts +5 -5
  54. package/src/mysql/errors/normalize.ts +2 -2
  55. package/src/mysql/executor.ts +7 -5
  56. package/src/mysql/internal/dialect.ts +9 -4
  57. package/src/mysql/internal/dsl.ts +906 -324
  58. package/src/mysql/internal/renderer.ts +7 -2
  59. package/src/mysql/json.ts +37 -0
  60. package/src/mysql/query-extension.ts +16 -0
  61. package/src/mysql/query.ts +9 -2
  62. package/src/mysql/renderer.ts +31 -4
  63. package/src/mysql.ts +4 -12
  64. package/src/postgres/column-extension.ts +28 -0
  65. package/src/postgres/column.ts +9 -13
  66. package/src/postgres/datatypes/index.d.ts +2 -1
  67. package/src/postgres/datatypes/index.ts +3 -2
  68. package/src/postgres/errors/normalize.ts +2 -2
  69. package/src/postgres/executor.ts +55 -10
  70. package/src/postgres/function/core.ts +20 -4
  71. package/src/postgres/function/index.ts +1 -17
  72. package/src/postgres/internal/dialect.ts +9 -4
  73. package/src/postgres/internal/dsl.ts +850 -359
  74. package/src/postgres/internal/renderer.ts +7 -2
  75. package/src/postgres/internal/schema-ddl.ts +22 -9
  76. package/src/postgres/internal/schema-model.ts +244 -10
  77. package/src/postgres/json.ts +100 -24
  78. package/src/postgres/jsonb.ts +38 -0
  79. package/src/postgres/query-extension.ts +2 -0
  80. package/src/postgres/query.ts +9 -2
  81. package/src/postgres/renderer.ts +31 -4
  82. package/src/postgres/schema-management.ts +108 -16
  83. package/src/postgres/schema.ts +98 -15
  84. package/src/postgres/table.ts +203 -398
  85. package/src/postgres/type.ts +8 -7
  86. package/src/postgres.ts +9 -11
  87. package/src/sqlite/column-extension.ts +3 -0
  88. package/src/sqlite/column.ts +127 -0
  89. package/src/sqlite/datatypes/index.ts +80 -0
  90. package/src/sqlite/datatypes/spec.ts +98 -0
  91. package/src/sqlite/errors/catalog.ts +103 -0
  92. package/src/sqlite/errors/fields.ts +19 -0
  93. package/src/sqlite/errors/index.ts +19 -0
  94. package/src/sqlite/errors/normalize.ts +229 -0
  95. package/src/sqlite/errors/requirements.ts +71 -0
  96. package/src/sqlite/errors/types.ts +29 -0
  97. package/src/sqlite/executor.ts +229 -0
  98. package/src/sqlite/function/aggregate.ts +2 -0
  99. package/src/sqlite/function/core.ts +2 -0
  100. package/src/sqlite/function/index.ts +19 -0
  101. package/src/sqlite/function/string.ts +2 -0
  102. package/src/sqlite/function/temporal.ts +100 -0
  103. package/src/sqlite/function/window.ts +2 -0
  104. package/src/sqlite/internal/dialect.ts +42 -0
  105. package/src/sqlite/internal/dsl.ts +6979 -0
  106. package/src/sqlite/internal/renderer.ts +51 -0
  107. package/src/sqlite/json.ts +39 -0
  108. package/src/sqlite/query-extension.ts +2 -0
  109. package/src/sqlite/query.ts +196 -0
  110. package/src/sqlite/renderer.ts +51 -0
  111. package/src/sqlite.ts +14 -0
  112. package/src/standard/column.ts +163 -0
  113. package/src/standard/datatypes/index.ts +83 -0
  114. package/src/standard/datatypes/spec.ts +98 -0
  115. package/src/standard/dialect.ts +40 -0
  116. package/src/standard/function/aggregate.ts +2 -0
  117. package/src/standard/function/core.ts +2 -0
  118. package/src/standard/function/index.ts +18 -0
  119. package/src/standard/function/string.ts +2 -0
  120. package/src/standard/function/temporal.ts +78 -0
  121. package/src/standard/function/window.ts +2 -0
  122. package/src/standard/internal/renderer.ts +45 -0
  123. package/src/standard/query.ts +152 -0
  124. package/src/standard/renderer.ts +21 -0
  125. package/src/standard/table.ts +147 -0
  126. package/src/standard.ts +18 -0
  127. package/src/internal/aggregation-validation.ts +0 -57
  128. package/src/mysql/table.ts +0 -157
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-qb",
3
- "version": "0.16.0",
3
+ "version": "0.19.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"
@@ -33,11 +37,17 @@
33
37
  "types": "./src/mysql.ts",
34
38
  "import": "./dist/mysql.js"
35
39
  },
40
+ "./sqlite": {
41
+ "types": "./src/sqlite.ts",
42
+ "import": "./dist/sqlite.js"
43
+ },
36
44
  "./package.json": "./package.json"
37
45
  },
38
46
  "imports": {
47
+ "#standard": "./src/standard.ts",
39
48
  "#postgres": "./src/postgres.ts",
40
49
  "#mysql": "./src/mysql.ts",
50
+ "#sqlite": "./src/sqlite.ts",
41
51
  "#internal/*": "./src/internal/*"
42
52
  },
43
53
  "publishConfig": {
@@ -52,9 +62,11 @@
52
62
  "@typescript/native-preview": "beta"
53
63
  },
54
64
  "dependencies": {
65
+ "pgsql-ast-parser": "^12.0.2"
66
+ },
67
+ "peerDependencies": {
55
68
  "@effect/experimental": "^0.57.0",
56
69
  "@effect/sql": "^0.48.0",
57
- "effect": "^3.19.3",
58
- "pgsql-ast-parser": "^12.0.2"
70
+ "effect": "^3.19.3"
59
71
  }
60
72
  }
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
+
@@ -4,6 +4,7 @@ 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 type * as Casing from "./casing.js"
7
8
  import type * as SchemaExpression from "./schema-expression.js"
8
9
 
9
10
  /** Symbol used to attach column-definition metadata. */
@@ -183,6 +184,7 @@ export interface BoundColumn<
183
184
  readonly columnName: ColumnName
184
185
  readonly baseTableName: BaseTableName
185
186
  readonly schemaName?: string
187
+ readonly casing?: Casing.Options
186
188
  }
187
189
  readonly [Expression.TypeId]: Expression.State<
188
190
  Select,
@@ -227,7 +229,7 @@ export type AnyBoundColumn = BoundColumn<
227
229
  >
228
230
 
229
231
  const ColumnProto = {
230
- pipe(this: unknown) {
232
+ pipe(this: Pipeable) {
231
233
  return pipeArguments(this, arguments)
232
234
  }
233
235
  }
@@ -236,7 +238,7 @@ const attachPipe = <Value extends object>(value: Value): Value => {
236
238
  Object.defineProperty(value, "pipe", {
237
239
  configurable: true,
238
240
  writable: true,
239
- value: function(this: unknown) {
241
+ value: function(this: Value) {
240
242
  return pipeArguments(value, arguments)
241
243
  }
242
244
  })
@@ -407,17 +409,18 @@ export const remapColumnDefinition = <
407
409
  enum: metadata.enum
408
410
  }
409
411
  if (ExpressionAst.TypeId in column) {
410
- next[ExpressionAst.TypeId] = (column as unknown as {
412
+ next[ExpressionAst.TypeId] = (column as {
411
413
  readonly [ExpressionAst.TypeId]: ExpressionAst.Any
412
414
  })[ExpressionAst.TypeId]
413
415
  }
414
416
  if (BoundColumnTypeId in column) {
415
- next[BoundColumnTypeId] = (column as unknown as {
417
+ next[BoundColumnTypeId] = (column as {
416
418
  readonly [BoundColumnTypeId]: {
417
419
  readonly tableName: string
418
420
  readonly columnName: string
419
421
  readonly baseTableName: string
420
422
  readonly schemaName?: string
423
+ readonly casing?: Casing.Options
421
424
  }
422
425
  })[BoundColumnTypeId]
423
426
  }
@@ -436,7 +439,8 @@ export const bindColumn = <
436
439
  columnName: ColumnName,
437
440
  column: Column,
438
441
  baseTableName: BaseTableName,
439
- schemaName?: SchemaName
442
+ schemaName?: SchemaName,
443
+ casing?: Casing.Options
440
444
  ): BoundColumnFrom<Column, TableName, ColumnName, BaseTableName> => {
441
445
  const brandName = `${tableName}.${columnName}`
442
446
  const schema = column.metadata.brand === true
@@ -467,7 +471,8 @@ export const bindColumn = <
467
471
  tableName,
468
472
  columnName,
469
473
  baseTableName,
470
- schemaName
474
+ schemaName,
475
+ casing
471
476
  }
472
477
  return bound
473
478
  }
@@ -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,6 +224,36 @@ 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
259
  SchemaType extends Schema.Schema.Any
@@ -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,4 +1,5 @@
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
 
4
5
  type DatatypeWitness<
@@ -20,7 +21,7 @@ export type DatatypeModule<
20
21
  Families extends Record<string, DatatypeFamilySpec>,
21
22
  Aliases extends Record<string, string> = Record<never, never>
22
23
  > = {
23
- readonly custom: <Kind extends string>(kind: Kind) => Expression.DbType.Base<Dialect, Kind>
24
+ readonly custom: <Kind extends string>(kind: NonEmptyStringInput<Kind>) => Expression.DbType.Base<Dialect, Kind>
24
25
  } & {
25
26
  readonly [Kind in keyof Kinds]: () => DatatypeWitness<Dialect, Kinds, Families, Kind & string>
26
27
  } & {
@@ -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
+ }
@@ -31,6 +31,13 @@ type BaseCastTargetsOf<Db extends Expression.DbType.Base<any, any>> =
31
31
  ? Target
32
32
  : never
33
33
 
34
+ type DbTypeCompatibleWithDialect<
35
+ Db extends Expression.DbType.Any,
36
+ Dialect extends string
37
+ > = Dialect extends "standard"
38
+ ? Db extends { readonly dialect: string } ? true : false
39
+ : Db extends { readonly dialect: Dialect | "standard" } ? true : false
40
+
34
41
  type BaseHasTextualTrait<Db extends Expression.DbType.Base<any, any>> =
35
42
  Db extends { readonly traits?: infer Traits }
36
43
  ? Traits extends { readonly textual: true }
@@ -103,8 +110,8 @@ export type CanCompareDbTypes<
103
110
  Left extends Expression.DbType.Any,
104
111
  Right extends Expression.DbType.Any,
105
112
  Dialect extends string
106
- > = Left extends { readonly dialect: Dialect }
107
- ? Right extends { readonly dialect: Dialect }
113
+ > = DbTypeCompatibleWithDialect<Left, Dialect> extends true
114
+ ? DbTypeCompatibleWithDialect<Right, Dialect> extends true
108
115
  ? CompareGroupOfDbType<Left> extends never
109
116
  ? false
110
117
  : CompareGroupOfDbType<Right> extends never
@@ -125,8 +132,8 @@ export type CanContainDbTypes<
125
132
  Left extends Expression.DbType.Any,
126
133
  Right extends Expression.DbType.Any,
127
134
  Dialect extends string
128
- > = Left extends { readonly dialect: Dialect }
129
- ? Right extends { readonly dialect: Dialect }
135
+ > = DbTypeCompatibleWithDialect<Left, Dialect> extends true
136
+ ? DbTypeCompatibleWithDialect<Right, Dialect> extends true
130
137
  ? FamilyOfDbType<Left> extends "array" | "range" | "multirange"
131
138
  ? FamilyOfDbType<Right> extends "array" | "range" | "multirange"
132
139
  ? [CompareGroupOfDbType<Left>] extends [CompareGroupOfDbType<Right>]
@@ -142,7 +149,7 @@ export type CanContainDbTypes<
142
149
  export type CanTextuallyCoerceDbType<
143
150
  Db extends Expression.DbType.Any,
144
151
  Dialect extends string
145
- > = Db extends { readonly dialect: Dialect }
152
+ > = DbTypeCompatibleWithDialect<Db, Dialect> extends true
146
153
  ? Db extends Expression.DbType.Domain<any, infer Base extends Expression.DbType.Any, any>
147
154
  ? CanTextuallyCoerceDbType<Base, Dialect>
148
155
  : Db extends Expression.DbType.Enum<any, any> | Expression.DbType.Set<any, any>
@@ -158,8 +165,8 @@ export type CanCastDbType<
158
165
  Source extends Expression.DbType.Any,
159
166
  Target extends Expression.DbType.Any,
160
167
  Dialect extends string
161
- > = Source extends { readonly dialect: Dialect }
162
- ? Target extends { readonly dialect: Dialect }
168
+ > = DbTypeCompatibleWithDialect<Source, Dialect> extends true
169
+ ? DbTypeCompatibleWithDialect<Target, Dialect> extends true
163
170
  ? Source extends Expression.DbType.Domain<any, infer Base extends Expression.DbType.Any, any>
164
171
  ? CanCastDbType<Base, Target, Dialect>
165
172
  : Target extends Expression.DbType.Domain<any, infer TargetBase extends Expression.DbType.Any, any>
@@ -1,4 +1,4 @@
1
- import { pipeArguments } from "effect/Pipeable"
1
+ import { pipeArguments, type Pipeable } from "effect/Pipeable"
2
2
 
3
3
  import * as Expression from "./scalar.js"
4
4
  import * as Plan from "./row-set.js"
@@ -11,13 +11,14 @@ import {
11
11
  type QueryPlan,
12
12
  getAst,
13
13
  makeExpression,
14
+ currentRequiredList,
14
15
  type SelectionOfPlan
15
16
  } from "./query.js"
16
17
  import * as ExpressionAst from "./expression-ast.js"
17
18
  import { flattenSelection } from "./projections.js"
18
19
 
19
20
  const DerivedProto = {
20
- pipe(this: unknown) {
21
+ pipe(this: Pipeable) {
21
22
  return pipeArguments(this, arguments)
22
23
  }
23
24
  }
@@ -26,7 +27,7 @@ const attachPipe = <Value extends object>(value: Value): Value => {
26
27
  Object.defineProperty(value, "pipe", {
27
28
  configurable: true,
28
29
  writable: true,
29
- value: function(this: unknown) {
30
+ value: function(this: Value) {
30
31
  return pipeArguments(value, arguments)
31
32
  }
32
33
  })
@@ -53,8 +54,6 @@ const setPath = (
53
54
  current[path[path.length - 1]!] = value
54
55
  }
55
56
 
56
- const pathAlias = (path: readonly string[]): string => path.join("__")
57
-
58
57
  const reboundedColumns = <
59
58
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
60
59
  Alias extends string
@@ -64,13 +63,8 @@ const reboundedColumns = <
64
63
  ): DerivedSelectionOf<SelectionOfPlan<PlanValue>, Alias> => {
65
64
  const ast = getAst(plan)
66
65
  const selection = {} as Record<string, unknown>
67
- for (const projection of flattenSelection(ast.select as Record<string, unknown>)) {
68
- const expectedAlias = pathAlias(projection.path)
69
- if (projection.alias !== expectedAlias) {
70
- throw new Error(
71
- `Derived subqueries currently require path-based output aliases; expected '${expectedAlias}' for path '${projection.path.join(".")}'`
72
- )
73
- }
66
+ const projections = flattenSelection(ast.select as Record<string, unknown>)
67
+ for (const projection of projections) {
74
68
  const expression = projection.expression
75
69
  setPath(selection, projection.path, makeExpression({
76
70
  runtime: undefined as never,
@@ -148,7 +142,7 @@ export const makeLateralSource = <
148
142
  lateral.baseName = alias
149
143
  lateral.dialect = plan[Plan.TypeId].dialect
150
144
  lateral.plan = plan
151
- lateral.required = undefined as never
145
+ lateral.required = currentRequiredList(plan[Plan.TypeId].required) as never
152
146
  lateral.columns = columns
153
147
  return lateral as unknown as LateralSource<PlanValue, Alias>
154
148
  }