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.
- package/README.md +6 -1431
- package/dist/mysql.js +61945 -3611
- package/dist/postgres/metadata.js +2818 -0
- package/dist/postgres.js +9942 -5591
- package/package.json +21 -10
- package/src/internal/aggregation-validation.ts +3 -3
- package/src/internal/case-analysis.d.ts +18 -0
- package/src/internal/case-analysis.ts +4 -4
- package/src/internal/coercion/analysis.d.ts +7 -0
- package/src/internal/{coercion-analysis.ts → coercion/analysis.ts} +3 -3
- package/src/internal/coercion/errors.d.ts +17 -0
- package/src/internal/{coercion-errors.ts → coercion/errors.ts} +1 -1
- package/src/internal/coercion/kind.d.ts +4 -0
- package/src/internal/{coercion-kind.ts → coercion/kind.ts} +2 -2
- package/src/internal/{coercion-normalize.ts → coercion/normalize.ts} +1 -1
- package/src/internal/coercion/rules.d.ts +6 -0
- package/src/internal/{coercion-rules.ts → coercion/rules.ts} +2 -2
- package/src/internal/column-state.d.ts +190 -0
- package/src/internal/column-state.ts +119 -56
- package/src/internal/column.ts +387 -149
- package/src/internal/datatypes/define.d.ts +17 -0
- package/src/internal/datatypes/define.ts +18 -34
- package/src/internal/datatypes/lookup.d.ts +44 -0
- package/src/internal/datatypes/lookup.ts +61 -152
- package/src/internal/datatypes/shape.d.ts +16 -0
- package/src/internal/datatypes/shape.ts +1 -1
- package/src/internal/derived-table.d.ts +4 -0
- package/src/internal/derived-table.ts +21 -16
- package/src/internal/dsl-mutation-runtime.ts +378 -0
- package/src/internal/dsl-plan-runtime.ts +387 -0
- package/src/internal/dsl-query-runtime.ts +160 -0
- package/src/internal/dsl-transaction-ddl-runtime.ts +263 -0
- package/src/internal/executor.ts +173 -38
- package/src/internal/expression-ast.ts +19 -5
- package/src/internal/grouping-key.d.ts +3 -0
- package/src/internal/grouping-key.ts +1 -1
- package/src/internal/implication-runtime.d.ts +15 -0
- package/src/internal/implication-runtime.ts +171 -0
- package/src/internal/json/ast.d.ts +30 -0
- package/src/internal/json/ast.ts +1 -1
- package/src/internal/json/errors.d.ts +8 -0
- package/src/internal/json/path.d.ts +75 -0
- package/src/internal/json/path.ts +1 -1
- package/src/internal/json/types.d.ts +62 -0
- package/src/internal/predicate/analysis.d.ts +20 -0
- package/src/internal/{predicate-analysis.ts → predicate/analysis.ts} +13 -3
- package/src/internal/predicate/atom.d.ts +28 -0
- package/src/internal/{predicate-branches.ts → predicate/branches.ts} +2 -2
- package/src/internal/predicate/context.d.ts +67 -0
- package/src/internal/{predicate-context.ts → predicate/context.ts} +111 -32
- package/src/internal/predicate/formula.d.ts +35 -0
- package/src/internal/{predicate-formula.ts → predicate/formula.ts} +32 -20
- package/src/internal/predicate/key.d.ts +11 -0
- package/src/internal/{predicate-key.ts → predicate/key.ts} +2 -2
- package/src/internal/{predicate-nnf.ts → predicate/nnf.ts} +2 -2
- package/src/internal/predicate/normalize.d.ts +53 -0
- package/src/internal/predicate/normalize.ts +273 -0
- package/src/internal/predicate/runtime.d.ts +31 -0
- package/src/internal/predicate/runtime.ts +679 -0
- package/src/internal/projection-alias.d.ts +13 -0
- package/src/internal/projections.d.ts +31 -0
- package/src/internal/projections.ts +1 -1
- package/src/internal/query-ast.d.ts +217 -0
- package/src/internal/query-ast.ts +1 -1
- package/src/internal/query-requirements.d.ts +20 -0
- package/src/internal/query.d.ts +775 -0
- package/src/internal/query.ts +767 -275
- package/src/internal/renderer.ts +7 -21
- package/src/internal/row-set.d.ts +53 -0
- package/src/internal/{plan.ts → row-set.ts} +23 -11
- package/src/internal/{runtime-normalize.ts → runtime/normalize.ts} +9 -31
- package/src/internal/{runtime-schema.ts → runtime/schema.ts} +84 -55
- package/src/internal/runtime/value.d.ts +22 -0
- package/src/internal/{runtime-value.ts → runtime/value.ts} +2 -2
- package/src/internal/scalar.d.ts +107 -0
- package/src/internal/scalar.ts +191 -0
- package/src/internal/schema-derivation.d.ts +105 -0
- package/src/internal/schema-derivation.ts +93 -21
- package/src/internal/schema-expression.d.ts +18 -0
- package/src/internal/schema-expression.ts +75 -0
- package/src/internal/table-options.d.ts +94 -0
- package/src/internal/table-options.ts +94 -8
- package/src/internal/table.d.ts +173 -0
- package/src/internal/table.ts +135 -54
- package/src/mysql/column.ts +95 -18
- package/src/mysql/datatypes/index.ts +58 -3
- package/src/mysql/errors/generated.ts +57336 -0
- package/src/mysql/errors/index.ts +1 -0
- package/src/mysql/errors/normalize.ts +55 -53
- package/src/mysql/errors/types.ts +74 -0
- package/src/mysql/executor.ts +69 -7
- package/src/mysql/function/aggregate.ts +1 -5
- package/src/mysql/function/core.ts +1 -3
- package/src/mysql/function/index.ts +1 -1
- package/src/mysql/function/string.ts +1 -5
- package/src/mysql/function/temporal.ts +12 -15
- package/src/mysql/function/window.ts +1 -6
- package/src/{internal/mysql-dialect.ts → mysql/internal/dialect.ts} +1 -1
- package/src/mysql/internal/dsl.ts +6115 -0
- package/src/{internal/mysql-renderer.ts → mysql/internal/renderer.ts} +6 -6
- package/src/mysql/internal/sql-expression-renderer.ts +1455 -0
- package/src/mysql/json.ts +2 -0
- package/src/mysql/query.ts +111 -86
- package/src/mysql/renderer.ts +1 -1
- package/src/mysql/table.ts +1 -1
- package/src/mysql.ts +6 -4
- package/src/postgres/cast.ts +30 -0
- package/src/postgres/column.ts +178 -20
- package/src/postgres/datatypes/index.d.ts +515 -0
- package/src/postgres/datatypes/index.ts +49 -5
- package/src/postgres/datatypes/spec.d.ts +412 -0
- package/src/postgres/errors/generated.ts +2636 -0
- package/src/postgres/errors/index.ts +1 -0
- package/src/postgres/errors/normalize.ts +47 -62
- package/src/postgres/errors/types.ts +92 -34
- package/src/postgres/executor.ts +37 -5
- package/src/postgres/function/aggregate.ts +1 -5
- package/src/postgres/function/core.ts +20 -2
- package/src/postgres/function/index.ts +1 -1
- package/src/postgres/function/string.ts +1 -5
- package/src/postgres/function/temporal.ts +12 -15
- package/src/postgres/function/window.ts +1 -6
- package/src/{internal/postgres-dialect.ts → postgres/internal/dialect.ts} +1 -1
- package/src/{internal/query-factory.ts → postgres/internal/dsl.ts} +1568 -2120
- package/src/{internal/postgres-renderer.ts → postgres/internal/renderer.ts} +6 -6
- package/src/postgres/internal/schema-ddl.ts +108 -0
- package/src/postgres/internal/schema-model.ts +150 -0
- package/src/{internal → postgres/internal}/sql-expression-renderer.ts +112 -46
- package/src/postgres/json.ts +493 -0
- package/src/postgres/metadata.ts +31 -0
- package/src/postgres/query.ts +113 -86
- package/src/postgres/renderer.ts +3 -13
- package/src/postgres/schema-expression.ts +17 -0
- package/src/postgres/schema-management.ts +204 -0
- package/src/postgres/schema.ts +35 -0
- package/src/postgres/table.ts +316 -42
- package/src/postgres/type.ts +31 -0
- package/src/postgres.ts +20 -4
- package/CHANGELOG.md +0 -134
- package/src/internal/expression.ts +0 -327
- package/src/internal/predicate-normalize.ts +0 -202
- package/src/mysql/function/json.ts +0 -4
- package/src/mysql/private/query.ts +0 -13
- package/src/postgres/function/json.ts +0 -4
- package/src/postgres/private/query.ts +0 -13
- /package/src/internal/{predicate-atom.ts → predicate/atom.ts} +0 -0
|
@@ -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
|
+
}
|
package/src/internal/executor.ts
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
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 "./
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
+
import * as Expression from "./scalar.js"
|
|
10
|
+
import * as ExpressionAst from "./expression-ast.js"
|
|
11
|
+
import { resolveImplicationScope, type ImplicationScope } from "./implication-runtime.js"
|
|
12
|
+
import { normalizeDbValue } from "./runtime/normalize.js"
|
|
13
|
+
import { expressionRuntimeSchema } from "./runtime/schema.js"
|
|
9
14
|
import { flattenSelection } from "./projections.js"
|
|
10
15
|
import * as Query from "./query.js"
|
|
11
16
|
import * as QueryAst from "./query-ast.js"
|
|
12
17
|
import * as Renderer from "./renderer.js"
|
|
13
|
-
import * as Plan from "./
|
|
18
|
+
import * as Plan from "./row-set.js"
|
|
14
19
|
|
|
15
20
|
/** Flat database row keyed by rendered projection aliases. */
|
|
16
21
|
export type FlatRow = Readonly<Record<string, unknown>>
|
|
17
22
|
export type DriverMode = "raw" | "normalized"
|
|
18
23
|
|
|
24
|
+
type AstBackedExpression = Expression.Any & {
|
|
25
|
+
readonly [ExpressionAst.TypeId]: ExpressionAst.Any
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
export interface RowDecodeError {
|
|
20
29
|
readonly _tag: "RowDecodeError"
|
|
21
30
|
readonly message: string
|
|
@@ -52,6 +61,9 @@ export interface Driver<
|
|
|
52
61
|
execute<Row>(
|
|
53
62
|
query: Renderer.RenderedQuery<Row, Dialect>
|
|
54
63
|
): Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
|
|
64
|
+
stream<Row>(
|
|
65
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
66
|
+
): Stream.Stream<FlatRow, Error, Context>
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
/**
|
|
@@ -67,9 +79,12 @@ export interface Executor<
|
|
|
67
79
|
Context = never
|
|
68
80
|
> {
|
|
69
81
|
readonly dialect: Dialect
|
|
70
|
-
execute<PlanValue extends Query.
|
|
82
|
+
execute<PlanValue extends Query.Plan.Any>(
|
|
71
83
|
plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
|
|
72
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>
|
|
73
88
|
}
|
|
74
89
|
|
|
75
90
|
const setPath = (
|
|
@@ -111,21 +126,21 @@ const hasWriteStatement = (statement: QueryAst.QueryStatement): boolean =>
|
|
|
111
126
|
|
|
112
127
|
const hasWriteCapabilityInSource = (source: unknown): boolean =>
|
|
113
128
|
typeof source === "object" && source !== null && "plan" in source
|
|
114
|
-
? hasWriteCapability((source as { readonly plan: Query.
|
|
129
|
+
? hasWriteCapability((source as { readonly plan: Query.Plan.Any }).plan)
|
|
115
130
|
: false
|
|
116
131
|
|
|
117
132
|
export const hasWriteCapability = (
|
|
118
|
-
plan: Query.
|
|
133
|
+
plan: Query.Plan.Any
|
|
119
134
|
): boolean => {
|
|
120
135
|
const ast = Query.getAst(plan)
|
|
121
136
|
if (hasWriteStatement(ast.kind)) {
|
|
122
137
|
return true
|
|
123
138
|
}
|
|
124
139
|
if (ast.kind === "set") {
|
|
125
|
-
if (ast.setBase && hasWriteCapability((ast.setBase as Query.
|
|
140
|
+
if (ast.setBase && hasWriteCapability((ast.setBase as Query.Plan.Any))) {
|
|
126
141
|
return true
|
|
127
142
|
}
|
|
128
|
-
if ((ast.setOperations ?? []).some((entry) => hasWriteCapability(entry.query as Query.
|
|
143
|
+
if ((ast.setOperations ?? []).some((entry) => hasWriteCapability(entry.query as Query.Plan.Any))) {
|
|
129
144
|
return true
|
|
130
145
|
}
|
|
131
146
|
}
|
|
@@ -189,24 +204,35 @@ const makeRowDecodeError = (
|
|
|
189
204
|
|
|
190
205
|
const hasOptionalSourceDependency = (
|
|
191
206
|
expression: Expression.Any,
|
|
192
|
-
|
|
207
|
+
scope: ImplicationScope
|
|
193
208
|
): boolean => {
|
|
194
209
|
const state = expression[Expression.TypeId]
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
return Object.keys(state.dependencies).some((sourceName) => available[sourceName]?.mode === "optional")
|
|
210
|
+
return Object.keys(state.dependencies).some((sourceName) =>
|
|
211
|
+
!scope.absentSourceNames.has(sourceName) && scope.sourceModes.get(sourceName) === "optional")
|
|
199
212
|
}
|
|
200
213
|
|
|
201
214
|
const effectiveRuntimeNullability = (
|
|
202
215
|
expression: Expression.Any,
|
|
203
|
-
|
|
216
|
+
scope: ImplicationScope
|
|
204
217
|
): Expression.Nullability => {
|
|
205
218
|
const nullability = expression[Expression.TypeId].nullability
|
|
219
|
+
const ast = (expression as AstBackedExpression)[ExpressionAst.TypeId]
|
|
206
220
|
if (nullability === "always") {
|
|
207
221
|
return "always"
|
|
208
222
|
}
|
|
209
|
-
|
|
223
|
+
if (ast.kind === "column") {
|
|
224
|
+
const key = `${ast.tableName}.${ast.columnName}`
|
|
225
|
+
if (scope.absentSourceNames.has(ast.tableName) || scope.nullKeys.has(key)) {
|
|
226
|
+
return "always"
|
|
227
|
+
}
|
|
228
|
+
if (scope.nonNullKeys.has(key)) {
|
|
229
|
+
return "never"
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (Object.keys(expression[Expression.TypeId].dependencies).some((sourceName) => scope.absentSourceNames.has(sourceName))) {
|
|
233
|
+
return "always"
|
|
234
|
+
}
|
|
235
|
+
return hasOptionalSourceDependency(expression, scope)
|
|
210
236
|
? "maybe"
|
|
211
237
|
: nullability
|
|
212
238
|
}
|
|
@@ -216,7 +242,7 @@ const decodeProjectionValue = (
|
|
|
216
242
|
projection: Renderer.RenderedQuery<any, any>["projections"][number],
|
|
217
243
|
expression: Expression.Any,
|
|
218
244
|
raw: unknown,
|
|
219
|
-
|
|
245
|
+
scope: ImplicationScope,
|
|
220
246
|
driverMode: DriverMode
|
|
221
247
|
): unknown => {
|
|
222
248
|
let normalized = raw
|
|
@@ -228,8 +254,9 @@ const decodeProjectionValue = (
|
|
|
228
254
|
}
|
|
229
255
|
}
|
|
230
256
|
|
|
257
|
+
const nullability = effectiveRuntimeNullability(expression, scope)
|
|
231
258
|
if (normalized === null) {
|
|
232
|
-
if (
|
|
259
|
+
if (nullability === "never") {
|
|
233
260
|
throw makeRowDecodeError(
|
|
234
261
|
rendered,
|
|
235
262
|
projection,
|
|
@@ -243,7 +270,19 @@ const decodeProjectionValue = (
|
|
|
243
270
|
return null
|
|
244
271
|
}
|
|
245
272
|
|
|
246
|
-
|
|
273
|
+
if (nullability === "always") {
|
|
274
|
+
throw makeRowDecodeError(
|
|
275
|
+
rendered,
|
|
276
|
+
projection,
|
|
277
|
+
expression,
|
|
278
|
+
raw,
|
|
279
|
+
"schema",
|
|
280
|
+
new Error("Received non-null for an always-null projection"),
|
|
281
|
+
normalized
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const schema = expressionRuntimeSchema(expression, { assumptions: scope.assumptions })
|
|
247
286
|
if (schema === undefined) {
|
|
248
287
|
return normalized
|
|
249
288
|
}
|
|
@@ -259,14 +298,13 @@ const decodeProjectionValue = (
|
|
|
259
298
|
}
|
|
260
299
|
}
|
|
261
300
|
|
|
262
|
-
export const
|
|
301
|
+
export const makeRowDecoder = (
|
|
263
302
|
rendered: Renderer.RenderedQuery<any, any>,
|
|
264
|
-
plan: Query.
|
|
265
|
-
rows: ReadonlyArray<FlatRow>,
|
|
303
|
+
plan: Query.Plan.Any,
|
|
266
304
|
options: {
|
|
267
305
|
readonly driverMode?: DriverMode
|
|
268
306
|
} = {}
|
|
269
|
-
):
|
|
307
|
+
): ((row: FlatRow) => any) => {
|
|
270
308
|
const projections = flattenSelection(
|
|
271
309
|
Query.getAst(plan).select as Record<string, unknown>
|
|
272
310
|
)
|
|
@@ -274,8 +312,8 @@ export const decodeRows = (
|
|
|
274
312
|
projections.map((projection) => [projection.alias, projection.expression] as const)
|
|
275
313
|
)
|
|
276
314
|
const driverMode = options.driverMode ?? "raw"
|
|
277
|
-
const
|
|
278
|
-
return
|
|
315
|
+
const scope = resolveImplicationScope(plan[Plan.TypeId].available, Query.getQueryState(plan).assumptions)
|
|
316
|
+
return (row) => {
|
|
279
317
|
const decoded: Record<string, unknown> = {}
|
|
280
318
|
for (const projection of rendered.projections) {
|
|
281
319
|
if (!(projection.alias in row)) {
|
|
@@ -288,11 +326,35 @@ export const decodeRows = (
|
|
|
288
326
|
setPath(
|
|
289
327
|
decoded,
|
|
290
328
|
projection.path,
|
|
291
|
-
decodeProjectionValue(rendered, projection, expression, row[projection.alias],
|
|
329
|
+
decodeProjectionValue(rendered, projection, expression, row[projection.alias], scope, driverMode)
|
|
292
330
|
)
|
|
293
331
|
}
|
|
294
332
|
return decoded
|
|
295
|
-
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export const decodeChunk = (
|
|
337
|
+
rendered: Renderer.RenderedQuery<any, any>,
|
|
338
|
+
plan: Query.Plan.Any,
|
|
339
|
+
rows: Chunk.Chunk<FlatRow>,
|
|
340
|
+
options: {
|
|
341
|
+
readonly driverMode?: DriverMode
|
|
342
|
+
} = {}
|
|
343
|
+
): Chunk.Chunk<any> => {
|
|
344
|
+
const decodeRow = makeRowDecoder(rendered, plan, options)
|
|
345
|
+
return Chunk.unsafeFromArray(Chunk.toReadonlyArray(rows).map((row) => decodeRow(row)))
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export const decodeRows = (
|
|
349
|
+
rendered: Renderer.RenderedQuery<any, any>,
|
|
350
|
+
plan: Query.Plan.Any,
|
|
351
|
+
rows: ReadonlyArray<FlatRow>,
|
|
352
|
+
options: {
|
|
353
|
+
readonly driverMode?: DriverMode
|
|
354
|
+
} = {}
|
|
355
|
+
): ReadonlyArray<any> => {
|
|
356
|
+
const decodeRow = makeRowDecoder(rendered, plan, options)
|
|
357
|
+
return rows.map((row) => decodeRow(row))
|
|
296
358
|
}
|
|
297
359
|
|
|
298
360
|
/**
|
|
@@ -304,20 +366,23 @@ export const make = <
|
|
|
304
366
|
Context = never
|
|
305
367
|
>(
|
|
306
368
|
dialect: Dialect,
|
|
307
|
-
execute: <PlanValue extends Query.
|
|
369
|
+
execute: <PlanValue extends Query.Plan.Any>(
|
|
308
370
|
plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
|
|
309
371
|
) => Effect.Effect<Query.ResultRows<PlanValue>, Error, Context>
|
|
310
372
|
): Executor<Dialect, Error, Context> => ({
|
|
311
373
|
dialect,
|
|
312
374
|
execute(plan) {
|
|
313
375
|
return (execute as any)(plan)
|
|
376
|
+
},
|
|
377
|
+
stream(plan) {
|
|
378
|
+
return Stream.unwrap(Effect.map((execute as any)(plan), (rows: ReadonlyArray<any>) => Stream.fromIterable(rows)))
|
|
314
379
|
}
|
|
315
380
|
}) as Executor<Dialect, Error, Context>
|
|
316
381
|
|
|
317
382
|
/**
|
|
318
383
|
* Constructs a driver from a dialect and execution callback.
|
|
319
384
|
*/
|
|
320
|
-
export
|
|
385
|
+
export function driver<
|
|
321
386
|
Dialect extends string,
|
|
322
387
|
Error = never,
|
|
323
388
|
Context = never
|
|
@@ -326,12 +391,58 @@ export const driver = <
|
|
|
326
391
|
execute: <Row>(
|
|
327
392
|
query: Renderer.RenderedQuery<Row, Dialect>
|
|
328
393
|
) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
|
|
329
|
-
): Driver<Dialect, Error, Context>
|
|
394
|
+
): Driver<Dialect, Error, Context>
|
|
395
|
+
export function driver<
|
|
396
|
+
Dialect extends string,
|
|
397
|
+
Error = never,
|
|
398
|
+
Context = never
|
|
399
|
+
>(
|
|
400
|
+
dialect: Dialect,
|
|
401
|
+
handlers: {
|
|
402
|
+
readonly execute: <Row>(
|
|
403
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
404
|
+
) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
|
|
405
|
+
readonly stream: <Row>(
|
|
406
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
407
|
+
) => Stream.Stream<FlatRow, Error, Context>
|
|
408
|
+
}
|
|
409
|
+
): Driver<Dialect, Error, Context>
|
|
410
|
+
export function driver<
|
|
411
|
+
Dialect extends string,
|
|
412
|
+
Error = never,
|
|
413
|
+
Context = never
|
|
414
|
+
>(
|
|
415
|
+
dialect: Dialect,
|
|
416
|
+
executeOrHandlers:
|
|
417
|
+
| (<Row>(
|
|
418
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
419
|
+
) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>)
|
|
420
|
+
| {
|
|
421
|
+
readonly execute: <Row>(
|
|
422
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
423
|
+
) => Effect.Effect<ReadonlyArray<FlatRow>, Error, Context>
|
|
424
|
+
readonly stream: <Row>(
|
|
425
|
+
query: Renderer.RenderedQuery<Row, Dialect>
|
|
426
|
+
) => Stream.Stream<FlatRow, Error, Context>
|
|
427
|
+
}
|
|
428
|
+
): Driver<Dialect, Error, Context> {
|
|
429
|
+
return {
|
|
330
430
|
dialect,
|
|
331
431
|
execute(query) {
|
|
332
|
-
return
|
|
432
|
+
return typeof executeOrHandlers === "function"
|
|
433
|
+
? executeOrHandlers(query)
|
|
434
|
+
: executeOrHandlers.execute(query)
|
|
435
|
+
},
|
|
436
|
+
stream(query) {
|
|
437
|
+
if (typeof executeOrHandlers === "function") {
|
|
438
|
+
return Stream.unwrap(
|
|
439
|
+
Effect.map(executeOrHandlers(query), (rows) => Stream.fromIterable(rows))
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
return executeOrHandlers.stream(query)
|
|
333
443
|
}
|
|
334
|
-
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
335
446
|
|
|
336
447
|
/**
|
|
337
448
|
* Creates an executor by composing a renderer with a rendered-query driver.
|
|
@@ -357,20 +468,44 @@ export const fromDriver = <
|
|
|
357
468
|
sqlDriver.execute(rendered),
|
|
358
469
|
(rows) => remapRows<any>(rendered, rows)
|
|
359
470
|
)
|
|
471
|
+
},
|
|
472
|
+
stream(plan: any) {
|
|
473
|
+
const rendered = renderer.render(plan) as Renderer.RenderedQuery<any, Dialect>
|
|
474
|
+
return Stream.mapChunks(
|
|
475
|
+
sqlDriver.stream(rendered),
|
|
476
|
+
(rows) => Chunk.unsafeFromArray(remapRows<any>(rendered, Chunk.toReadonlyArray(rows)))
|
|
477
|
+
)
|
|
360
478
|
}
|
|
361
479
|
}
|
|
362
480
|
return executor as unknown as Executor<Dialect, Error, Context>
|
|
363
481
|
}
|
|
364
482
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
483
|
+
export const streamFromSqlClient = <Dialect extends string>(
|
|
484
|
+
query: Renderer.RenderedQuery<any, Dialect>
|
|
485
|
+
): Stream.Stream<FlatRow, SqlError.SqlError, SqlClient.SqlClient> =>
|
|
486
|
+
Stream.unwrapScoped(
|
|
487
|
+
Effect.flatMap(SqlClient.SqlClient, (sql) =>
|
|
488
|
+
Effect.flatMap(
|
|
489
|
+
Effect.serviceOption(SqlClient.TransactionConnection),
|
|
490
|
+
Option.match({
|
|
491
|
+
onNone: () => sql.reserve,
|
|
492
|
+
onSome: ([connection]) => Effect.succeed(connection)
|
|
493
|
+
})
|
|
494
|
+
).pipe(
|
|
495
|
+
Effect.map((connection) => connection.executeStream(query.sql, [...query.params], undefined))
|
|
496
|
+
)
|
|
497
|
+
)
|
|
498
|
+
)
|
|
499
|
+
|
|
368
500
|
export const fromSqlClient = <Dialect extends string>(
|
|
369
501
|
renderer: Renderer.Renderer<Dialect>
|
|
370
502
|
): Executor<Dialect, unknown, SqlClient.SqlClient> =>
|
|
371
|
-
fromDriver(renderer, driver(renderer.dialect,
|
|
372
|
-
|
|
373
|
-
|
|
503
|
+
fromDriver(renderer, driver(renderer.dialect, {
|
|
504
|
+
execute: (query) =>
|
|
505
|
+
Effect.flatMap(SqlClient.SqlClient, (sql) =>
|
|
506
|
+
sql.unsafe<FlatRow>(query.sql, [...query.params])),
|
|
507
|
+
stream: (query) => streamFromSqlClient(query)
|
|
508
|
+
}))
|
|
374
509
|
|
|
375
510
|
/** Runs an effect within the ambient `@effect/sql` transaction service. */
|
|
376
511
|
export const withTransaction = <A, E, R>(
|