effect-qb 0.15.0 → 0.17.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/dist/mysql.js +1957 -595
- package/dist/postgres/metadata.js +2507 -182
- package/dist/postgres.js +9587 -8201
- package/dist/sqlite.js +8360 -0
- package/package.json +7 -2
- package/src/internal/column-state.ts +7 -0
- package/src/internal/column.ts +22 -0
- package/src/internal/derived-table.ts +29 -3
- package/src/internal/dialect.ts +14 -1
- package/src/internal/dsl-mutation-runtime.ts +173 -4
- package/src/internal/dsl-plan-runtime.ts +165 -20
- package/src/internal/dsl-query-runtime.ts +60 -6
- package/src/internal/dsl-transaction-ddl-runtime.ts +72 -2
- package/src/internal/executor.ts +62 -13
- package/src/internal/expression-ast.ts +3 -2
- package/src/internal/grouping-key.ts +141 -1
- package/src/internal/implication-runtime.ts +2 -1
- package/src/internal/json/types.ts +155 -40
- package/src/internal/predicate/analysis.ts +103 -1
- package/src/internal/predicate/atom.ts +7 -0
- package/src/internal/predicate/context.ts +170 -17
- package/src/internal/predicate/key.ts +64 -2
- package/src/internal/predicate/normalize.ts +115 -34
- package/src/internal/predicate/runtime.ts +144 -13
- package/src/internal/query.ts +563 -103
- package/src/internal/renderer.ts +39 -2
- package/src/internal/runtime/driver-value-mapping.ts +244 -0
- package/src/internal/runtime/normalize.ts +62 -38
- package/src/internal/runtime/schema.ts +5 -3
- package/src/internal/runtime/value.ts +153 -30
- package/src/internal/scalar.ts +11 -0
- package/src/internal/table-options.ts +108 -1
- package/src/internal/table.ts +87 -29
- package/src/mysql/column.ts +19 -2
- package/src/mysql/datatypes/index.ts +21 -0
- package/src/mysql/errors/catalog.ts +5 -5
- package/src/mysql/errors/normalize.ts +2 -2
- package/src/mysql/executor.ts +20 -5
- package/src/mysql/internal/dialect.ts +12 -6
- package/src/mysql/internal/dsl.ts +995 -263
- package/src/mysql/internal/renderer.ts +13 -3
- package/src/mysql/internal/sql-expression-renderer.ts +530 -128
- package/src/mysql/query.ts +9 -2
- package/src/mysql/renderer.ts +7 -2
- package/src/mysql/table.ts +38 -12
- package/src/postgres/cast.ts +22 -7
- package/src/postgres/column.ts +5 -2
- package/src/postgres/errors/normalize.ts +2 -2
- package/src/postgres/executor.ts +68 -10
- package/src/postgres/function/core.ts +19 -1
- package/src/postgres/internal/dialect.ts +12 -6
- package/src/postgres/internal/dsl.ts +958 -288
- package/src/postgres/internal/renderer.ts +13 -3
- package/src/postgres/internal/schema-ddl.ts +2 -1
- package/src/postgres/internal/schema-model.ts +6 -3
- package/src/postgres/internal/sql-expression-renderer.ts +477 -96
- package/src/postgres/json.ts +57 -17
- package/src/postgres/query.ts +9 -2
- package/src/postgres/renderer.ts +7 -2
- package/src/postgres/schema-management.ts +91 -4
- package/src/postgres/schema.ts +1 -1
- package/src/postgres/table.ts +189 -53
- package/src/postgres/type.ts +4 -0
- package/src/sqlite/column.ts +128 -0
- package/src/sqlite/datatypes/index.ts +79 -0
- package/src/sqlite/datatypes/spec.ts +98 -0
- package/src/sqlite/errors/catalog.ts +103 -0
- package/src/sqlite/errors/fields.ts +19 -0
- package/src/sqlite/errors/index.ts +19 -0
- package/src/sqlite/errors/normalize.ts +229 -0
- package/src/sqlite/errors/requirements.ts +71 -0
- package/src/sqlite/errors/types.ts +29 -0
- package/src/sqlite/executor.ts +227 -0
- package/src/sqlite/function/aggregate.ts +2 -0
- package/src/sqlite/function/core.ts +2 -0
- package/src/sqlite/function/index.ts +19 -0
- package/src/sqlite/function/string.ts +2 -0
- package/src/sqlite/function/temporal.ts +100 -0
- package/src/sqlite/function/window.ts +2 -0
- package/src/sqlite/internal/dialect.ts +37 -0
- package/src/sqlite/internal/dsl.ts +6926 -0
- package/src/sqlite/internal/renderer.ts +47 -0
- package/src/sqlite/internal/sql-expression-renderer.ts +1821 -0
- package/src/sqlite/json.ts +2 -0
- package/src/sqlite/query.ts +196 -0
- package/src/sqlite/renderer.ts +24 -0
- package/src/sqlite/table.ts +183 -0
- package/src/sqlite.ts +22 -0
|
@@ -4,6 +4,7 @@ import type { PredicateAtom } from "./atom.js"
|
|
|
4
4
|
import type {
|
|
5
5
|
EqColumnAtom,
|
|
6
6
|
EqLiteralAtom,
|
|
7
|
+
LiteralSetAtom,
|
|
7
8
|
NeqLiteralAtom,
|
|
8
9
|
NonNullAtom,
|
|
9
10
|
NullAtom,
|
|
@@ -24,6 +25,7 @@ export interface RuntimeContext {
|
|
|
24
25
|
readonly nullKeys: ReadonlySet<string>
|
|
25
26
|
readonly eqLiterals: ReadonlyMap<string, string>
|
|
26
27
|
readonly neqLiterals: ReadonlyMap<string, ReadonlySet<string>>
|
|
28
|
+
readonly literalSets: ReadonlyMap<string, ReadonlySet<string>>
|
|
27
29
|
readonly sourceNames: ReadonlySet<string>
|
|
28
30
|
readonly contradiction: boolean
|
|
29
31
|
readonly unknown: boolean
|
|
@@ -34,6 +36,7 @@ type MutableContext = {
|
|
|
34
36
|
nullKeys: Set<string>
|
|
35
37
|
eqLiterals: Map<string, string>
|
|
36
38
|
neqLiterals: Map<string, Set<string>>
|
|
39
|
+
literalSets: Map<string, Set<string>>
|
|
37
40
|
sourceNames: Set<string>
|
|
38
41
|
contradiction: boolean
|
|
39
42
|
unknown: boolean
|
|
@@ -72,6 +75,7 @@ const emptyContext = (): MutableContext => ({
|
|
|
72
75
|
nullKeys: new Set(),
|
|
73
76
|
eqLiterals: new Map(),
|
|
74
77
|
neqLiterals: new Map(),
|
|
78
|
+
literalSets: new Map(),
|
|
75
79
|
sourceNames: new Set(),
|
|
76
80
|
contradiction: false,
|
|
77
81
|
unknown: false
|
|
@@ -84,6 +88,9 @@ const cloneContext = (context: MutableContext): MutableContext => ({
|
|
|
84
88
|
neqLiterals: new Map(
|
|
85
89
|
Array.from(context.neqLiterals.entries(), ([key, values]) => [key, new Set(values)])
|
|
86
90
|
),
|
|
91
|
+
literalSets: new Map(
|
|
92
|
+
Array.from(context.literalSets.entries(), ([key, values]) => [key, new Set(values)])
|
|
93
|
+
),
|
|
87
94
|
sourceNames: new Set(context.sourceNames),
|
|
88
95
|
contradiction: context.contradiction,
|
|
89
96
|
unknown: context.unknown
|
|
@@ -91,7 +98,26 @@ const cloneContext = (context: MutableContext): MutableContext => ({
|
|
|
91
98
|
|
|
92
99
|
const freezeContext = (context: MutableContext): RuntimeContext => context
|
|
93
100
|
|
|
94
|
-
const
|
|
101
|
+
export const columnPredicateKey = (tableName: string, columnName: string): string =>
|
|
102
|
+
JSON.stringify([tableName, columnName])
|
|
103
|
+
|
|
104
|
+
const columnPredicateKeyParts = (key: string): readonly [string, string] | undefined => {
|
|
105
|
+
const jsonSeparator = key.indexOf("#json:")
|
|
106
|
+
const columnKey = jsonSeparator === -1 ? key : key.slice(0, jsonSeparator)
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(columnKey) as unknown
|
|
109
|
+
return Array.isArray(parsed) &&
|
|
110
|
+
parsed.length === 2 &&
|
|
111
|
+
typeof parsed[0] === "string" &&
|
|
112
|
+
typeof parsed[1] === "string"
|
|
113
|
+
? [parsed[0], parsed[1]]
|
|
114
|
+
: undefined
|
|
115
|
+
} catch {
|
|
116
|
+
return undefined
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const sourceNameOfKey = (key: string): string => columnPredicateKeyParts(key)?.[0] ?? key.split(".", 1)[0] ?? key
|
|
95
121
|
|
|
96
122
|
const addSourceName = (context: MutableContext, key: string): void => {
|
|
97
123
|
context.sourceNames.add(sourceNameOfKey(key))
|
|
@@ -123,7 +149,12 @@ const addEqLiteral = (context: MutableContext, key: string, value: string): void
|
|
|
123
149
|
if (neqValues?.has(value)) {
|
|
124
150
|
context.contradiction = true
|
|
125
151
|
}
|
|
152
|
+
const existingSet = context.literalSets.get(key)
|
|
153
|
+
if (existingSet !== undefined && !existingSet.has(value)) {
|
|
154
|
+
context.contradiction = true
|
|
155
|
+
}
|
|
126
156
|
context.eqLiterals.set(key, value)
|
|
157
|
+
context.literalSets.set(key, new Set([value]))
|
|
127
158
|
}
|
|
128
159
|
|
|
129
160
|
const addNeqLiteral = (context: MutableContext, key: string, value: string): void => {
|
|
@@ -136,6 +167,24 @@ const addNeqLiteral = (context: MutableContext, key: string, value: string): voi
|
|
|
136
167
|
context.neqLiterals.set(key, values)
|
|
137
168
|
}
|
|
138
169
|
|
|
170
|
+
const addLiteralSet = (context: MutableContext, key: string, values: ReadonlySet<string>): void => {
|
|
171
|
+
addNonNull(context, key)
|
|
172
|
+
const existingEq = context.eqLiterals.get(key)
|
|
173
|
+
if (existingEq !== undefined && !values.has(existingEq)) {
|
|
174
|
+
context.contradiction = true
|
|
175
|
+
}
|
|
176
|
+
const existing = context.literalSets.get(key)
|
|
177
|
+
context.literalSets.set(
|
|
178
|
+
key,
|
|
179
|
+
existing === undefined
|
|
180
|
+
? new Set(values)
|
|
181
|
+
: new Set(Array.from(existing).filter((value) => values.has(value)))
|
|
182
|
+
)
|
|
183
|
+
if (context.literalSets.get(key)?.size === 0) {
|
|
184
|
+
context.contradiction = true
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
139
188
|
const applyEqColumn = (context: MutableContext, left: string, right: string): void => {
|
|
140
189
|
const leftValue = context.eqLiterals.get(left)
|
|
141
190
|
const rightValue = context.eqLiterals.get(right)
|
|
@@ -176,6 +225,9 @@ const applyAtom = (context: MutableContext, atom: PredicateAtom): void => {
|
|
|
176
225
|
case "neq-literal":
|
|
177
226
|
addNeqLiteral(context, atom.key, atom.value)
|
|
178
227
|
return
|
|
228
|
+
case "literal-set":
|
|
229
|
+
addLiteralSet(context, atom.key, new Set(atom.values))
|
|
230
|
+
return
|
|
179
231
|
case "eq-column":
|
|
180
232
|
applyEqColumn(context, atom.left, atom.right)
|
|
181
233
|
return
|
|
@@ -199,6 +251,9 @@ const applyNegativeAtom = (context: MutableContext, atom: PredicateAtom): void =
|
|
|
199
251
|
case "neq-literal":
|
|
200
252
|
addEqLiteral(context, atom.key, atom.value)
|
|
201
253
|
return
|
|
254
|
+
case "literal-set":
|
|
255
|
+
addNonNull(context, atom.key)
|
|
256
|
+
return
|
|
202
257
|
case "eq-column":
|
|
203
258
|
addNonNull(context, atom.left)
|
|
204
259
|
addNonNull(context, atom.right)
|
|
@@ -240,6 +295,21 @@ const intersectNeqLiterals = (
|
|
|
240
295
|
return result
|
|
241
296
|
}
|
|
242
297
|
|
|
298
|
+
const unionLiteralSets = (
|
|
299
|
+
left: ReadonlyMap<string, ReadonlySet<string>>,
|
|
300
|
+
right: ReadonlyMap<string, ReadonlySet<string>>
|
|
301
|
+
): Map<string, Set<string>> => {
|
|
302
|
+
const result = new Map<string, Set<string>>()
|
|
303
|
+
for (const [key, leftValues] of left) {
|
|
304
|
+
const rightValues = right.get(key)
|
|
305
|
+
if (rightValues === undefined) {
|
|
306
|
+
continue
|
|
307
|
+
}
|
|
308
|
+
result.set(key, new Set([...leftValues, ...rightValues]))
|
|
309
|
+
}
|
|
310
|
+
return result
|
|
311
|
+
}
|
|
312
|
+
|
|
243
313
|
const intersectContexts = (left: MutableContext, right: MutableContext): MutableContext => {
|
|
244
314
|
if (left.contradiction) {
|
|
245
315
|
return cloneContext(right)
|
|
@@ -252,6 +322,7 @@ const intersectContexts = (left: MutableContext, right: MutableContext): Mutable
|
|
|
252
322
|
nullKeys: new Set(Array.from(left.nullKeys).filter((key) => right.nullKeys.has(key))),
|
|
253
323
|
eqLiterals: intersectEqLiterals(left.eqLiterals, right.eqLiterals),
|
|
254
324
|
neqLiterals: intersectNeqLiterals(left.neqLiterals, right.neqLiterals),
|
|
325
|
+
literalSets: unionLiteralSets(left.literalSets, right.literalSets),
|
|
255
326
|
sourceNames: new Set(Array.from(left.sourceNames).filter((name) => right.sourceNames.has(name))),
|
|
256
327
|
contradiction: false,
|
|
257
328
|
unknown: left.unknown || right.unknown
|
|
@@ -334,7 +405,59 @@ const astOf = (value: Expression.Any): ExpressionAst.Any =>
|
|
|
334
405
|
|
|
335
406
|
const columnKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
336
407
|
const ast = astOf(value)
|
|
337
|
-
return ast.kind === "column" ?
|
|
408
|
+
return ast.kind === "column" ? columnPredicateKey(ast.tableName, ast.columnName) : undefined
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const sameDbType = (left: Expression.DbType.Any, right: Expression.DbType.Any): boolean =>
|
|
412
|
+
left.dialect === right.dialect && left.kind === right.kind
|
|
413
|
+
|
|
414
|
+
const escapeJsonPathPredicateKeySegment = (value: string): string =>
|
|
415
|
+
value.replaceAll("\\", "\\\\").replaceAll(".", "\\.")
|
|
416
|
+
|
|
417
|
+
const jsonPathPredicateKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
418
|
+
const ast = astOf(value)
|
|
419
|
+
switch (ast.kind) {
|
|
420
|
+
case "jsonGetText":
|
|
421
|
+
case "jsonPathText":
|
|
422
|
+
case "jsonAccessText":
|
|
423
|
+
case "jsonTraverseText": {
|
|
424
|
+
const jsonAst = ast as ExpressionAst.JsonAccessNode
|
|
425
|
+
const segments = jsonAst.segments
|
|
426
|
+
if (segments.length === 0 || segments.length > 8) {
|
|
427
|
+
return undefined
|
|
428
|
+
}
|
|
429
|
+
const path: Array<string> = []
|
|
430
|
+
for (const segment of segments) {
|
|
431
|
+
if (typeof segment !== "object" || segment === null || segment.kind !== "key") {
|
|
432
|
+
return undefined
|
|
433
|
+
}
|
|
434
|
+
path.push(segment.key)
|
|
435
|
+
}
|
|
436
|
+
if (path.length === 0) {
|
|
437
|
+
return undefined
|
|
438
|
+
}
|
|
439
|
+
const baseKey = columnKeyOfExpression(jsonAst.base)
|
|
440
|
+
return baseKey === undefined
|
|
441
|
+
? undefined
|
|
442
|
+
: `${baseKey}#json:${path.map(escapeJsonPathPredicateKeySegment).join(".")}`
|
|
443
|
+
}
|
|
444
|
+
default:
|
|
445
|
+
return undefined
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const predicateKeyOfExpression = (value: Expression.Any): string | undefined =>
|
|
450
|
+
columnKeyOfExpression(value) ?? castPredicateKeyOfExpression(value) ?? jsonPathPredicateKeyOfExpression(value)
|
|
451
|
+
|
|
452
|
+
const castPredicateKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
453
|
+
const ast = astOf(value)
|
|
454
|
+
if (ast.kind !== "cast") {
|
|
455
|
+
return undefined
|
|
456
|
+
}
|
|
457
|
+
const source = ast.value as Expression.Any
|
|
458
|
+
return sameDbType(source[Expression.TypeId].dbType, ast.target)
|
|
459
|
+
? predicateKeyOfExpression(source)
|
|
460
|
+
: undefined
|
|
338
461
|
}
|
|
339
462
|
|
|
340
463
|
const valueKeyOfLiteral = (value: unknown): string => {
|
|
@@ -357,7 +480,7 @@ const valueKeyOfLiteral = (value: unknown): string => {
|
|
|
357
480
|
}
|
|
358
481
|
|
|
359
482
|
const nonNullFactsOfExpression = (value: Expression.Any): PredicateFormula | undefined => {
|
|
360
|
-
const key =
|
|
483
|
+
const key = predicateKeyOfExpression(value)
|
|
361
484
|
return key === undefined ? undefined : atomFormula<NonNullAtom<string>>({ kind: "is-not-null", key })
|
|
362
485
|
}
|
|
363
486
|
|
|
@@ -375,8 +498,8 @@ const combineFacts = (
|
|
|
375
498
|
}
|
|
376
499
|
|
|
377
500
|
const formulaOfEq = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
378
|
-
const leftKey =
|
|
379
|
-
const rightKey =
|
|
501
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
502
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
380
503
|
const leftAst = astOf(left)
|
|
381
504
|
const rightAst = astOf(right)
|
|
382
505
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -428,8 +551,8 @@ const formulaOfEq = (left: Expression.Any, right: Expression.Any): PredicateForm
|
|
|
428
551
|
}
|
|
429
552
|
|
|
430
553
|
const formulaOfNeq = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
431
|
-
const leftKey =
|
|
432
|
-
const rightKey =
|
|
554
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
555
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
433
556
|
const leftAst = astOf(left)
|
|
434
557
|
const rightAst = astOf(right)
|
|
435
558
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -477,8 +600,8 @@ const formulaOfNeq = (left: Expression.Any, right: Expression.Any): PredicateFor
|
|
|
477
600
|
}
|
|
478
601
|
|
|
479
602
|
const formulaOfIsNotDistinctFrom = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
480
|
-
const leftKey =
|
|
481
|
-
const rightKey =
|
|
603
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
604
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
482
605
|
const leftAst = astOf(left)
|
|
483
606
|
const rightAst = astOf(right)
|
|
484
607
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -587,13 +710,13 @@ export const formulaOfExpression = (value: Expression.Any): PredicateFormula =>
|
|
|
587
710
|
}
|
|
588
711
|
return unknownTag("literal:non-boolean")
|
|
589
712
|
case "isNull": {
|
|
590
|
-
const key =
|
|
713
|
+
const key = predicateKeyOfExpression(ast.value)
|
|
591
714
|
return key === undefined
|
|
592
715
|
? unknownTag("isNull:unsupported")
|
|
593
716
|
: atomFormula<NullAtom<string>>({ kind: "is-null", key })
|
|
594
717
|
}
|
|
595
718
|
case "isNotNull": {
|
|
596
|
-
const key =
|
|
719
|
+
const key = predicateKeyOfExpression(ast.value)
|
|
597
720
|
return key === undefined
|
|
598
721
|
? unknownTag("isNotNull:unsupported")
|
|
599
722
|
: atomFormula<NonNullAtom<string>>({ kind: "is-not-null", key })
|
|
@@ -614,8 +737,16 @@ export const formulaOfExpression = (value: Expression.Any): PredicateFormula =>
|
|
|
614
737
|
return anyFormula(ast.values.map((value: Expression.Any) => formulaOfExpression(value)))
|
|
615
738
|
case "in": {
|
|
616
739
|
const [left, ...rest] = ast.values
|
|
617
|
-
|
|
618
|
-
|
|
740
|
+
if (left === undefined) {
|
|
741
|
+
return falseFormula()
|
|
742
|
+
}
|
|
743
|
+
const key = predicateKeyOfExpression(left)
|
|
744
|
+
const literalValues = rest.map((entry: Expression.Any) => {
|
|
745
|
+
const entryAst = astOf(entry)
|
|
746
|
+
return entryAst.kind === "literal" && entryAst.value !== null ? valueKeyOfLiteral(entryAst.value) : undefined
|
|
747
|
+
})
|
|
748
|
+
return key !== undefined && literalValues.every((entry): entry is string => entry !== undefined)
|
|
749
|
+
? atomFormula<LiteralSetAtom<string, string>>({ kind: "literal-set", key, values: literalValues })
|
|
619
750
|
: anyFormula(rest.map((value: Expression.Any) => formulaOfEq(left, value)))
|
|
620
751
|
}
|
|
621
752
|
case "notIn": {
|