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
@@ -6,6 +6,7 @@ import * as RowSet from "./row-set.js"
6
6
  import * as Table from "./table.js"
7
7
  import * as ExpressionAst from "./expression-ast.js"
8
8
  import * as QueryAst from "./query-ast.js"
9
+ import type * as ProjectionAlias from "./projection-alias.js"
9
10
  import type { JsonNode } from "./json/ast.js"
10
11
  import type * as JsonPath from "./json/path.js"
11
12
  import type { QueryCapability } from "./query-requirements.js"
@@ -24,7 +25,7 @@ import type {
24
25
  } from "./predicate/analysis.js"
25
26
  import type { AssumeFactsFalse, AssumeFactsTrue, PredicateContext } from "./predicate/context.js"
26
27
  import type { FormulaOfPredicate } from "./predicate/normalize.js"
27
- import type { ColumnKeyOfAst, ColumnKeyOfExpression, PredicateKeyOfAst } from "./predicate/key.js"
28
+ import type { ColumnKey, ColumnKeyOfAst, ColumnKeyOfExpression, PredicateKeyOfAst } from "./predicate/key.js"
28
29
  import type { PredicateFormula, TrueFormula } from "./predicate/formula.js"
29
30
  import { trueFormula } from "./predicate/runtime.js"
30
31
 
@@ -95,7 +96,7 @@ export { union_query_capabilities } from "./query-requirements.js"
95
96
  * `Pipeable.pipe(...)` plus the metadata stored under `Expression.TypeId`.
96
97
  */
97
98
  const ExpressionProto = {
98
- pipe(this: unknown) {
99
+ pipe(this: Pipeable) {
99
100
  return pipeArguments(this, arguments)
100
101
  }
101
102
  }
@@ -107,7 +108,7 @@ const ExpressionProto = {
107
108
  * chained through `.pipe(...)`.
108
109
  */
109
110
  const PlanProto = {
110
- pipe(this: unknown) {
111
+ pipe(this: Pipeable) {
111
112
  return pipeArguments(this, arguments)
112
113
  }
113
114
  }
@@ -142,6 +143,34 @@ export interface QueryState<
142
143
 
143
144
  /** Effective SQL dialect carried by an expression. */
144
145
  export type DialectOf<Value extends Expression.Any> = Value[typeof Expression.TypeId]["dialect"]
146
+ type ConcreteDialect<D> = D extends "standard" ? never : D
147
+ type IsDialectUnion<Union, All = Union> = Union extends any
148
+ ? [All] extends [Union] ? false : true
149
+ : false
150
+ export type DialectConflictError<A extends string, B extends string> = string & {
151
+ readonly _tag: "DialectConflict"
152
+ readonly left: A
153
+ readonly right: B
154
+ }
155
+ export type MergeDialect<A extends string, B extends string> =
156
+ [ConcreteDialect<A>, ConcreteDialect<B>] extends [never, never] ? "standard"
157
+ : [ConcreteDialect<A>, ConcreteDialect<B>] extends [never, infer C extends string] ? C
158
+ : [ConcreteDialect<A>, ConcreteDialect<B>] extends [infer C extends string, never] ? C
159
+ : ConcreteDialect<A> extends ConcreteDialect<B>
160
+ ? ConcreteDialect<B> extends ConcreteDialect<A>
161
+ ? A
162
+ : DialectConflictError<A, B>
163
+ : DialectConflictError<A, B>
164
+
165
+ /** Collapses the portable standard tag out of a dialect union. */
166
+ export type NormalizeDialect<Dialect extends string> =
167
+ [Dialect] extends [never]
168
+ ? never
169
+ : [Exclude<Dialect, "standard">] extends [never]
170
+ ? "standard"
171
+ : IsDialectUnion<Exclude<Dialect, "standard">> extends true
172
+ ? DialectConflictError<Exclude<Dialect, "standard">, Exclude<Dialect, "standard">>
173
+ : Exclude<Dialect, "standard">
145
174
  /** Source dependency union carried by an expression. */
146
175
  export type DependenciesOf<Value extends Expression.Any> = Expression.DependenciesOf<Value>
147
176
  /** Aggregation kind carried by an expression. */
@@ -281,8 +310,57 @@ type JoinGroupingKeys<Keys extends readonly string[]> = Keys extends readonly []
281
310
  ? `${Head},${JoinGroupingKeys<Tail>}`
282
311
  : string
283
312
 
313
+ type EscapeGroupingBackslashes<Value extends string> = string extends Value
314
+ ? string
315
+ : Value extends `${infer Head}\\${infer Tail}`
316
+ ? `${Head}\\\\${EscapeGroupingBackslashes<Tail>}`
317
+ : Value
318
+
319
+ type EscapeGroupingCommas<Value extends string> = string extends Value
320
+ ? string
321
+ : Value extends `${infer Head},${infer Tail}`
322
+ ? `${Head}\\,${EscapeGroupingCommas<Tail>}`
323
+ : Value
324
+
325
+ type EscapeGroupingPipes<Value extends string> = string extends Value
326
+ ? string
327
+ : Value extends `${infer Head}|${infer Tail}`
328
+ ? `${Head}\\|${EscapeGroupingPipes<Tail>}`
329
+ : Value
330
+
331
+ type EscapeGroupingEquals<Value extends string> = string extends Value
332
+ ? string
333
+ : Value extends `${infer Head}=${infer Tail}`
334
+ ? `${Head}\\=${EscapeGroupingEquals<Tail>}`
335
+ : Value
336
+
337
+ type EscapeGroupingGreaterThan<Value extends string> = string extends Value
338
+ ? string
339
+ : Value extends `${infer Head}>${infer Tail}`
340
+ ? `${Head}\\>${EscapeGroupingGreaterThan<Tail>}`
341
+ : Value
342
+
343
+ type EscapeGroupingText<Value extends string> =
344
+ EscapeGroupingGreaterThan<
345
+ EscapeGroupingEquals<
346
+ EscapeGroupingPipes<
347
+ EscapeGroupingCommas<
348
+ EscapeGroupingBackslashes<Value>
349
+ >
350
+ >
351
+ >
352
+ >
353
+
354
+ type JsonStringKeysGroupingKey<Keys extends readonly string[]> = Keys extends readonly []
355
+ ? ""
356
+ : Keys extends readonly [infer Head extends string]
357
+ ? EscapeGroupingText<Head>
358
+ : Keys extends readonly [infer Head extends string, ...infer Tail extends readonly string[]]
359
+ ? `${EscapeGroupingText<Head>},${JsonStringKeysGroupingKey<Tail>}`
360
+ : string
361
+
284
362
  type JsonSegmentGroupingKey<Segment> =
285
- Segment extends JsonPath.KeySegment<infer Key extends string> ? `key:${Key}` :
363
+ Segment extends JsonPath.KeySegment<infer Key extends string> ? `key:${EscapeGroupingText<Key>}` :
286
364
  Segment extends JsonPath.IndexSegment<infer Index extends number> ? `index:${Index}` :
287
365
  Segment extends JsonPath.WildcardSegment ? "wildcard" :
288
366
  Segment extends JsonPath.SliceSegment<infer Start extends number | undefined, infer End extends number | undefined>
@@ -290,7 +368,7 @@ type JsonSegmentGroupingKey<Segment> =
290
368
  : Segment extends JsonPath.DescendSegment
291
369
  ? "descend"
292
370
  : Segment extends string
293
- ? `key:${Segment}`
371
+ ? `key:${EscapeGroupingText<Segment>}`
294
372
  : Segment extends number
295
373
  ? `index:${Segment}`
296
374
  : "unknown"
@@ -306,13 +384,13 @@ type JsonPathGroupingKey<Segments extends readonly any[]> = Segments extends rea
306
384
  type JsonOpaquePathGroupingKey<Value> =
307
385
  Value extends JsonPath.Path<infer Segments extends readonly JsonPath.CanonicalSegment[]>
308
386
  ? `jsonpath:${JsonPathGroupingKey<Segments>}` :
309
- Value extends string ? `jsonpath:${Value}` :
387
+ Value extends string ? `jsonpath:${EscapeGroupingText<Value>}` :
310
388
  Value extends Expression.Any ? `jsonpath:${GroupingKeyOfExpression<Value>}` :
311
389
  "jsonpath:unknown"
312
390
 
313
391
  type JsonEntryGroupingKey<Entry> =
314
392
  Entry extends { readonly key: infer Key extends string; readonly value: infer Value extends Expression.Any }
315
- ? `${Key}=>${GroupingKeyOfExpression<Value>}`
393
+ ? `${EscapeGroupingText<Key>}=>${GroupingKeyOfExpression<Value>}`
316
394
  : "entry:unknown"
317
395
 
318
396
  type JsonEntriesGroupingKey<Entries extends readonly { readonly key: string; readonly value: Expression.Any }[]> = Entries extends readonly []
@@ -338,13 +416,19 @@ type BranchGroupingKeys<
338
416
 
339
417
  type GroupingKeyOfAst<Ast extends ExpressionAst.Any> =
340
418
  Ast extends ExpressionAst.ColumnNode<infer TableName extends string, infer ColumnName extends string>
341
- ? `column:${TableName}.${ColumnName}`
419
+ ? `column:${ColumnKey<TableName, ColumnName>}`
342
420
  : Ast extends ExpressionAst.LiteralNode<infer Value>
343
421
  ? `literal:${LiteralGroupingKey<Value>}`
344
422
  : Ast extends ExpressionAst.ExcludedNode<infer ColumnName extends string>
345
423
  ? `excluded:${ColumnName}`
346
424
  : Ast extends ExpressionAst.CastNode<infer Value extends Expression.Any, infer Target extends Expression.DbType.Any>
347
425
  ? `cast(${GroupingKeyOfExpression<Value>} as ${Target["dialect"]}:${Target["kind"]})`
426
+ : Ast extends ExpressionAst.CollateNode<infer Value extends Expression.Any, infer Collation extends readonly [string, ...string[]]>
427
+ ? `collate(${GroupingKeyOfExpression<Value>},${JsonStringKeysGroupingKey<Collation>})`
428
+ : Ast extends ExpressionAst.FunctionCallNode<infer Name extends string, infer Args extends readonly Expression.Any[]>
429
+ ? `function(${EscapeGroupingText<Name>},${JoinGroupingKeys<{
430
+ readonly [K in keyof Args]: Args[K] extends Expression.Any ? GroupingKeyOfExpression<Args[K]> : never
431
+ } & readonly string[]>})`
348
432
  : Ast extends ExpressionAst.UnaryNode<infer Kind extends ExpressionAst.UnaryKind, infer Value extends Expression.Any>
349
433
  ? `${Kind}(${GroupingKeyOfExpression<Value>})`
350
434
  : Ast extends ExpressionAst.BinaryNode<infer Kind extends ExpressionAst.BinaryKind, infer Left extends Expression.Any, infer Right extends Expression.Any>
@@ -357,7 +441,7 @@ type GroupingKeyOfAst<Ast extends ExpressionAst.Any> =
357
441
  ? Kind extends "jsonGet" | "jsonPath" | "jsonAccess" | "jsonTraverse" | "jsonGetText" | "jsonPathText" | "jsonAccessText" | "jsonTraverseText"
358
442
  ? `json(${Kind},${GroupingKeyOfExpression<Extract<Ast["value"] | Ast["base"] | Ast["left"], Expression.Any>>},${JsonPathGroupingKey<Extract<Ast["segments"] | Ast["path"], readonly any[]>>})`
359
443
  : Kind extends "jsonHasKey" | "jsonKeyExists" | "jsonHasAnyKeys" | "jsonHasAllKeys"
360
- ? `json(${Kind},${GroupingKeyOfExpression<Extract<Ast["value"] | Ast["base"] | Ast["left"], Expression.Any>>},${JoinGroupingKeys<Extract<Ast["keys"], readonly string[]> & readonly string[]>})`
444
+ ? `json(${Kind},${GroupingKeyOfExpression<Extract<Ast["value"] | Ast["base"] | Ast["left"], Expression.Any>>},${JsonStringKeysGroupingKey<Extract<Ast["keys"], readonly string[]> & readonly string[]>})`
361
445
  : Kind extends "jsonConcat" | "jsonMerge" | "jsonDelete" | "jsonDeletePath" | "jsonRemove" | "jsonSet" | "jsonInsert"
362
446
  ? `json(${Kind},${GroupingKeyOfExpression<Extract<Ast["left"] | Ast["base"] | Ast["value"], Expression.Any>>},${GroupingKeyOfExpression<Extract<Ast["right"] | Ast["newValue"] | Ast["insert"], Expression.Any>>},${JsonPathGroupingKey<Extract<Ast["segments"] | Ast["path"], readonly any[]>>})`
363
447
  : Kind extends "jsonPathExists" | "jsonPathMatch"
@@ -408,15 +492,17 @@ export type ExtractRequired<Selection> = Selection extends Expression.Any
408
492
  }[keyof Selection]
409
493
  : never
410
494
 
411
- /** Walks a selection tree and unions the dialects referenced by its leaves. */
412
- export type ExtractDialect<Selection> = Selection extends Expression.Any
495
+ type ExtractDialectRaw<Selection> = Selection extends Expression.Any
413
496
  ? DialectOf<Selection>
414
497
  : Selection extends Record<string, any>
415
498
  ? {
416
- [K in keyof Selection]: ExtractDialect<Selection[K]>
499
+ [K in keyof Selection]: ExtractDialectRaw<Selection[K]>
417
500
  }[keyof Selection]
418
501
  : never
419
502
 
503
+ /** Walks a selection tree and extracts the effective dialects referenced by its leaves. */
504
+ export type ExtractDialect<Selection> = NormalizeDialect<Extract<ExtractDialectRaw<Selection>, string>>
505
+
420
506
  /**
421
507
  * Minimal table-like shape required by `from(...)` and joins.
422
508
  *
@@ -949,8 +1035,7 @@ export type UpdateInputOfTarget<Target extends MutationTargetInput> =
949
1035
  }>
950
1036
  : never
951
1037
 
952
- /** Extracts the effective dialect from a source. */
953
- export type SourceDialectOf<Source extends SourceLike> =
1038
+ type SourceDialectOfRaw<Source extends SourceLike> =
954
1039
  Source extends TableLike<any, infer Dialect> ? Dialect :
955
1040
  Source extends { readonly kind: "derived"; readonly plan: infer PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any> } ? PlanDialectOf<PlanValue> :
956
1041
  Source extends { readonly kind: "cte"; readonly plan: infer PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any> } ? PlanDialectOf<PlanValue> :
@@ -958,6 +1043,9 @@ export type SourceDialectOf<Source extends SourceLike> =
958
1043
  Source extends { readonly dialect: infer Dialect extends string } ? Dialect :
959
1044
  never
960
1045
 
1046
+ /** Extracts the effective dialect from a source. */
1047
+ export type SourceDialectOf<Source extends SourceLike> = NormalizeDialect<SourceDialectOfRaw<Source>>
1048
+
961
1049
  /** Extracts the base table name from a source. */
962
1050
  export type SourceBaseNameOf<Source extends SourceLike> =
963
1051
  Source extends TableLike<any, any> ? Source[typeof Table.TypeId]["baseName"] :
@@ -1000,6 +1088,153 @@ type JoinPath<Segments extends readonly string[]> = Segments extends readonly []
1000
1088
  ? `${Head}__${JoinPath<Tail>}`
1001
1089
  : string
1002
1090
 
1091
+ type ProjectionAliasOf<
1092
+ Value extends Expression.Any,
1093
+ Path extends readonly string[]
1094
+ > = Value extends {
1095
+ readonly [ProjectionAlias.TypeId]: ProjectionAlias.State<infer Alias extends string>
1096
+ } ? Alias : JoinPath<Path>
1097
+
1098
+ type SelectionProjectionEntry<
1099
+ Alias extends string,
1100
+ Path extends readonly string[],
1101
+ ExpectedAlias extends string
1102
+ > = {
1103
+ readonly alias: Alias
1104
+ readonly path: Path
1105
+ readonly expectedAlias: ExpectedAlias
1106
+ }
1107
+
1108
+ type SelectionProjectionEntries<
1109
+ Selection,
1110
+ Path extends readonly string[] = []
1111
+ > = Selection extends Expression.Any
1112
+ ? SelectionProjectionEntry<ProjectionAliasOf<Selection, Path>, Path, JoinPath<Path>>
1113
+ : Selection extends Record<string, any>
1114
+ ? {
1115
+ readonly [K in Extract<keyof Selection, string>]:
1116
+ SelectionProjectionEntries<Selection[K], [...Path, K]>
1117
+ }[Extract<keyof Selection, string>]
1118
+ : never
1119
+
1120
+ type SameProjectionPath<
1121
+ Left extends readonly string[],
1122
+ Right extends readonly string[]
1123
+ > = Left extends readonly []
1124
+ ? Right extends readonly [] ? true : false
1125
+ : Left extends readonly [infer LeftHead extends string, ...infer LeftTail extends readonly string[]]
1126
+ ? Right extends readonly [infer RightHead extends string, ...infer RightTail extends readonly string[]]
1127
+ ? [LeftHead] extends [RightHead]
1128
+ ? [RightHead] extends [LeftHead]
1129
+ ? SameProjectionPath<LeftTail, RightTail>
1130
+ : false
1131
+ : false
1132
+ : false
1133
+ : false
1134
+
1135
+ type SameProjectionAlias<
1136
+ Left extends string,
1137
+ Right extends string
1138
+ > = [Left] extends [Right] ? [Right] extends [Left] ? true : false : false
1139
+
1140
+ type HasDifferentPathForAlias<
1141
+ Entries,
1142
+ Alias extends string,
1143
+ Path extends readonly string[]
1144
+ > = Entries extends SelectionProjectionEntry<infer EntryAlias, infer EntryPath, any>
1145
+ ? SameProjectionAlias<EntryAlias, Alias> extends true
1146
+ ? SameProjectionPath<EntryPath, Path> extends true ? never : true
1147
+ : never
1148
+ : never
1149
+
1150
+ type DuplicateProjectionAliases<
1151
+ Entries,
1152
+ AllEntries = Entries
1153
+ > = Entries extends SelectionProjectionEntry<infer Alias, infer Path, any>
1154
+ ? string extends Alias ? never
1155
+ : true extends HasDifferentPathForAlias<AllEntries, Alias, Path> ? Alias : never
1156
+ : never
1157
+
1158
+ type ProjectionAliasMismatches<Entries> =
1159
+ Entries extends SelectionProjectionEntry<infer Alias, any, infer ExpectedAlias>
1160
+ ? string extends Alias ? never
1161
+ : string extends ExpectedAlias ? never
1162
+ : SameProjectionAlias<Alias, ExpectedAlias> extends true ? never : Alias
1163
+ : never
1164
+
1165
+ type DerivedProjectionDuplicateAliases<Selection> =
1166
+ DuplicateProjectionAliases<SelectionProjectionEntries<Selection>>
1167
+
1168
+ type DerivedProjectionAliasMismatches<Selection> =
1169
+ ProjectionAliasMismatches<SelectionProjectionEntries<Selection>>
1170
+
1171
+ type IsAny<Value> = 0 extends (1 & Value) ? true : false
1172
+
1173
+ type IsBroadSelection<Selection> =
1174
+ IsAny<Selection> extends true ? true :
1175
+ unknown extends Selection ? true : false
1176
+
1177
+ type DerivedProjectionIssues<Selection> =
1178
+ IsBroadSelection<Selection> extends true
1179
+ ? never
1180
+ : | DerivedProjectionDuplicateAliases<Selection>
1181
+ | DerivedProjectionAliasMismatches<Selection>
1182
+
1183
+ export type SelectionProjectionDuplicateAliases<Selection> =
1184
+ IsBroadSelection<Selection> extends true
1185
+ ? never
1186
+ : DuplicateProjectionAliases<SelectionProjectionEntries<Selection>>
1187
+
1188
+ export type SelectionProjectionAliasCollisionError<Selection> = Selection & {
1189
+ readonly __effect_qb_error__: "effect-qb: projection aliases must be unique"
1190
+ readonly __effect_qb_duplicate_projection_aliases__: SelectionProjectionDuplicateAliases<Selection>
1191
+ }
1192
+
1193
+ export type SelectionProjectionAliasCollisionConstraint<Selection> =
1194
+ [SelectionProjectionDuplicateAliases<Selection>] extends [never]
1195
+ ? unknown
1196
+ : SelectionProjectionAliasCollisionError<Selection>
1197
+
1198
+ export type DerivedSourceProjectionCompatibilityError<
1199
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1200
+ > = PlanValue & {
1201
+ readonly __effect_qb_error__: "effect-qb: derived subqueries require unique path-based projection aliases"
1202
+ readonly __effect_qb_duplicate_projection_aliases__: DerivedProjectionDuplicateAliases<SelectionOfPlan<PlanValue>>
1203
+ readonly __effect_qb_alias_mismatches__: DerivedProjectionAliasMismatches<SelectionOfPlan<PlanValue>>
1204
+ readonly __effect_qb_hint__: "Use unique nested selection paths and do not override projection aliases inside derived subqueries"
1205
+ }
1206
+
1207
+ export type DerivedProjectionCompatiblePlan<
1208
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
1209
+ ValidPlan = PlanValue
1210
+ > = [DerivedProjectionIssues<SelectionOfPlan<PlanValue>>] extends [never]
1211
+ ? ValidPlan
1212
+ : ValidPlan & DerivedSourceProjectionCompatibilityError<PlanValue>
1213
+
1214
+ export type DerivedSourceCompatiblePlan<
1215
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1216
+ > = DerivedProjectionCompatiblePlan<PlanValue, CompletePlan<PlanValue>>
1217
+
1218
+ type InlineSourceStatementError<
1219
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1220
+ > = PlanValue & {
1221
+ readonly __effect_qb_error__: "effect-qb: inline derived sources only accept select-like query plans"
1222
+ readonly __effect_qb_statement__: StatementOfPlan<PlanValue>
1223
+ readonly __effect_qb_hint__: "Use select(...) or a set operator for as(...) and lateral(...); use with(...) for data-modifying CTEs where supported"
1224
+ }
1225
+
1226
+ export type DerivedTableCompatiblePlan<
1227
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1228
+ > = StatementOfPlan<PlanValue> extends SelectLikeStatement
1229
+ ? DerivedSourceCompatiblePlan<PlanValue>
1230
+ : InlineSourceStatementError<PlanValue>
1231
+
1232
+ export type LateralSourceCompatiblePlan<
1233
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1234
+ > = StatementOfPlan<PlanValue> extends SelectLikeStatement
1235
+ ? DerivedProjectionCompatiblePlan<PlanValue>
1236
+ : InlineSourceStatementError<PlanValue>
1237
+
1003
1238
  type DerivedLeafExpression<
1004
1239
  Value extends Expression.Any,
1005
1240
  Alias extends string,
@@ -1066,7 +1301,7 @@ export type AvailableOfPlan<
1066
1301
  /** Extracts the effective dialect carried by a query plan. */
1067
1302
  export type PlanDialectOf<
1068
1303
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
1069
- > = QueryPlanParts<PlanValue>["dialect"]
1304
+ > = NormalizeDialect<QueryPlanParts<PlanValue>["dialect"]>
1070
1305
  /** Extracts the grouped-source phantom carried by a query plan. */
1071
1306
  export type GroupedOfPlan<
1072
1307
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
@@ -1085,6 +1320,12 @@ export type AssumptionsOfPlan<
1085
1320
  export type FactsOfPlan<
1086
1321
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
1087
1322
  > = QueryPlanState<PlanValue>["facts"]
1323
+ export type CommonSetFacts<
1324
+ Left extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
1325
+ Right extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
1326
+ > = [FactsOfPlan<Left>] extends [FactsOfPlan<Right>]
1327
+ ? [FactsOfPlan<Right>] extends [FactsOfPlan<Left>] ? FactsOfPlan<Left> : EmptyFacts
1328
+ : EmptyFacts
1088
1329
  export type PredicateStateOfPlan<
1089
1330
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
1090
1331
  > = PredicateState<AssumptionsOfPlan<PlanValue>, FactsOfPlan<PlanValue>>
@@ -1217,9 +1458,10 @@ export type AddJoinRequired<
1217
1458
  Available extends Record<string, RowSet.AnySource>,
1218
1459
  JoinedName extends string,
1219
1460
  Predicate extends PredicateInput | never,
1220
- Kind extends QueryAst.JoinKind = "inner"
1461
+ Kind extends QueryAst.JoinKind = "inner",
1462
+ SourceRequired extends string = never
1221
1463
  > = Exclude<
1222
- Required | (Predicate extends never ? never : RequiredFromInput<Predicate>),
1464
+ Required | SourceRequired | (Predicate extends never ? never : RequiredFromInput<Predicate>),
1223
1465
  AvailableNames<AvailableAfterJoin<Available, JoinedName, Kind>>
1224
1466
  >
1225
1467
 
@@ -1270,7 +1512,7 @@ export type MergeNullabilityTuple<
1270
1512
  /** Dialect union across a tuple of expressions. */
1271
1513
  export type TupleDialect<
1272
1514
  Values extends readonly Expression.Any[]
1273
- > = Values[number] extends never ? never : DialectOf<Values[number]>
1515
+ > = Values[number] extends never ? never : NormalizeDialect<DialectOf<Values[number]>>
1274
1516
 
1275
1517
  /** Converts a union into an intersection. */
1276
1518
  type UnionToIntersection<Union> = (
@@ -1744,30 +1986,45 @@ type JsonLiteralSetsForColumn<
1744
1986
  ? Paths
1745
1987
  : {}
1746
1988
 
1989
+ type JsonPathHead<
1990
+ Path extends string,
1991
+ Current extends string = ""
1992
+ > = Path extends `\\.${infer Rest}`
1993
+ ? JsonPathHead<Rest, `${Current}.`>
1994
+ : Path extends `\\\\${infer Rest}`
1995
+ ? JsonPathHead<Rest, `${Current}\\`>
1996
+ : Path extends `.${infer Tail}`
1997
+ ? readonly [Current, Tail]
1998
+ : Path extends `${infer Character}${infer Rest}`
1999
+ ? JsonPathHead<Rest, `${Current}${Character}`>
2000
+ : readonly [Current, ""]
2001
+
1747
2002
  type RefineJsonRuntimeAtPath<
1748
2003
  Runtime,
1749
2004
  Path extends string,
1750
2005
  Values
1751
2006
  > = Runtime extends unknown
1752
- ? Path extends `${infer Head}.${infer Tail}`
1753
- ? Runtime extends object
1754
- ? Head extends keyof Runtime
1755
- ? RefineJsonRuntimeAtPath<NonNullable<Runtime[Head]>, Tail, Values> extends infer Refined
1756
- ? [Refined] extends [never]
1757
- ? never
1758
- : Omit<Runtime, Head> & { readonly [K in Head]: Refined }
2007
+ ? JsonPathHead<Path> extends readonly [infer Head extends string, infer Tail extends string]
2008
+ ? Tail extends ""
2009
+ ? Runtime extends object
2010
+ ? Head extends keyof Runtime
2011
+ ? RefineRuntimeByAllowedLiterals<NonNullable<Runtime[Head]>, Values> extends infer Refined
2012
+ ? [Refined] extends [never]
2013
+ ? never
2014
+ : Omit<Runtime, Head> & { readonly [K in Head]: Refined }
2015
+ : never
1759
2016
  : never
1760
- : never
1761
- : never
1762
- : Runtime extends object
1763
- ? Path extends keyof Runtime
1764
- ? RefineRuntimeByAllowedLiterals<NonNullable<Runtime[Path]>, Values> extends infer Refined
1765
- ? [Refined] extends [never]
1766
- ? never
1767
- : Omit<Runtime, Path> & { readonly [K in Path]: Refined }
2017
+ : RefineRuntimeByAllowedLiterals<NonNullable<Runtime>, Values>
2018
+ : Runtime extends object
2019
+ ? Head extends keyof Runtime
2020
+ ? RefineJsonRuntimeAtPath<NonNullable<Runtime[Head]>, Tail, Values> extends infer Refined
2021
+ ? [Refined] extends [never]
2022
+ ? never
2023
+ : Omit<Runtime, Head> & { readonly [K in Head]: Refined }
2024
+ : never
1768
2025
  : never
1769
2026
  : never
1770
- : RefineRuntimeByAllowedLiterals<NonNullable<Runtime>, Values>
2027
+ : never
1771
2028
  : never
1772
2029
 
1773
2030
  type RefineJsonRuntimeWithConstraints<
@@ -1914,7 +2171,7 @@ type DialectCompatibilityError<
1914
2171
  EngineDialect extends string
1915
2172
  > = PlanValue & {
1916
2173
  readonly __effect_qb_error__: "effect-qb: plan dialect is not compatible with the target renderer or executor"
1917
- readonly __effect_qb_plan_dialect__: PlanValue[typeof RowSet.TypeId]["dialect"]
2174
+ readonly __effect_qb_plan_dialect__: PlanDialectOf<PlanValue>
1918
2175
  readonly __effect_qb_target_dialect__: EngineDialect
1919
2176
  readonly __effect_qb_hint__: "Use the matching dialect module or renderer/executor"
1920
2177
  }
@@ -1965,27 +2222,39 @@ type IsDialectCompatible<
1965
2222
  EngineDialect extends string
1966
2223
  > = [PlanDialect] extends [never]
1967
2224
  ? true
1968
- : Extract<PlanDialect, EngineDialect> extends never
1969
- ? false
1970
- : true
2225
+ : Exclude<PlanDialect, EngineDialect | "standard"> extends never
2226
+ ? true
2227
+ : false
1971
2228
 
1972
2229
  /** Narrows a complete plan to those compatible with a target engine dialect. */
1973
2230
  export type DialectCompatiblePlan<
1974
2231
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
1975
2232
  EngineDialect extends string
1976
- > = IsDialectCompatible<PlanValue[typeof RowSet.TypeId]["dialect"], EngineDialect> extends true
2233
+ > = IsDialectCompatible<PlanDialectOf<PlanValue>, EngineDialect> extends true
1977
2234
  ? CompletePlan<PlanValue>
1978
2235
  : DialectCompatibilityError<PlanValue, EngineDialect>
1979
2236
 
2237
+ type SelectLikeStatement = "select" | "set"
2238
+
2239
+ type NestedPlanStatementError<
2240
+ PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
2241
+ > = PlanValue & {
2242
+ readonly __effect_qb_error__: "effect-qb: subquery expressions only accept select-like query plans"
2243
+ readonly __effect_qb_statement__: StatementOfPlan<PlanValue>
2244
+ readonly __effect_qb_hint__: "Use select(...) or a set operator as the nested subquery expression"
2245
+ }
2246
+
1980
2247
  /** Nested-plan compatibility used by subquery expressions such as `exists(...)`. */
1981
2248
  export type DialectCompatibleNestedPlan<
1982
2249
  PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
1983
2250
  EngineDialect extends string
1984
- > = IsDialectCompatible<PlanValue[typeof RowSet.TypeId]["dialect"], EngineDialect> extends true
1985
- ? AggregationCompatiblePlan<PlanValue>
2251
+ > = IsDialectCompatible<PlanDialectOf<PlanValue>, EngineDialect> extends true
2252
+ ? StatementOfPlan<PlanValue> extends SelectLikeStatement
2253
+ ? AggregationCompatiblePlan<PlanValue>
2254
+ : NestedPlanStatementError<PlanValue>
1986
2255
  : DialectCompatibilityError<PlanValue, EngineDialect>
1987
2256
 
1988
- type SetOperandStatement = "select" | "set"
2257
+ type SetOperandStatement = SelectLikeStatement
1989
2258
  type IsUnion<Value, All = Value> = Value extends any ? ([All] extends [Value] ? false : true) : never
1990
2259
 
1991
2260
  type SingleSelectedExpressionError<
@@ -2205,7 +2474,7 @@ export const makeExpression = <
2205
2474
  Object.defineProperty(expression, "pipe", {
2206
2475
  configurable: true,
2207
2476
  writable: true,
2208
- value: function(this: unknown) {
2477
+ value: function(this: Pipeable) {
2209
2478
  return pipeArguments(expression, arguments)
2210
2479
  }
2211
2480
  })
@@ -2255,7 +2524,7 @@ export const makePlan = <
2255
2524
  Object.defineProperty(plan, "pipe", {
2256
2525
  configurable: true,
2257
2526
  writable: true,
2258
- value: function(this: unknown) {
2527
+ value: function(this: Pipeable) {
2259
2528
  return pipeArguments(plan, arguments)
2260
2529
  }
2261
2530
  })
@@ -2314,16 +2583,8 @@ export const extractRequiredRuntime = (selection: SelectionShape): readonly stri
2314
2583
 
2315
2584
  /** Extracts the single top-level expression from a scalar subquery selection. */
2316
2585
  export const extractSingleSelectedExpressionRuntime = (selection: SelectionShape): Expression.Any => {
2317
- const keys = Object.keys(selection)
2318
- if (keys.length !== 1) {
2319
- throw new Error("scalar subqueries must select exactly one top-level expression")
2320
- }
2321
- const record = selection as Record<string, unknown>
2322
- const value = record[keys[0]!]
2323
- if (value === null || typeof value !== "object" || !(Expression.TypeId in (value as object))) {
2324
- throw new Error("scalar subqueries must select a scalar expression")
2325
- }
2326
- return value as unknown as Expression.Any
2586
+ const record = selection as Record<string, Expression.Any>
2587
+ return record[Object.keys(record)[0]!]!
2327
2588
  }
2328
2589
 
2329
2590
  /** Converts the plan's runtime `required` metadata into a mutable string list. */
@@ -1,6 +1,6 @@
1
1
  import * as Query from "./query.js"
2
- import type * as Expression from "./scalar.js"
3
- import { type Projection, validateProjections } from "./projections.js"
2
+ import * as Expression from "./scalar.js"
3
+ import { flattenSelection, type Projection, validateProjections } from "./projections.js"
4
4
 
5
5
  /** Symbol used to attach rendered-query phantom row metadata. */
6
6
  export const TypeId: unique symbol = Symbol.for("effect-qb/Renderer")
@@ -37,14 +37,13 @@ export type RowOf<Value extends RenderedQuery<any, any>> = Value[typeof TypeId][
37
37
  *
38
38
  * Renderers only accept complete, dialect-compatible plans. The returned
39
39
  * `RenderedQuery` keeps the canonical `Query.ResultRow<...>` type attached for
40
- * downstream executor layers, and the built-in renderer also performs a
41
- * matching runtime aggregate-shape validation.
40
+ * downstream executor layers.
42
41
  */
43
42
  export interface Renderer<Dialect extends string = string> {
44
43
  readonly dialect: Dialect
45
44
  render<PlanValue extends Query.Plan.Any>(
46
45
  plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
47
- ): RenderedQuery<any, Dialect>
46
+ ): RenderedQuery<Query.ResultRow<PlanValue>, Dialect>
48
47
  }
49
48
 
50
49
  type CustomRender<Dialect extends string> = <PlanValue extends Query.Plan.Any>(
@@ -56,6 +55,29 @@ type CustomRender<Dialect extends string> = <PlanValue extends Query.Plan.Any>(
56
55
  readonly valueMappings?: Expression.DriverValueMappings
57
56
  }
58
57
 
58
+ const projectionPathKey = (path: readonly string[]): string => JSON.stringify(path)
59
+
60
+ const formatProjectionPath = (path: readonly string[]): string => path.join(".")
61
+
62
+ const validateProjectionPathsMatchSelection = (
63
+ plan: Query.Plan.Any,
64
+ projections: readonly Projection[]
65
+ ): void => {
66
+ const expected = flattenSelection(Query.getAst(plan).select as Record<string, unknown>)
67
+ const expectedPaths = new Set(expected.map((projection) => projectionPathKey(projection.path)))
68
+ const actualPaths = new Set(projections.map((projection) => projectionPathKey(projection.path)))
69
+ for (const projection of projections) {
70
+ if (!expectedPaths.has(projectionPathKey(projection.path))) {
71
+ throw new Error(`Projection path ${formatProjectionPath(projection.path)} does not exist in the query selection`)
72
+ }
73
+ }
74
+ for (const projection of expected) {
75
+ if (!actualPaths.has(projectionPathKey(projection.path))) {
76
+ throw new Error(`Projection path ${formatProjectionPath(projection.path)} is missing from rendered projections`)
77
+ }
78
+ }
79
+ }
80
+
59
81
  /**
60
82
  * Constructs a renderer from a dialect and implementation callback.
61
83
  */
@@ -67,6 +89,26 @@ export function make<Dialect extends string>(
67
89
  dialect: Dialect,
68
90
  render: CustomRender<Dialect>
69
91
  ): Renderer<Dialect> {
92
+ return makeRenderer(dialect, render, true)
93
+ }
94
+
95
+ /** Internal renderer factory for built-in renderers that derive projections from typed plans. */
96
+ export function makeTrusted<Dialect extends string>(
97
+ dialect: Dialect,
98
+ render: CustomRender<Dialect>
99
+ ): Renderer<Dialect>
100
+ export function makeTrusted<Dialect extends string>(
101
+ dialect: Dialect,
102
+ render: CustomRender<Dialect>
103
+ ): Renderer<Dialect> {
104
+ return makeRenderer(dialect, render, false)
105
+ }
106
+
107
+ const makeRenderer = <Dialect extends string>(
108
+ dialect: Dialect,
109
+ render: CustomRender<Dialect>,
110
+ validate: boolean
111
+ ): Renderer<Dialect> => {
70
112
  if (typeof render !== "function") {
71
113
  throw new Error(`Renderer.make requires an explicit render implementation for dialect: ${dialect}`)
72
114
  }
@@ -75,7 +117,10 @@ export function make<Dialect extends string>(
75
117
  render(plan) {
76
118
  const rendered = render(plan)
77
119
  const projections = rendered.projections ?? []
78
- validateProjections(projections)
120
+ if (validate) {
121
+ validateProjections(projections)
122
+ validateProjectionPathsMatchSelection(plan as Query.Plan.Any, projections)
123
+ }
79
124
  return {
80
125
  sql: rendered.sql,
81
126
  params: rendered.params ?? [],