effect-qb 0.14.0 → 0.16.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 (146) hide show
  1. package/dist/mysql.js +61555 -4252
  2. package/dist/postgres/metadata.js +728 -104
  3. package/dist/postgres.js +6906 -4023
  4. package/package.json +15 -2
  5. package/src/internal/aggregation-validation.ts +3 -3
  6. package/src/internal/case-analysis.d.ts +18 -0
  7. package/src/internal/case-analysis.ts +4 -4
  8. package/src/internal/coercion/analysis.d.ts +7 -0
  9. package/src/internal/{coercion-analysis.ts → coercion/analysis.ts} +3 -3
  10. package/src/internal/coercion/errors.d.ts +17 -0
  11. package/src/internal/{coercion-errors.ts → coercion/errors.ts} +1 -1
  12. package/src/internal/coercion/kind.d.ts +4 -0
  13. package/src/internal/{coercion-kind.ts → coercion/kind.ts} +2 -2
  14. package/src/internal/{coercion-normalize.ts → coercion/normalize.ts} +1 -1
  15. package/src/internal/coercion/rules.d.ts +6 -0
  16. package/src/internal/{coercion-rules.ts → coercion/rules.ts} +2 -2
  17. package/src/internal/column-state.d.ts +190 -0
  18. package/src/internal/column-state.ts +43 -47
  19. package/src/internal/column.ts +43 -305
  20. package/src/internal/datatypes/define.d.ts +17 -0
  21. package/src/internal/datatypes/define.ts +18 -4
  22. package/src/internal/datatypes/lookup.d.ts +44 -0
  23. package/src/internal/datatypes/lookup.ts +61 -152
  24. package/src/internal/datatypes/shape.d.ts +16 -0
  25. package/src/internal/datatypes/shape.ts +1 -1
  26. package/src/internal/derived-table.d.ts +4 -0
  27. package/src/internal/derived-table.ts +21 -16
  28. package/src/internal/dialect.ts +12 -1
  29. package/src/internal/dsl-mutation-runtime.ts +378 -0
  30. package/src/internal/dsl-plan-runtime.ts +387 -0
  31. package/src/internal/dsl-query-runtime.ts +160 -0
  32. package/src/internal/dsl-transaction-ddl-runtime.ts +263 -0
  33. package/src/internal/executor.ts +146 -34
  34. package/src/internal/expression-ast.ts +15 -5
  35. package/src/internal/grouping-key.d.ts +3 -0
  36. package/src/internal/grouping-key.ts +1 -1
  37. package/src/internal/implication-runtime.d.ts +15 -0
  38. package/src/internal/implication-runtime.ts +4 -4
  39. package/src/internal/json/ast.d.ts +30 -0
  40. package/src/internal/json/ast.ts +1 -1
  41. package/src/internal/json/errors.d.ts +8 -0
  42. package/src/internal/json/path.d.ts +75 -0
  43. package/src/internal/json/path.ts +1 -1
  44. package/src/internal/json/types.d.ts +62 -0
  45. package/src/internal/predicate/analysis.d.ts +20 -0
  46. package/src/internal/predicate/analysis.ts +183 -0
  47. package/src/internal/predicate/atom.d.ts +28 -0
  48. package/src/internal/{predicate-atom.ts → predicate/atom.ts} +7 -0
  49. package/src/internal/{predicate-branches.ts → predicate/branches.ts} +2 -2
  50. package/src/internal/predicate/context.d.ts +67 -0
  51. package/src/internal/{predicate-context.ts → predicate/context.ts} +163 -20
  52. package/src/internal/predicate/formula.d.ts +35 -0
  53. package/src/internal/{predicate-formula.ts → predicate/formula.ts} +1 -1
  54. package/src/internal/predicate/key.d.ts +11 -0
  55. package/src/internal/predicate/key.ts +73 -0
  56. package/src/internal/{predicate-nnf.ts → predicate/nnf.ts} +2 -2
  57. package/src/internal/predicate/normalize.d.ts +53 -0
  58. package/src/internal/{predicate-normalize.ts → predicate/normalize.ts} +130 -49
  59. package/src/internal/predicate/runtime.d.ts +31 -0
  60. package/src/internal/{predicate-runtime.ts → predicate/runtime.ts} +127 -17
  61. package/src/internal/projection-alias.d.ts +13 -0
  62. package/src/internal/projections.d.ts +31 -0
  63. package/src/internal/projections.ts +1 -1
  64. package/src/internal/query-ast.d.ts +217 -0
  65. package/src/internal/query-ast.ts +1 -1
  66. package/src/internal/query-requirements.d.ts +20 -0
  67. package/src/internal/query.d.ts +775 -0
  68. package/src/internal/query.ts +683 -369
  69. package/src/internal/renderer.ts +11 -21
  70. package/src/internal/row-set.d.ts +53 -0
  71. package/src/internal/{plan.ts → row-set.ts} +11 -9
  72. package/src/internal/runtime/driver-value-mapping.ts +186 -0
  73. package/src/internal/{runtime-normalize.ts → runtime/normalize.ts} +9 -31
  74. package/src/internal/{runtime-schema.ts → runtime/schema.ts} +13 -38
  75. package/src/internal/runtime/value.d.ts +22 -0
  76. package/src/internal/{runtime-value.ts → runtime/value.ts} +2 -2
  77. package/src/internal/scalar.d.ts +107 -0
  78. package/src/internal/scalar.ts +202 -0
  79. package/src/internal/schema-derivation.d.ts +105 -0
  80. package/src/internal/schema-expression.d.ts +18 -0
  81. package/src/internal/schema-expression.ts +38 -7
  82. package/src/internal/table-options.d.ts +94 -0
  83. package/src/internal/table-options.ts +8 -2
  84. package/src/internal/table.d.ts +173 -0
  85. package/src/internal/table.ts +32 -14
  86. package/src/mysql/column.ts +95 -18
  87. package/src/mysql/datatypes/index.ts +47 -7
  88. package/src/mysql/errors/generated.ts +57336 -0
  89. package/src/mysql/errors/index.ts +1 -0
  90. package/src/mysql/errors/normalize.ts +55 -53
  91. package/src/mysql/errors/types.ts +74 -0
  92. package/src/mysql/executor.ts +88 -11
  93. package/src/mysql/function/aggregate.ts +1 -5
  94. package/src/mysql/function/core.ts +1 -4
  95. package/src/mysql/function/index.ts +0 -1
  96. package/src/mysql/function/string.ts +1 -5
  97. package/src/mysql/function/temporal.ts +12 -15
  98. package/src/mysql/function/window.ts +1 -6
  99. package/src/{internal/mysql-dialect.ts → mysql/internal/dialect.ts} +12 -6
  100. package/src/{internal/mysql-query.ts → mysql/internal/dsl.ts} +1299 -2143
  101. package/src/mysql/internal/renderer.ts +46 -0
  102. package/src/mysql/internal/sql-expression-renderer.ts +1501 -0
  103. package/src/mysql/json.ts +2 -0
  104. package/src/mysql/query.ts +111 -91
  105. package/src/mysql/renderer.ts +8 -3
  106. package/src/mysql/table.ts +1 -1
  107. package/src/mysql.ts +6 -4
  108. package/src/postgres/cast.ts +30 -16
  109. package/src/postgres/column.ts +179 -46
  110. package/src/postgres/datatypes/index.d.ts +515 -0
  111. package/src/postgres/datatypes/index.ts +22 -13
  112. package/src/postgres/datatypes/spec.d.ts +412 -0
  113. package/src/postgres/errors/generated.ts +2636 -0
  114. package/src/postgres/errors/index.ts +1 -0
  115. package/src/postgres/errors/normalize.ts +47 -62
  116. package/src/postgres/errors/types.ts +92 -34
  117. package/src/postgres/executor.ts +54 -7
  118. package/src/postgres/function/aggregate.ts +1 -5
  119. package/src/postgres/function/core.ts +12 -6
  120. package/src/postgres/function/index.ts +0 -1
  121. package/src/postgres/function/string.ts +1 -5
  122. package/src/postgres/function/temporal.ts +12 -15
  123. package/src/postgres/function/window.ts +1 -6
  124. package/src/{internal/postgres-dialect.ts → postgres/internal/dialect.ts} +12 -6
  125. package/src/{internal/postgres-query.ts → postgres/internal/dsl.ts} +1356 -2133
  126. package/src/{internal/postgres-renderer.ts → postgres/internal/renderer.ts} +17 -8
  127. package/src/postgres/internal/schema-ddl.ts +108 -0
  128. package/src/{internal/postgres-schema-model.ts → postgres/internal/schema-model.ts} +12 -6
  129. package/src/{internal → postgres/internal}/sql-expression-renderer.ts +79 -25
  130. package/src/postgres/{function/json.ts → json.ts} +77 -85
  131. package/src/postgres/metadata.ts +2 -2
  132. package/src/postgres/query.ts +113 -89
  133. package/src/postgres/renderer.ts +8 -13
  134. package/src/postgres/schema-expression.ts +2 -1
  135. package/src/postgres/schema-management.ts +1 -1
  136. package/src/postgres/table.ts +12 -4
  137. package/src/postgres/type.ts +33 -2
  138. package/src/postgres.ts +6 -4
  139. package/src/internal/expression.ts +0 -327
  140. package/src/internal/mysql-renderer.ts +0 -37
  141. package/src/internal/predicate-analysis.ts +0 -81
  142. package/src/internal/predicate-key.ts +0 -28
  143. package/src/internal/schema-ddl.ts +0 -55
  144. package/src/mysql/function/json.ts +0 -4
  145. package/src/mysql/private/query.ts +0 -1
  146. package/src/postgres/private/query.ts +0 -1
@@ -0,0 +1,263 @@
1
+ import * as Plan from "./row-set.js"
2
+
3
+ type DslTransactionDdlRuntimeContext = {
4
+ readonly profile: {
5
+ readonly dialect: string
6
+ }
7
+ readonly makePlan: (...args: readonly any[]) => any
8
+ readonly targetSourceDetails: (target: any) => { readonly sourceName: string; readonly sourceBaseName: string }
9
+ readonly normalizeColumnList: (columns: string | readonly string[]) => readonly string[]
10
+ readonly defaultIndexName: (tableName: string, columns: readonly string[], unique: boolean) => string
11
+ }
12
+
13
+ export const makeDslTransactionDdlRuntime = (ctx: DslTransactionDdlRuntimeContext) => {
14
+ const transaction = (options: { readonly isolationLevel?: any; readonly readOnly?: boolean } = {}) =>
15
+ ctx.makePlan({
16
+ selection: {},
17
+ required: [],
18
+ available: {},
19
+ dialect: ctx.profile.dialect
20
+ }, {
21
+ kind: "transaction",
22
+ select: {},
23
+ transaction: {
24
+ kind: "transaction",
25
+ isolationLevel: options.isolationLevel,
26
+ readOnly: options.readOnly
27
+ },
28
+ where: [],
29
+ having: [],
30
+ joins: [],
31
+ groupBy: [],
32
+ orderBy: []
33
+ }, undefined, "transaction", "transaction")
34
+
35
+ const commit = () =>
36
+ ctx.makePlan({
37
+ selection: {},
38
+ required: [],
39
+ available: {},
40
+ dialect: ctx.profile.dialect
41
+ }, {
42
+ kind: "commit",
43
+ select: {},
44
+ transaction: {
45
+ kind: "commit"
46
+ },
47
+ where: [],
48
+ having: [],
49
+ joins: [],
50
+ groupBy: [],
51
+ orderBy: []
52
+ }, undefined, "transaction", "commit")
53
+
54
+ const rollback = () =>
55
+ ctx.makePlan({
56
+ selection: {},
57
+ required: [],
58
+ available: {},
59
+ dialect: ctx.profile.dialect
60
+ }, {
61
+ kind: "rollback",
62
+ select: {},
63
+ transaction: {
64
+ kind: "rollback"
65
+ },
66
+ where: [],
67
+ having: [],
68
+ joins: [],
69
+ groupBy: [],
70
+ orderBy: []
71
+ }, undefined, "transaction", "rollback")
72
+
73
+ const savepoint = (name: string) =>
74
+ ctx.makePlan({
75
+ selection: {},
76
+ required: [],
77
+ available: {},
78
+ dialect: ctx.profile.dialect
79
+ }, {
80
+ kind: "savepoint",
81
+ select: {},
82
+ transaction: {
83
+ kind: "savepoint",
84
+ name
85
+ },
86
+ where: [],
87
+ having: [],
88
+ joins: [],
89
+ groupBy: [],
90
+ orderBy: []
91
+ }, undefined, "transaction", "savepoint")
92
+
93
+ const rollbackTo = (name: string) =>
94
+ ctx.makePlan({
95
+ selection: {},
96
+ required: [],
97
+ available: {},
98
+ dialect: ctx.profile.dialect
99
+ }, {
100
+ kind: "rollbackTo",
101
+ select: {},
102
+ transaction: {
103
+ kind: "rollbackTo",
104
+ name
105
+ },
106
+ where: [],
107
+ having: [],
108
+ joins: [],
109
+ groupBy: [],
110
+ orderBy: []
111
+ }, undefined, "transaction", "rollbackTo")
112
+
113
+ const releaseSavepoint = (name: string) =>
114
+ ctx.makePlan({
115
+ selection: {},
116
+ required: [],
117
+ available: {},
118
+ dialect: ctx.profile.dialect
119
+ }, {
120
+ kind: "releaseSavepoint",
121
+ select: {},
122
+ transaction: {
123
+ kind: "releaseSavepoint",
124
+ name
125
+ },
126
+ where: [],
127
+ having: [],
128
+ joins: [],
129
+ groupBy: [],
130
+ orderBy: []
131
+ }, undefined, "transaction", "releaseSavepoint")
132
+
133
+ const createTable = (target: any, options: { readonly ifNotExists?: boolean } = {}) => {
134
+ const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target)
135
+ return ctx.makePlan({
136
+ selection: {},
137
+ required: [],
138
+ available: {},
139
+ dialect: target[Plan.TypeId].dialect
140
+ }, {
141
+ kind: "createTable",
142
+ select: {},
143
+ target: {
144
+ kind: "from",
145
+ tableName: sourceName,
146
+ baseTableName: sourceBaseName,
147
+ source: target
148
+ },
149
+ ddl: {
150
+ kind: "createTable",
151
+ ifNotExists: options.ifNotExists ?? false
152
+ },
153
+ where: [],
154
+ having: [],
155
+ joins: [],
156
+ groupBy: [],
157
+ orderBy: []
158
+ }, undefined, "ddl", "createTable")
159
+ }
160
+
161
+ const dropTable = (target: any, options: { readonly ifExists?: boolean } = {}) => {
162
+ const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target)
163
+ return ctx.makePlan({
164
+ selection: {},
165
+ required: [],
166
+ available: {},
167
+ dialect: target[Plan.TypeId].dialect
168
+ }, {
169
+ kind: "dropTable",
170
+ select: {},
171
+ target: {
172
+ kind: "from",
173
+ tableName: sourceName,
174
+ baseTableName: sourceBaseName,
175
+ source: target
176
+ },
177
+ ddl: {
178
+ kind: "dropTable",
179
+ ifExists: options.ifExists ?? false
180
+ },
181
+ where: [],
182
+ having: [],
183
+ joins: [],
184
+ groupBy: [],
185
+ orderBy: []
186
+ }, undefined, "ddl", "dropTable")
187
+ }
188
+
189
+ const createIndex = (target: any, columns: string | readonly string[], options: { readonly name?: string; readonly unique?: boolean; readonly ifNotExists?: boolean } = {}) => {
190
+ const normalizedColumns = ctx.normalizeColumnList(columns)
191
+ const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target)
192
+ return ctx.makePlan({
193
+ selection: {},
194
+ required: [],
195
+ available: {},
196
+ dialect: target[Plan.TypeId].dialect
197
+ }, {
198
+ kind: "createIndex",
199
+ select: {},
200
+ target: {
201
+ kind: "from",
202
+ tableName: sourceName,
203
+ baseTableName: sourceBaseName,
204
+ source: target
205
+ },
206
+ ddl: {
207
+ kind: "createIndex",
208
+ name: options.name ?? ctx.defaultIndexName(sourceBaseName, normalizedColumns, options.unique ?? false),
209
+ columns: normalizedColumns,
210
+ unique: options.unique ?? false,
211
+ ifNotExists: options.ifNotExists ?? false
212
+ },
213
+ where: [],
214
+ having: [],
215
+ joins: [],
216
+ groupBy: [],
217
+ orderBy: []
218
+ }, undefined, "ddl", "createIndex")
219
+ }
220
+
221
+ const dropIndex = (target: any, columns: string | readonly string[], options: { readonly name?: string; readonly ifExists?: boolean } = {}) => {
222
+ const normalizedColumns = ctx.normalizeColumnList(columns)
223
+ const { sourceName, sourceBaseName } = ctx.targetSourceDetails(target)
224
+ return ctx.makePlan({
225
+ selection: {},
226
+ required: [],
227
+ available: {},
228
+ dialect: target[Plan.TypeId].dialect
229
+ }, {
230
+ kind: "dropIndex",
231
+ select: {},
232
+ target: {
233
+ kind: "from",
234
+ tableName: sourceName,
235
+ baseTableName: sourceBaseName,
236
+ source: target
237
+ },
238
+ ddl: {
239
+ kind: "dropIndex",
240
+ name: options.name ?? ctx.defaultIndexName(sourceBaseName, normalizedColumns, false),
241
+ ifExists: options.ifExists ?? false
242
+ },
243
+ where: [],
244
+ having: [],
245
+ joins: [],
246
+ groupBy: [],
247
+ orderBy: []
248
+ }, undefined, "ddl", "dropIndex")
249
+ }
250
+
251
+ return {
252
+ transaction,
253
+ commit,
254
+ rollback,
255
+ savepoint,
256
+ rollbackTo,
257
+ releaseSavepoint,
258
+ createTable,
259
+ dropTable,
260
+ createIndex,
261
+ dropIndex
262
+ }
263
+ }
@@ -1,18 +1,21 @@
1
+ import * as Chunk from "effect/Chunk"
1
2
  import * as Effect from "effect/Effect"
3
+ import * as Option from "effect/Option"
2
4
  import * as Schema from "effect/Schema"
3
5
  import * as SqlClient from "@effect/sql/SqlClient"
4
6
  import * as SqlError from "@effect/sql/SqlError"
7
+ import * as Stream from "effect/Stream"
5
8
 
6
- import * as Expression from "./expression.js"
9
+ import * as Expression from "./scalar.js"
7
10
  import * as ExpressionAst from "./expression-ast.js"
8
11
  import { resolveImplicationScope, type ImplicationScope } from "./implication-runtime.js"
9
- import { normalizeDbValue } from "./runtime-normalize.js"
10
- import { expressionRuntimeSchema } from "./runtime-schema.js"
12
+ import { fromDriverValue } from "./runtime/driver-value-mapping.js"
13
+ import { expressionRuntimeSchema } from "./runtime/schema.js"
11
14
  import { flattenSelection } from "./projections.js"
12
15
  import * as Query from "./query.js"
13
16
  import * as QueryAst from "./query-ast.js"
14
17
  import * as Renderer from "./renderer.js"
15
- import * as Plan from "./plan.js"
18
+ import * as Plan from "./row-set.js"
16
19
 
17
20
  /** Flat database row keyed by rendered projection aliases. */
18
21
  export type FlatRow = Readonly<Record<string, unknown>>
@@ -58,6 +61,9 @@ export interface Driver<
58
61
  execute<Row>(
59
62
  query: Renderer.RenderedQuery<Row, Dialect>
60
63
  ): Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
64
+ stream<Row>(
65
+ query: Renderer.RenderedQuery<Row, Dialect>
66
+ ): Stream.Stream<FlatRow, Error, Context>
61
67
  }
62
68
 
63
69
  /**
@@ -73,9 +79,12 @@ export interface Executor<
73
79
  Context = never
74
80
  > {
75
81
  readonly dialect: Dialect
76
- execute<PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
82
+ execute<PlanValue extends Query.Plan.Any>(
77
83
  plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
78
84
  ): Effect.Effect<Query.ResultRows<PlanValue>, Error, Context>
85
+ stream<PlanValue extends Query.Plan.Any>(
86
+ plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
87
+ ): Stream.Stream<Query.ResultRow<PlanValue>, Error, Context>
79
88
  }
80
89
 
81
90
  const setPath = (
@@ -117,21 +126,21 @@ const hasWriteStatement = (statement: QueryAst.QueryStatement): boolean =>
117
126
 
118
127
  const hasWriteCapabilityInSource = (source: unknown): boolean =>
119
128
  typeof source === "object" && source !== null && "plan" in source
120
- ? hasWriteCapability((source as { readonly plan: Query.QueryPlan<any, any, any, any, any, any, any, any, any, any> }).plan)
129
+ ? hasWriteCapability((source as { readonly plan: Query.Plan.Any }).plan)
121
130
  : false
122
131
 
123
132
  export const hasWriteCapability = (
124
- plan: Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>
133
+ plan: Query.Plan.Any
125
134
  ): boolean => {
126
135
  const ast = Query.getAst(plan)
127
136
  if (hasWriteStatement(ast.kind)) {
128
137
  return true
129
138
  }
130
139
  if (ast.kind === "set") {
131
- if (ast.setBase && hasWriteCapability((ast.setBase as Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>))) {
140
+ if (ast.setBase && hasWriteCapability((ast.setBase as Query.Plan.Any))) {
132
141
  return true
133
142
  }
134
- if ((ast.setOperations ?? []).some((entry) => hasWriteCapability(entry.query as Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>))) {
143
+ if ((ast.setOperations ?? []).some((entry) => hasWriteCapability(entry.query as Query.Plan.Any))) {
135
144
  return true
136
145
  }
137
146
  }
@@ -198,9 +207,6 @@ const hasOptionalSourceDependency = (
198
207
  scope: ImplicationScope
199
208
  ): boolean => {
200
209
  const state = expression[Expression.TypeId]
201
- if (state.sourceNullability === "resolved") {
202
- return false
203
- }
204
210
  return Object.keys(state.dependencies).some((sourceName) =>
205
211
  !scope.absentSourceNames.has(sourceName) && scope.sourceModes.get(sourceName) === "optional")
206
212
  }
@@ -223,8 +229,7 @@ const effectiveRuntimeNullability = (
223
229
  return "never"
224
230
  }
225
231
  }
226
- if (expression[Expression.TypeId].sourceNullability !== "resolved" &&
227
- Object.keys(expression[Expression.TypeId].dependencies).some((sourceName) => scope.absentSourceNames.has(sourceName))) {
232
+ if (Object.keys(expression[Expression.TypeId].dependencies).some((sourceName) => scope.absentSourceNames.has(sourceName))) {
228
233
  return "always"
229
234
  }
230
235
  return hasOptionalSourceDependency(expression, scope)
@@ -238,12 +243,19 @@ const decodeProjectionValue = (
238
243
  expression: Expression.Any,
239
244
  raw: unknown,
240
245
  scope: ImplicationScope,
241
- driverMode: DriverMode
246
+ driverMode: DriverMode,
247
+ valueMappings?: Expression.DriverValueMappings
242
248
  ): unknown => {
243
249
  let normalized = raw
244
250
  if (driverMode === "raw") {
245
251
  try {
246
- normalized = normalizeDbValue(expression[Expression.TypeId].dbType, raw)
252
+ normalized = fromDriverValue(raw, {
253
+ dialect: rendered.dialect,
254
+ dbType: expression[Expression.TypeId].dbType,
255
+ runtimeSchema: expression[Expression.TypeId].runtimeSchema,
256
+ driverValueMapping: expression[Expression.TypeId].driverValueMapping,
257
+ valueMappings
258
+ })
247
259
  } catch (cause) {
248
260
  throw makeRowDecodeError(rendered, projection, expression, raw, "normalize", cause)
249
261
  }
@@ -293,14 +305,14 @@ const decodeProjectionValue = (
293
305
  }
294
306
  }
295
307
 
296
- export const decodeRows = (
308
+ export const makeRowDecoder = (
297
309
  rendered: Renderer.RenderedQuery<any, any>,
298
- plan: Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>,
299
- rows: ReadonlyArray<FlatRow>,
310
+ plan: Query.Plan.Any,
300
311
  options: {
301
312
  readonly driverMode?: DriverMode
313
+ readonly valueMappings?: Expression.DriverValueMappings
302
314
  } = {}
303
- ): ReadonlyArray<any> => {
315
+ ): ((row: FlatRow) => any) => {
304
316
  const projections = flattenSelection(
305
317
  Query.getAst(plan).select as Record<string, unknown>
306
318
  )
@@ -308,8 +320,9 @@ export const decodeRows = (
308
320
  projections.map((projection) => [projection.alias, projection.expression] as const)
309
321
  )
310
322
  const driverMode = options.driverMode ?? "raw"
323
+ const valueMappings = options.valueMappings ?? rendered.valueMappings
311
324
  const scope = resolveImplicationScope(plan[Plan.TypeId].available, Query.getQueryState(plan).assumptions)
312
- return rows.map((row) => {
325
+ return (row) => {
313
326
  const decoded: Record<string, unknown> = {}
314
327
  for (const projection of rendered.projections) {
315
328
  if (!(projection.alias in row)) {
@@ -322,11 +335,37 @@ export const decodeRows = (
322
335
  setPath(
323
336
  decoded,
324
337
  projection.path,
325
- decodeProjectionValue(rendered, projection, expression, row[projection.alias], scope, driverMode)
338
+ decodeProjectionValue(rendered, projection, expression, row[projection.alias], scope, driverMode, valueMappings)
326
339
  )
327
340
  }
328
341
  return decoded
329
- })
342
+ }
343
+ }
344
+
345
+ export const decodeChunk = (
346
+ rendered: Renderer.RenderedQuery<any, any>,
347
+ plan: Query.Plan.Any,
348
+ rows: Chunk.Chunk<FlatRow>,
349
+ options: {
350
+ readonly driverMode?: DriverMode
351
+ readonly valueMappings?: Expression.DriverValueMappings
352
+ } = {}
353
+ ): Chunk.Chunk<any> => {
354
+ const decodeRow = makeRowDecoder(rendered, plan, options)
355
+ return Chunk.unsafeFromArray(Chunk.toReadonlyArray(rows).map((row) => decodeRow(row)))
356
+ }
357
+
358
+ export const decodeRows = (
359
+ rendered: Renderer.RenderedQuery<any, any>,
360
+ plan: Query.Plan.Any,
361
+ rows: ReadonlyArray<FlatRow>,
362
+ options: {
363
+ readonly driverMode?: DriverMode
364
+ readonly valueMappings?: Expression.DriverValueMappings
365
+ } = {}
366
+ ): ReadonlyArray<any> => {
367
+ const decodeRow = makeRowDecoder(rendered, plan, options)
368
+ return rows.map((row) => decodeRow(row))
330
369
  }
331
370
 
332
371
  /**
@@ -338,20 +377,23 @@ export const make = <
338
377
  Context = never
339
378
  >(
340
379
  dialect: Dialect,
341
- execute: <PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
380
+ execute: <PlanValue extends Query.Plan.Any>(
342
381
  plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
343
382
  ) => Effect.Effect<Query.ResultRows<PlanValue>, Error, Context>
344
383
  ): Executor<Dialect, Error, Context> => ({
345
384
  dialect,
346
385
  execute(plan) {
347
386
  return (execute as any)(plan)
387
+ },
388
+ stream(plan) {
389
+ return Stream.unwrap(Effect.map((execute as any)(plan), (rows: ReadonlyArray<any>) => Stream.fromIterable(rows)))
348
390
  }
349
391
  }) as Executor<Dialect, Error, Context>
350
392
 
351
393
  /**
352
394
  * Constructs a driver from a dialect and execution callback.
353
395
  */
354
- export const driver = <
396
+ export function driver<
355
397
  Dialect extends string,
356
398
  Error = never,
357
399
  Context = never
@@ -360,12 +402,58 @@ export const driver = <
360
402
  execute: <Row>(
361
403
  query: Renderer.RenderedQuery<Row, Dialect>
362
404
  ) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
363
- ): Driver<Dialect, Error, Context> => ({
405
+ ): Driver<Dialect, Error, Context>
406
+ export function driver<
407
+ Dialect extends string,
408
+ Error = never,
409
+ Context = never
410
+ >(
411
+ dialect: Dialect,
412
+ handlers: {
413
+ readonly execute: <Row>(
414
+ query: Renderer.RenderedQuery<Row, Dialect>
415
+ ) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
416
+ readonly stream: <Row>(
417
+ query: Renderer.RenderedQuery<Row, Dialect>
418
+ ) => Stream.Stream<FlatRow, Error, Context>
419
+ }
420
+ ): Driver<Dialect, Error, Context>
421
+ export function driver<
422
+ Dialect extends string,
423
+ Error = never,
424
+ Context = never
425
+ >(
426
+ dialect: Dialect,
427
+ executeOrHandlers:
428
+ | (<Row>(
429
+ query: Renderer.RenderedQuery<Row, Dialect>
430
+ ) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>)
431
+ | {
432
+ readonly execute: <Row>(
433
+ query: Renderer.RenderedQuery<Row, Dialect>
434
+ ) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
435
+ readonly stream: <Row>(
436
+ query: Renderer.RenderedQuery<Row, Dialect>
437
+ ) => Stream.Stream<FlatRow, Error, Context>
438
+ }
439
+ ): Driver<Dialect, Error, Context> {
440
+ return {
364
441
  dialect,
365
442
  execute(query) {
366
- return execute(query)
443
+ return typeof executeOrHandlers === "function"
444
+ ? executeOrHandlers(query)
445
+ : executeOrHandlers.execute(query)
446
+ },
447
+ stream(query) {
448
+ if (typeof executeOrHandlers === "function") {
449
+ return Stream.unwrap(
450
+ Effect.map(executeOrHandlers(query), (rows) => Stream.fromIterable(rows))
451
+ )
452
+ }
453
+ return executeOrHandlers.stream(query)
367
454
  }
368
- })
455
+ }
456
+ }
369
457
 
370
458
  /**
371
459
  * Creates an executor by composing a renderer with a rendered-query driver.
@@ -391,20 +479,44 @@ export const fromDriver = <
391
479
  sqlDriver.execute(rendered),
392
480
  (rows) => remapRows<any>(rendered, rows)
393
481
  )
482
+ },
483
+ stream(plan: any) {
484
+ const rendered = renderer.render(plan) as Renderer.RenderedQuery<any, Dialect>
485
+ return Stream.mapChunks(
486
+ sqlDriver.stream(rendered),
487
+ (rows) => Chunk.unsafeFromArray(remapRows<any>(rendered, Chunk.toReadonlyArray(rows)))
488
+ )
394
489
  }
395
490
  }
396
491
  return executor as unknown as Executor<Dialect, Error, Context>
397
492
  }
398
493
 
399
- /**
400
- * Creates an executor backed by `@effect/sql`'s `SqlClient`.
401
- */
494
+ export const streamFromSqlClient = <Dialect extends string>(
495
+ query: Renderer.RenderedQuery<any, Dialect>
496
+ ): Stream.Stream<FlatRow, SqlError.SqlError, SqlClient.SqlClient> =>
497
+ Stream.unwrapScoped(
498
+ Effect.flatMap(SqlClient.SqlClient, (sql) =>
499
+ Effect.flatMap(
500
+ Effect.serviceOption(SqlClient.TransactionConnection),
501
+ Option.match({
502
+ onNone: () => sql.reserve,
503
+ onSome: ([connection]) => Effect.succeed(connection)
504
+ })
505
+ ).pipe(
506
+ Effect.map((connection) => connection.executeStream(query.sql, [...query.params], undefined))
507
+ )
508
+ )
509
+ )
510
+
402
511
  export const fromSqlClient = <Dialect extends string>(
403
512
  renderer: Renderer.Renderer<Dialect>
404
513
  ): Executor<Dialect, unknown, SqlClient.SqlClient> =>
405
- fromDriver(renderer, driver(renderer.dialect, (query) =>
406
- Effect.flatMap(SqlClient.SqlClient, (sql) =>
407
- sql.unsafe<FlatRow>(query.sql, [...query.params]))))
514
+ fromDriver(renderer, driver(renderer.dialect, {
515
+ execute: (query) =>
516
+ Effect.flatMap(SqlClient.SqlClient, (sql) =>
517
+ sql.unsafe<FlatRow>(query.sql, [...query.params])),
518
+ stream: (query) => streamFromSqlClient(query)
519
+ }))
408
520
 
409
521
  /** Runs an effect within the ambient `@effect/sql` transaction service. */
410
522
  export const withTransaction = <A, E, R>(
@@ -1,4 +1,4 @@
1
- import type * as Expression from "./expression.js"
1
+ import type * as Expression from "./scalar.js"
2
2
  import type * as Query from "./query.js"
3
3
  import type * as JsonPath from "./json/path.js"
4
4
  import type { JsonNode } from "./json/ast.js"
@@ -34,6 +34,15 @@ export interface CastNode<
34
34
  readonly target: Target
35
35
  }
36
36
 
37
+ /** Explicit collation captured by the internal expression AST. */
38
+ export interface CollateNode<
39
+ Value extends Expression.Any = Expression.Any
40
+ > {
41
+ readonly kind: "collate"
42
+ readonly value: Value
43
+ readonly collation: readonly [string, ...string[]]
44
+ }
45
+
37
46
  /** General SQL function call captured by the internal expression AST. */
38
47
  export interface FunctionCallNode<
39
48
  Name extends string = string,
@@ -136,7 +145,7 @@ export interface CaseNode<
136
145
 
137
146
  /** `exists (<subquery>)` expression node. */
138
147
  export interface ExistsNode<
139
- PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any> = Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>
148
+ PlanValue extends Query.Plan.Any = Query.Plan.Any
140
149
  > {
141
150
  readonly kind: "exists"
142
151
  readonly plan: PlanValue
@@ -144,7 +153,7 @@ export interface ExistsNode<
144
153
 
145
154
  /** Scalar subquery expression node. */
146
155
  export interface ScalarSubqueryNode<
147
- PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any> = Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>
156
+ PlanValue extends Query.Plan.Any = Query.Plan.Any
148
157
  > {
149
158
  readonly kind: "scalarSubquery"
150
159
  readonly plan: PlanValue
@@ -153,7 +162,7 @@ export interface ScalarSubqueryNode<
153
162
  /** `value in (<subquery>)` expression node. */
154
163
  export interface InSubqueryNode<
155
164
  Left extends Expression.Any = Expression.Any,
156
- PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any> = Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>
165
+ PlanValue extends Query.Plan.Any = Query.Plan.Any
157
166
  > {
158
167
  readonly kind: "inSubquery"
159
168
  readonly left: Left
@@ -165,7 +174,7 @@ export interface QuantifiedComparisonNode<
165
174
  Kind extends "comparisonAny" | "comparisonAll" = "comparisonAny" | "comparisonAll",
166
175
  Operator extends "eq" | "neq" | "lt" | "lte" | "gt" | "gte" = "eq" | "neq" | "lt" | "lte" | "gt" | "gte",
167
176
  Left extends Expression.Any = Expression.Any,
168
- PlanValue extends Query.QueryPlan<any, any, any, any, any, any, any, any, any, any> = Query.QueryPlan<any, any, any, any, any, any, any, any, any, any>
177
+ PlanValue extends Query.Plan.Any = Query.Plan.Any
169
178
  > {
170
179
  readonly kind: Kind
171
180
  readonly operator: Operator
@@ -339,6 +348,7 @@ export type Any =
339
348
  | ColumnNode
340
349
  | LiteralNode
341
350
  | CastNode
351
+ | CollateNode
342
352
  | FunctionCallNode
343
353
  | ExcludedNode
344
354
  | UnaryNode
@@ -0,0 +1,3 @@
1
+ import * as Expression from "./scalar.js";
2
+ export declare const groupingKeyOfExpression: (expression: Expression.Any) => string;
3
+ export declare const dedupeGroupedExpressions: <Values extends readonly Expression.Any[]>(values: Values) => Values;
@@ -1,4 +1,4 @@
1
- import * as Expression from "./expression.js"
1
+ import * as Expression from "./scalar.js"
2
2
  import * as ExpressionAst from "./expression-ast.js"
3
3
 
4
4
  const literalGroupingKey = (value: unknown): string => {
@@ -0,0 +1,15 @@
1
+ import * as Plan from "./row-set.js";
2
+ import type { PredicateFormula } from "./predicate/formula.js";
3
+ import type { SourceLike } from "./query.js";
4
+ export interface ImplicationScope {
5
+ readonly assumptions: PredicateFormula;
6
+ readonly nonNullKeys: ReadonlySet<string>;
7
+ readonly nullKeys: ReadonlySet<string>;
8
+ readonly requiredSourceNames: ReadonlySet<string>;
9
+ readonly absentSourceNames: ReadonlySet<string>;
10
+ readonly sourceModes: ReadonlyMap<string, Plan.SourceMode>;
11
+ }
12
+ export declare const presentFormulaOfSource: (source: Plan.Source<string, Plan.SourceMode, PredicateFormula, never>) => PredicateFormula;
13
+ export declare const presenceWitnessesOfSource: (source: Plan.Source<string, Plan.SourceMode, PredicateFormula, never>) => ReadonlySet<string>;
14
+ export declare const presenceWitnessesOfSourceLike: (source: SourceLike) => readonly string[];
15
+ export declare const resolveImplicationScope: (available: Readonly<Record<string, Plan.Source<string, Plan.SourceMode, PredicateFormula, never>>>, initialAssumptions: PredicateFormula) => ImplicationScope;