effect-qb 0.13.0 → 0.15.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/README.md +6 -1431
  2. package/dist/mysql.js +61945 -3611
  3. package/dist/postgres/metadata.js +2818 -0
  4. package/dist/postgres.js +9942 -5591
  5. package/package.json +21 -10
  6. package/src/internal/aggregation-validation.ts +3 -3
  7. package/src/internal/case-analysis.d.ts +18 -0
  8. package/src/internal/case-analysis.ts +4 -4
  9. package/src/internal/coercion/analysis.d.ts +7 -0
  10. package/src/internal/{coercion-analysis.ts → coercion/analysis.ts} +3 -3
  11. package/src/internal/coercion/errors.d.ts +17 -0
  12. package/src/internal/{coercion-errors.ts → coercion/errors.ts} +1 -1
  13. package/src/internal/coercion/kind.d.ts +4 -0
  14. package/src/internal/{coercion-kind.ts → coercion/kind.ts} +2 -2
  15. package/src/internal/{coercion-normalize.ts → coercion/normalize.ts} +1 -1
  16. package/src/internal/coercion/rules.d.ts +6 -0
  17. package/src/internal/{coercion-rules.ts → coercion/rules.ts} +2 -2
  18. package/src/internal/column-state.d.ts +190 -0
  19. package/src/internal/column-state.ts +119 -56
  20. package/src/internal/column.ts +387 -149
  21. package/src/internal/datatypes/define.d.ts +17 -0
  22. package/src/internal/datatypes/define.ts +18 -34
  23. package/src/internal/datatypes/lookup.d.ts +44 -0
  24. package/src/internal/datatypes/lookup.ts +61 -152
  25. package/src/internal/datatypes/shape.d.ts +16 -0
  26. package/src/internal/datatypes/shape.ts +1 -1
  27. package/src/internal/derived-table.d.ts +4 -0
  28. package/src/internal/derived-table.ts +21 -16
  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 +173 -38
  34. package/src/internal/expression-ast.ts +19 -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 +171 -0
  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 → predicate/analysis.ts} +13 -3
  47. package/src/internal/predicate/atom.d.ts +28 -0
  48. package/src/internal/{predicate-branches.ts → predicate/branches.ts} +2 -2
  49. package/src/internal/predicate/context.d.ts +67 -0
  50. package/src/internal/{predicate-context.ts → predicate/context.ts} +111 -32
  51. package/src/internal/predicate/formula.d.ts +35 -0
  52. package/src/internal/{predicate-formula.ts → predicate/formula.ts} +32 -20
  53. package/src/internal/predicate/key.d.ts +11 -0
  54. package/src/internal/{predicate-key.ts → predicate/key.ts} +2 -2
  55. package/src/internal/{predicate-nnf.ts → predicate/nnf.ts} +2 -2
  56. package/src/internal/predicate/normalize.d.ts +53 -0
  57. package/src/internal/predicate/normalize.ts +273 -0
  58. package/src/internal/predicate/runtime.d.ts +31 -0
  59. package/src/internal/predicate/runtime.ts +679 -0
  60. package/src/internal/projection-alias.d.ts +13 -0
  61. package/src/internal/projections.d.ts +31 -0
  62. package/src/internal/projections.ts +1 -1
  63. package/src/internal/query-ast.d.ts +217 -0
  64. package/src/internal/query-ast.ts +1 -1
  65. package/src/internal/query-requirements.d.ts +20 -0
  66. package/src/internal/query.d.ts +775 -0
  67. package/src/internal/query.ts +767 -275
  68. package/src/internal/renderer.ts +7 -21
  69. package/src/internal/row-set.d.ts +53 -0
  70. package/src/internal/{plan.ts → row-set.ts} +23 -11
  71. package/src/internal/{runtime-normalize.ts → runtime/normalize.ts} +9 -31
  72. package/src/internal/{runtime-schema.ts → runtime/schema.ts} +84 -55
  73. package/src/internal/runtime/value.d.ts +22 -0
  74. package/src/internal/{runtime-value.ts → runtime/value.ts} +2 -2
  75. package/src/internal/scalar.d.ts +107 -0
  76. package/src/internal/scalar.ts +191 -0
  77. package/src/internal/schema-derivation.d.ts +105 -0
  78. package/src/internal/schema-derivation.ts +93 -21
  79. package/src/internal/schema-expression.d.ts +18 -0
  80. package/src/internal/schema-expression.ts +75 -0
  81. package/src/internal/table-options.d.ts +94 -0
  82. package/src/internal/table-options.ts +94 -8
  83. package/src/internal/table.d.ts +173 -0
  84. package/src/internal/table.ts +135 -54
  85. package/src/mysql/column.ts +95 -18
  86. package/src/mysql/datatypes/index.ts +58 -3
  87. package/src/mysql/errors/generated.ts +57336 -0
  88. package/src/mysql/errors/index.ts +1 -0
  89. package/src/mysql/errors/normalize.ts +55 -53
  90. package/src/mysql/errors/types.ts +74 -0
  91. package/src/mysql/executor.ts +69 -7
  92. package/src/mysql/function/aggregate.ts +1 -5
  93. package/src/mysql/function/core.ts +1 -3
  94. package/src/mysql/function/index.ts +1 -1
  95. package/src/mysql/function/string.ts +1 -5
  96. package/src/mysql/function/temporal.ts +12 -15
  97. package/src/mysql/function/window.ts +1 -6
  98. package/src/{internal/mysql-dialect.ts → mysql/internal/dialect.ts} +1 -1
  99. package/src/mysql/internal/dsl.ts +6115 -0
  100. package/src/{internal/mysql-renderer.ts → mysql/internal/renderer.ts} +6 -6
  101. package/src/mysql/internal/sql-expression-renderer.ts +1455 -0
  102. package/src/mysql/json.ts +2 -0
  103. package/src/mysql/query.ts +111 -86
  104. package/src/mysql/renderer.ts +1 -1
  105. package/src/mysql/table.ts +1 -1
  106. package/src/mysql.ts +6 -4
  107. package/src/postgres/cast.ts +30 -0
  108. package/src/postgres/column.ts +178 -20
  109. package/src/postgres/datatypes/index.d.ts +515 -0
  110. package/src/postgres/datatypes/index.ts +49 -5
  111. package/src/postgres/datatypes/spec.d.ts +412 -0
  112. package/src/postgres/errors/generated.ts +2636 -0
  113. package/src/postgres/errors/index.ts +1 -0
  114. package/src/postgres/errors/normalize.ts +47 -62
  115. package/src/postgres/errors/types.ts +92 -34
  116. package/src/postgres/executor.ts +37 -5
  117. package/src/postgres/function/aggregate.ts +1 -5
  118. package/src/postgres/function/core.ts +20 -2
  119. package/src/postgres/function/index.ts +1 -1
  120. package/src/postgres/function/string.ts +1 -5
  121. package/src/postgres/function/temporal.ts +12 -15
  122. package/src/postgres/function/window.ts +1 -6
  123. package/src/{internal/postgres-dialect.ts → postgres/internal/dialect.ts} +1 -1
  124. package/src/{internal/query-factory.ts → postgres/internal/dsl.ts} +1568 -2120
  125. package/src/{internal/postgres-renderer.ts → postgres/internal/renderer.ts} +6 -6
  126. package/src/postgres/internal/schema-ddl.ts +108 -0
  127. package/src/postgres/internal/schema-model.ts +150 -0
  128. package/src/{internal → postgres/internal}/sql-expression-renderer.ts +112 -46
  129. package/src/postgres/json.ts +493 -0
  130. package/src/postgres/metadata.ts +31 -0
  131. package/src/postgres/query.ts +113 -86
  132. package/src/postgres/renderer.ts +3 -13
  133. package/src/postgres/schema-expression.ts +17 -0
  134. package/src/postgres/schema-management.ts +204 -0
  135. package/src/postgres/schema.ts +35 -0
  136. package/src/postgres/table.ts +316 -42
  137. package/src/postgres/type.ts +31 -0
  138. package/src/postgres.ts +20 -4
  139. package/CHANGELOG.md +0 -134
  140. package/src/internal/expression.ts +0 -327
  141. package/src/internal/predicate-normalize.ts +0 -202
  142. package/src/mysql/function/json.ts +0 -4
  143. package/src/mysql/private/query.ts +0 -13
  144. package/src/postgres/function/json.ts +0 -4
  145. package/src/postgres/private/query.ts +0 -13
  146. /package/src/internal/{predicate-atom.ts → predicate/atom.ts} +0 -0
@@ -0,0 +1,387 @@
1
+ import * as Expression from "./scalar.js"
2
+ import * as Plan from "./row-set.js"
3
+ import * as Table from "./table.js"
4
+
5
+ type DslPlanRuntimeContext = {
6
+ readonly profile: {
7
+ readonly dialect: string
8
+ }
9
+ readonly makePlan: (...args: readonly any[]) => any
10
+ readonly getAst: (plan: any) => any
11
+ readonly getQueryState: (plan: any) => any
12
+ readonly currentRequiredList: (required: any) => readonly string[]
13
+ readonly toDialectExpression: (value: any) => Expression.Any
14
+ readonly toDialectNumericExpression: (value: any) => Expression.Any
15
+ readonly extractRequiredFromDialectInputRuntime: (value: any) => readonly string[]
16
+ readonly extractRequiredFromDialectNumericInputRuntime: (value: any) => readonly string[]
17
+ readonly formulaOfExpressionRuntime: (value: Expression.Any) => any
18
+ readonly assumeFormulaTrue: (assumptions: any, formula: any) => any
19
+ readonly trueFormula: () => any
20
+ readonly sourceDetails: (source: any) => { readonly sourceName: string; readonly sourceBaseName: string }
21
+ readonly presenceWitnessesOfSourceLike: (source: any) => readonly string[]
22
+ readonly attachInsertSource: (plan: any, source: any) => any
23
+ }
24
+
25
+ export const makeDslPlanRuntime = (ctx: DslPlanRuntimeContext) => {
26
+ const buildSetOperation = (kind: string, all: boolean, left: any, right: any) => {
27
+ const leftState = left[Plan.TypeId]
28
+ const leftAst = ctx.getAst(left)
29
+ const basePlan = leftAst.kind === "set"
30
+ ? leftAst.setBase ?? left
31
+ : left
32
+ const leftOperations = leftAst.kind === "set"
33
+ ? [...(leftAst.setOperations ?? [])]
34
+ : []
35
+ return ctx.makePlan({
36
+ selection: leftState.selection,
37
+ required: undefined,
38
+ available: {},
39
+ dialect: leftState.dialect ?? right[Plan.TypeId].dialect
40
+ }, {
41
+ kind: "set",
42
+ select: leftState.selection,
43
+ where: [],
44
+ having: [],
45
+ joins: [],
46
+ groupBy: [],
47
+ orderBy: [],
48
+ setBase: basePlan,
49
+ setOperations: [
50
+ ...leftOperations,
51
+ {
52
+ kind,
53
+ all,
54
+ query: right
55
+ }
56
+ ]
57
+ }, undefined, undefined, "set")
58
+ }
59
+
60
+ const where = (predicate: any) =>
61
+ (plan: any) => {
62
+ const current = plan[Plan.TypeId]
63
+ const currentAst = ctx.getAst(plan)
64
+ const currentQuery = ctx.getQueryState(plan)
65
+ const predicateExpression = ctx.toDialectExpression(predicate)
66
+ const predicateRequired = ctx.extractRequiredFromDialectInputRuntime(predicate)
67
+ return ctx.makePlan({
68
+ selection: current.selection,
69
+ required: [...ctx.currentRequiredList(current.required), ...predicateRequired].filter((name, index, values) =>
70
+ !(name in current.available) && values.indexOf(name) === index),
71
+ available: current.available,
72
+ dialect: current.dialect ?? predicateExpression[Expression.TypeId].dialect
73
+ }, {
74
+ ...currentAst,
75
+ where: [...currentAst.where, {
76
+ kind: "where",
77
+ predicate: predicateExpression
78
+ }]
79
+ }, ctx.assumeFormulaTrue(
80
+ currentQuery.assumptions,
81
+ ctx.formulaOfExpressionRuntime(predicateExpression)
82
+ ), currentQuery.capabilities, currentQuery.statement)
83
+ }
84
+
85
+ const from = (source: any) =>
86
+ (plan: any) => {
87
+ const current = plan[Plan.TypeId]
88
+ const currentAst = ctx.getAst(plan)
89
+ const currentQuery = ctx.getQueryState(plan)
90
+
91
+ if (currentQuery.statement === "insert") {
92
+ return ctx.attachInsertSource(plan, source)
93
+ }
94
+
95
+ if (
96
+ typeof source !== "object" ||
97
+ source === null ||
98
+ ("kind" in source && source.kind === "values" && !("name" in source)) ||
99
+ (!(Table.TypeId in source) && !("name" in source && "baseName" in source))
100
+ ) {
101
+ throw new Error("from(...) requires an aliased source in select/update statements")
102
+ }
103
+
104
+ const sourceLike = source
105
+ const { sourceName, sourceBaseName } = ctx.sourceDetails(sourceLike)
106
+ const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(sourceLike)
107
+
108
+ if (currentQuery.statement === "select") {
109
+ return ctx.makePlan({
110
+ selection: current.selection,
111
+ required: ctx.currentRequiredList(current.required).filter((name) => name !== sourceName),
112
+ available: {
113
+ [sourceName]: {
114
+ name: sourceName,
115
+ mode: "required",
116
+ baseName: sourceBaseName,
117
+ _presentFormula: ctx.trueFormula(),
118
+ _presenceWitnesses: presenceWitnesses
119
+ }
120
+ },
121
+ dialect: current.dialect
122
+ }, {
123
+ ...currentAst,
124
+ from: {
125
+ kind: "from",
126
+ tableName: sourceName,
127
+ baseTableName: sourceBaseName,
128
+ source: sourceLike
129
+ }
130
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
131
+ }
132
+
133
+ if (currentQuery.statement === "update") {
134
+ const nextAvailable = {
135
+ ...current.available,
136
+ [sourceName]: {
137
+ name: sourceName,
138
+ mode: "required",
139
+ baseName: sourceBaseName,
140
+ _presentFormula: ctx.trueFormula(),
141
+ _presenceWitnesses: presenceWitnesses
142
+ }
143
+ }
144
+ return ctx.makePlan({
145
+ selection: current.selection,
146
+ required: ctx.currentRequiredList(current.required).filter((name) => !(name in nextAvailable)),
147
+ available: nextAvailable,
148
+ dialect: current.dialect
149
+ }, {
150
+ ...currentAst,
151
+ fromSources: [
152
+ ...(currentAst.fromSources ?? []),
153
+ {
154
+ kind: "from",
155
+ tableName: sourceName,
156
+ baseTableName: sourceBaseName,
157
+ source: sourceLike
158
+ }
159
+ ]
160
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
161
+ }
162
+
163
+ throw new Error(`from(...) is not supported for ${currentQuery.statement} statements`)
164
+ }
165
+
166
+ const having = (predicate: any) =>
167
+ (plan: any) => {
168
+ const current = plan[Plan.TypeId]
169
+ const currentAst = ctx.getAst(plan)
170
+ const currentQuery = ctx.getQueryState(plan)
171
+ const predicateExpression = ctx.toDialectExpression(predicate)
172
+ const predicateRequired = ctx.extractRequiredFromDialectInputRuntime(predicate)
173
+ return ctx.makePlan({
174
+ selection: current.selection,
175
+ required: [...ctx.currentRequiredList(current.required), ...predicateRequired].filter((name, index, values) =>
176
+ !(name in current.available) && values.indexOf(name) === index),
177
+ available: current.available,
178
+ dialect: current.dialect ?? predicateExpression[Expression.TypeId].dialect
179
+ }, {
180
+ ...currentAst,
181
+ having: [...currentAst.having, {
182
+ kind: "having",
183
+ predicate: predicateExpression
184
+ }]
185
+ }, ctx.assumeFormulaTrue(
186
+ currentQuery.assumptions,
187
+ ctx.formulaOfExpressionRuntime(predicateExpression)
188
+ ), currentQuery.capabilities, currentQuery.statement)
189
+ }
190
+
191
+ const crossJoin = (table: any) =>
192
+ (plan: any) => {
193
+ const current = plan[Plan.TypeId]
194
+ const currentAst = ctx.getAst(plan)
195
+ const currentQuery = ctx.getQueryState(plan)
196
+ const { sourceName, sourceBaseName } = ctx.sourceDetails(table)
197
+ const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table)
198
+ const nextAvailable = {
199
+ ...current.available,
200
+ [sourceName]: {
201
+ name: sourceName,
202
+ mode: "required",
203
+ baseName: sourceBaseName,
204
+ _presentFormula: ctx.trueFormula(),
205
+ _presenceWitnesses: presenceWitnesses
206
+ }
207
+ }
208
+ return ctx.makePlan({
209
+ selection: current.selection,
210
+ required: ctx.currentRequiredList(current.required).filter((name) => !(name in nextAvailable)),
211
+ available: nextAvailable,
212
+ dialect: current.dialect ?? table[Plan.TypeId]?.dialect ?? table.dialect
213
+ }, {
214
+ ...currentAst,
215
+ joins: [...currentAst.joins, {
216
+ kind: "cross",
217
+ tableName: sourceName,
218
+ baseTableName: sourceBaseName,
219
+ source: table
220
+ }]
221
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
222
+ }
223
+
224
+ const join = (kind: string, table: any, on: any) =>
225
+ (plan: any) => {
226
+ const current = plan[Plan.TypeId]
227
+ const currentAst = ctx.getAst(plan)
228
+ const currentQuery = ctx.getQueryState(plan)
229
+ const onExpression = ctx.toDialectExpression(on)
230
+ const onFormula = ctx.formulaOfExpressionRuntime(onExpression)
231
+ const { sourceName, sourceBaseName } = ctx.sourceDetails(table)
232
+ const presenceWitnesses = ctx.presenceWitnessesOfSourceLike(table)
233
+ const baseAvailable = (kind === "right" || kind === "full"
234
+ ? Object.fromEntries(
235
+ Object.entries(current.available as Record<string, any>).map(([name, source]) => [name, {
236
+ name: source.name,
237
+ mode: "optional",
238
+ baseName: source.baseName,
239
+ _presentFormula: source._presentFormula,
240
+ _presenceWitnesses: source._presenceWitnesses
241
+ }])
242
+ )
243
+ : current.available) as Record<string, any>
244
+ const nextAvailable = {
245
+ ...baseAvailable,
246
+ [sourceName]: {
247
+ name: sourceName,
248
+ mode: (kind === "left" || kind === "full") ? "optional" : "required",
249
+ baseName: sourceBaseName,
250
+ _presentFormula: (kind === "inner" || kind === "left") ? onFormula : ctx.trueFormula(),
251
+ _presenceWitnesses: presenceWitnesses
252
+ }
253
+ }
254
+ return ctx.makePlan({
255
+ selection: current.selection,
256
+ required: [...ctx.currentRequiredList(current.required), ...ctx.extractRequiredFromDialectInputRuntime(on)].filter((name, index, values) =>
257
+ !(name in nextAvailable) && values.indexOf(name) === index),
258
+ available: nextAvailable,
259
+ dialect: current.dialect ?? table.dialect ?? onExpression[Expression.TypeId].dialect
260
+ }, {
261
+ ...currentAst,
262
+ joins: [...currentAst.joins, {
263
+ kind,
264
+ tableName: sourceName,
265
+ baseTableName: sourceBaseName,
266
+ source: table,
267
+ on: onExpression
268
+ }]
269
+ }, (
270
+ kind === "inner"
271
+ ? ctx.assumeFormulaTrue(currentQuery.assumptions, onFormula)
272
+ : currentQuery.assumptions
273
+ ), currentQuery.capabilities, currentQuery.statement)
274
+ }
275
+
276
+ const orderBy = (value: any, direction: "asc" | "desc" = "asc") =>
277
+ (plan: any) => {
278
+ const current = plan[Plan.TypeId]
279
+ const currentAst = ctx.getAst(plan)
280
+ const currentQuery = ctx.getQueryState(plan)
281
+ const expression = ctx.toDialectExpression(value)
282
+ const required = ctx.extractRequiredFromDialectInputRuntime(value)
283
+ return ctx.makePlan({
284
+ selection: current.selection,
285
+ required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index, values) =>
286
+ !(name in current.available) && values.indexOf(name) === index),
287
+ available: current.available,
288
+ dialect: current.dialect ?? expression[Expression.TypeId].dialect
289
+ }, {
290
+ ...currentAst,
291
+ orderBy: [...currentAst.orderBy, {
292
+ kind: "orderBy",
293
+ value: expression,
294
+ direction
295
+ }]
296
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
297
+ }
298
+
299
+ const lock = (mode: string, options: { readonly nowait?: boolean; readonly skipLocked?: boolean } = {}) =>
300
+ (plan: any) => {
301
+ const current = plan[Plan.TypeId]
302
+ const currentAst = ctx.getAst(plan)
303
+ const currentQuery = ctx.getQueryState(plan)
304
+ return ctx.makePlan({
305
+ selection: current.selection,
306
+ required: current.required,
307
+ available: current.available,
308
+ dialect: current.dialect
309
+ }, {
310
+ ...currentAst,
311
+ lock: {
312
+ kind: "lock",
313
+ mode,
314
+ nowait: options.nowait ?? false,
315
+ skipLocked: options.skipLocked ?? false
316
+ }
317
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
318
+ }
319
+
320
+ const distinct = () =>
321
+ (plan: any) => {
322
+ const current = plan[Plan.TypeId]
323
+ const currentAst = ctx.getAst(plan)
324
+ const currentQuery = ctx.getQueryState(plan)
325
+ return ctx.makePlan({
326
+ selection: current.selection,
327
+ required: current.required,
328
+ available: current.available,
329
+ dialect: current.dialect
330
+ }, {
331
+ ...currentAst,
332
+ distinct: true
333
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
334
+ }
335
+
336
+ const limit = (value: any) =>
337
+ (plan: any) => {
338
+ const current = plan[Plan.TypeId]
339
+ const currentAst = ctx.getAst(plan)
340
+ const currentQuery = ctx.getQueryState(plan)
341
+ const expression = ctx.toDialectNumericExpression(value)
342
+ const required = ctx.extractRequiredFromDialectNumericInputRuntime(value)
343
+ return ctx.makePlan({
344
+ selection: current.selection,
345
+ required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index, values) =>
346
+ !(name in current.available) && values.indexOf(name) === index),
347
+ available: current.available,
348
+ dialect: current.dialect ?? expression[Expression.TypeId].dialect
349
+ }, {
350
+ ...currentAst,
351
+ limit: expression
352
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
353
+ }
354
+
355
+ const offset = (value: any) =>
356
+ (plan: any) => {
357
+ const current = plan[Plan.TypeId]
358
+ const currentAst = ctx.getAst(plan)
359
+ const currentQuery = ctx.getQueryState(plan)
360
+ const expression = ctx.toDialectNumericExpression(value)
361
+ const required = ctx.extractRequiredFromDialectNumericInputRuntime(value)
362
+ return ctx.makePlan({
363
+ selection: current.selection,
364
+ required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index, values) =>
365
+ !(name in current.available) && values.indexOf(name) === index),
366
+ available: current.available,
367
+ dialect: current.dialect ?? expression[Expression.TypeId].dialect
368
+ }, {
369
+ ...currentAst,
370
+ offset: expression
371
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
372
+ }
373
+
374
+ return {
375
+ buildSetOperation,
376
+ where,
377
+ from,
378
+ having,
379
+ crossJoin,
380
+ join,
381
+ orderBy,
382
+ lock,
383
+ distinct,
384
+ limit,
385
+ offset
386
+ }
387
+ }
@@ -0,0 +1,160 @@
1
+ import * as Expression from "./scalar.js"
2
+ import * as Plan from "./row-set.js"
3
+
4
+ type DslQueryRuntimeContext = {
5
+ readonly profile: {
6
+ readonly dialect: string
7
+ }
8
+ readonly ValuesInputProto: object
9
+ readonly normalizeValuesRow: (row: any) => Record<string, Expression.Any>
10
+ readonly normalizeUnnestColumns: (columns: any) => Record<string, readonly Expression.Any[]>
11
+ readonly makeColumnReferenceSelection: (alias: string, selection: Record<string, Expression.Any>) => any
12
+ readonly toDialectNumericExpression: (value: any) => Expression.Any
13
+ readonly extractRequiredRuntime: (selection: any) => readonly string[]
14
+ readonly makePlan: (...args: readonly any[]) => any
15
+ readonly getAst: (plan: any) => any
16
+ readonly getQueryState: (plan: any) => any
17
+ readonly currentRequiredList: (required: any) => readonly string[]
18
+ readonly dedupeGroupedExpressions: (values: readonly any[]) => any
19
+ }
20
+
21
+ export const makeDslQueryRuntime = (ctx: DslQueryRuntimeContext) => {
22
+ const values = (rows: readonly [Record<string, any>, ...Record<string, any>[]]) => {
23
+ if (rows.length === 0) {
24
+ throw new Error("values(...) requires at least one row")
25
+ }
26
+ const normalizedRows = rows.map((row) => ctx.normalizeValuesRow(row)) as unknown as readonly [
27
+ Record<string, Expression.Any>,
28
+ ...Record<string, Expression.Any>[]
29
+ ]
30
+ const columnNames = Object.keys(normalizedRows[0]!)
31
+ for (const row of normalizedRows) {
32
+ const rowKeys = Object.keys(row)
33
+ if (rowKeys.length !== columnNames.length || !rowKeys.every((key, index) => key === columnNames[index])) {
34
+ throw new Error("values(...) rows must project the same columns in the same order")
35
+ }
36
+ }
37
+ return Object.assign(Object.create(ctx.ValuesInputProto), {
38
+ kind: "values",
39
+ dialect: ctx.profile.dialect,
40
+ rows: normalizedRows,
41
+ selection: normalizedRows[0]!
42
+ })
43
+ }
44
+
45
+ const unnest = (columns: Record<string, readonly any[]>, alias: string) => {
46
+ const normalizedColumns = ctx.normalizeUnnestColumns(columns)
47
+ const columnNames = Object.keys(normalizedColumns)
48
+ if (columnNames.length === 0) {
49
+ throw new Error("unnest(...) requires at least one column array")
50
+ }
51
+ const firstColumn = normalizedColumns[columnNames[0] as keyof typeof normalizedColumns]
52
+ const rowCount = firstColumn?.length ?? 0
53
+ if (rowCount === 0) {
54
+ throw new Error("unnest(...) requires at least one row")
55
+ }
56
+ for (const columnName of columnNames) {
57
+ const values = normalizedColumns[columnName]!
58
+ if (values.length !== rowCount) {
59
+ throw new Error("unnest(...) column arrays must have the same length")
60
+ }
61
+ }
62
+ const firstRow = Object.fromEntries(
63
+ columnNames.map((columnName) => [columnName, normalizedColumns[columnName]![0]!])
64
+ ) as Record<string, Expression.Any>
65
+ const columnsSelection = ctx.makeColumnReferenceSelection(alias, firstRow)
66
+ const source = {
67
+ kind: "unnest",
68
+ name: alias,
69
+ baseName: alias,
70
+ dialect: ctx.profile.dialect,
71
+ values: columns,
72
+ arrays: normalizedColumns,
73
+ columns: columnsSelection
74
+ }
75
+ return Object.assign(source, columnsSelection)
76
+ }
77
+
78
+ const generateSeries = (start: any, stop: any, step?: any, alias = "series") => {
79
+ const startExpression = ctx.toDialectNumericExpression(start)
80
+ const stopExpression = ctx.toDialectNumericExpression(stop)
81
+ const stepExpression = step === undefined ? undefined : ctx.toDialectNumericExpression(step)
82
+ const valueSelection = {
83
+ value: startExpression
84
+ } as Record<string, Expression.Any>
85
+ const columns = ctx.makeColumnReferenceSelection(alias, valueSelection)
86
+ const source = {
87
+ kind: "tableFunction",
88
+ name: alias,
89
+ baseName: alias,
90
+ dialect: ctx.profile.dialect,
91
+ functionName: "generate_series",
92
+ args: stepExpression === undefined
93
+ ? [startExpression, stopExpression] as readonly Expression.Any[]
94
+ : [startExpression, stopExpression, stepExpression] as readonly Expression.Any[],
95
+ columns
96
+ }
97
+ return Object.assign(source, columns)
98
+ }
99
+
100
+ const select = (selection: any) =>
101
+ ctx.makePlan({
102
+ selection,
103
+ required: ctx.extractRequiredRuntime(selection),
104
+ available: {},
105
+ dialect: ctx.profile.dialect
106
+ }, {
107
+ kind: "select",
108
+ select: selection,
109
+ where: [],
110
+ having: [],
111
+ joins: [],
112
+ groupBy: [],
113
+ orderBy: []
114
+ }, undefined, "read", "select")
115
+
116
+ const groupBy = (...values: readonly Expression.Any[]) =>
117
+ (plan: any) => {
118
+ const current = plan[Plan.TypeId]
119
+ const currentAst = ctx.getAst(plan)
120
+ const currentQuery = ctx.getQueryState(plan)
121
+ const required = [...values.flatMap((value) => Object.keys(value[Expression.TypeId].dependencies))].filter((name, index, list) =>
122
+ !(name in current.available) && list.indexOf(name) === index)
123
+ return ctx.makePlan({
124
+ selection: current.selection,
125
+ required: [...ctx.currentRequiredList(current.required), ...required].filter((name, index, list) =>
126
+ !(name in current.available) && list.indexOf(name) === index),
127
+ available: current.available,
128
+ dialect: current.dialect
129
+ }, {
130
+ ...currentAst,
131
+ groupBy: ctx.dedupeGroupedExpressions([...currentAst.groupBy, ...values])
132
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement)
133
+ }
134
+
135
+ const returning = (selection: any) =>
136
+ (plan: any) => {
137
+ const current = plan[Plan.TypeId]
138
+ const currentAst = ctx.getAst(plan)
139
+ const currentQuery = ctx.getQueryState(plan)
140
+ return ctx.makePlan({
141
+ selection,
142
+ required: [...ctx.currentRequiredList(current.required), ...ctx.extractRequiredRuntime(selection)].filter((name, index, list) =>
143
+ !(name in current.available) && list.indexOf(name) === index),
144
+ available: current.available,
145
+ dialect: current.dialect
146
+ }, {
147
+ ...currentAst,
148
+ select: selection
149
+ }, currentQuery.assumptions, currentQuery.capabilities, currentQuery.statement, currentQuery.target, currentQuery.insertSource)
150
+ }
151
+
152
+ return {
153
+ values,
154
+ unnest,
155
+ generateSeries,
156
+ select,
157
+ groupBy,
158
+ returning
159
+ }
160
+ }