effect-qb 0.15.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.
- package/dist/mysql.js +362 -70
- package/dist/postgres/metadata.js +557 -27
- package/dist/postgres.js +5028 -4732
- package/package.json +2 -2
- package/src/internal/column-state.ts +7 -0
- package/src/internal/column.ts +22 -0
- package/src/internal/dialect.ts +12 -1
- package/src/internal/executor.ts +15 -4
- package/src/internal/predicate/analysis.ts +103 -1
- package/src/internal/predicate/atom.ts +7 -0
- package/src/internal/predicate/context.ts +156 -16
- package/src/internal/predicate/key.ts +46 -1
- package/src/internal/predicate/normalize.ts +115 -34
- package/src/internal/predicate/runtime.ts +118 -11
- package/src/internal/query.ts +328 -90
- package/src/internal/renderer.ts +4 -0
- package/src/internal/runtime/driver-value-mapping.ts +186 -0
- package/src/internal/scalar.ts +11 -0
- package/src/mysql/column.ts +1 -0
- package/src/mysql/executor.ts +20 -5
- package/src/mysql/internal/dialect.ts +12 -6
- package/src/mysql/internal/dsl.ts +268 -54
- package/src/mysql/internal/renderer.ts +11 -2
- package/src/mysql/internal/sql-expression-renderer.ts +54 -8
- package/src/mysql/renderer.ts +7 -2
- package/src/postgres/cast.ts +22 -7
- package/src/postgres/column.ts +1 -0
- package/src/postgres/executor.ts +20 -5
- package/src/postgres/internal/dialect.ts +12 -6
- package/src/postgres/internal/dsl.ts +285 -58
- package/src/postgres/internal/renderer.ts +11 -2
- package/src/postgres/internal/sql-expression-renderer.ts +60 -8
- package/src/postgres/renderer.ts +7 -2
- package/src/postgres/type.ts +4 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type * as Expression from "../scalar.js"
|
|
2
2
|
import type * as ExpressionAst from "../expression-ast.js"
|
|
3
|
+
import type * as JsonPath from "../json/path.js"
|
|
3
4
|
|
|
4
5
|
export type ColumnKey<
|
|
5
6
|
TableName extends string,
|
|
@@ -7,15 +8,59 @@ export type ColumnKey<
|
|
|
7
8
|
> = `${TableName}.${ColumnName}`
|
|
8
9
|
|
|
9
10
|
export type ColumnKeyOfAst<Ast extends ExpressionAst.Any> =
|
|
10
|
-
Ast extends ExpressionAst.ColumnNode<infer TableName extends string, infer ColumnName extends string>
|
|
11
|
+
[Ast] extends [ExpressionAst.ColumnNode<infer TableName extends string, infer ColumnName extends string>]
|
|
11
12
|
? ColumnKey<TableName, ColumnName>
|
|
12
13
|
: never
|
|
13
14
|
|
|
15
|
+
type JsonPathKey<
|
|
16
|
+
Segments extends ExpressionAst.JsonSegmentTuple,
|
|
17
|
+
Current extends string = never,
|
|
18
|
+
Seen extends readonly unknown[] = []
|
|
19
|
+
> = Seen["length"] extends 8
|
|
20
|
+
? never
|
|
21
|
+
: Segments extends readonly [
|
|
22
|
+
infer Segment,
|
|
23
|
+
...infer Tail extends ExpressionAst.JsonSegmentTuple
|
|
24
|
+
]
|
|
25
|
+
? Segment extends JsonPath.KeySegment<infer Key extends string>
|
|
26
|
+
? JsonPathKey<
|
|
27
|
+
Tail,
|
|
28
|
+
[Current] extends [never] ? Key : `${Current}.${Key}`,
|
|
29
|
+
readonly [...Seen, unknown]
|
|
30
|
+
>
|
|
31
|
+
: never
|
|
32
|
+
: Current
|
|
33
|
+
|
|
34
|
+
export type JsonPathPredicateKey<
|
|
35
|
+
Base extends Expression.Any,
|
|
36
|
+
Segments extends ExpressionAst.JsonSegmentTuple
|
|
37
|
+
> = [ColumnKeyOfExpression<Base>] extends [never]
|
|
38
|
+
? never
|
|
39
|
+
: [JsonPathKey<Segments>] extends [never]
|
|
40
|
+
? never
|
|
41
|
+
: `${ColumnKeyOfExpression<Base>}#json:${JsonPathKey<Segments>}`
|
|
42
|
+
|
|
43
|
+
export type PredicateKeyOfAst<Ast extends ExpressionAst.Any> =
|
|
44
|
+
[Ast] extends [ExpressionAst.ColumnNode<infer TableName extends string, infer ColumnName extends string>]
|
|
45
|
+
? ColumnKey<TableName, ColumnName>
|
|
46
|
+
: [Ast] extends [ExpressionAst.CastNode<infer Value extends Expression.Any, infer Target extends Expression.DbType.Any>]
|
|
47
|
+
? [Target] extends [Expression.DbTypeOf<Value>]
|
|
48
|
+
? [Expression.DbTypeOf<Value>] extends [Target]
|
|
49
|
+
? PredicateKeyOfExpression<Value>
|
|
50
|
+
: never
|
|
51
|
+
: never
|
|
52
|
+
: [Ast] extends [ExpressionAst.JsonAccessNode<infer Kind, infer Base extends Expression.Any, infer Segments extends ExpressionAst.JsonSegmentTuple>]
|
|
53
|
+
? Kind extends "jsonGetText" | "jsonPathText" | "jsonAccessText" | "jsonTraverseText"
|
|
54
|
+
? JsonPathPredicateKey<Base, Segments>
|
|
55
|
+
: never
|
|
56
|
+
: never
|
|
57
|
+
|
|
14
58
|
type AstOf<Value extends Expression.Any> = Value extends {
|
|
15
59
|
readonly [ExpressionAst.TypeId]: infer Ast extends ExpressionAst.Any
|
|
16
60
|
} ? Ast : never
|
|
17
61
|
|
|
18
62
|
export type ColumnKeyOfExpression<Value extends Expression.Any> = ColumnKeyOfAst<AstOf<Value>>
|
|
63
|
+
export type PredicateKeyOfExpression<Value extends Expression.Any> = PredicateKeyOfAst<AstOf<Value>>
|
|
19
64
|
|
|
20
65
|
export type LiteralKey<Value> =
|
|
21
66
|
Value extends string ? `string:${Value}` :
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type * as Expression from "../scalar.js"
|
|
2
2
|
import type * as ExpressionAst from "../expression-ast.js"
|
|
3
|
-
import type {
|
|
3
|
+
import type { PredicateKeyOfExpression, ValueKey } from "./key.js"
|
|
4
4
|
import type { AllFormula, AnyFormula, AtomFormula, FalseFormula, NotFormula, PredicateFormula, TrueFormula } from "./formula.js"
|
|
5
|
-
import type { EqColumnAtom, EqLiteralAtom, NeqLiteralAtom, NonNullAtom, NullAtom, UnknownAtom } from "./atom.js"
|
|
5
|
+
import type { EqColumnAtom, EqLiteralAtom, LiteralSetAtom, NeqLiteralAtom, NonNullAtom, NullAtom, UnknownAtom } from "./atom.js"
|
|
6
6
|
|
|
7
7
|
type AstOf<Value extends Expression.Any> = Value extends {
|
|
8
8
|
readonly [ExpressionAst.TypeId]: infer Ast extends ExpressionAst.Any
|
|
@@ -20,9 +20,9 @@ type AtomOf<Atom extends import("./atom.js").PredicateAtom> = AtomFormula<Atom>
|
|
|
20
20
|
type FactOf<Atom extends import("./atom.js").PredicateAtom> = AtomFormula<Atom>
|
|
21
21
|
|
|
22
22
|
type NonNullFactsOfExpression<Value extends Expression.Any> =
|
|
23
|
-
[
|
|
23
|
+
[PredicateKeyOfExpression<Value>] extends [never]
|
|
24
24
|
? never
|
|
25
|
-
: FactOf<NonNullAtom<
|
|
25
|
+
: FactOf<NonNullAtom<PredicateKeyOfExpression<Value>>>
|
|
26
26
|
|
|
27
27
|
type CombineFacts<
|
|
28
28
|
Left extends PredicateFormula,
|
|
@@ -45,8 +45,8 @@ type FormulaOfEq<
|
|
|
45
45
|
Left extends Expression.Any,
|
|
46
46
|
Right extends Expression.Any
|
|
47
47
|
> =
|
|
48
|
-
[
|
|
49
|
-
? [
|
|
48
|
+
[PredicateKeyOfExpression<Left>] extends [never]
|
|
49
|
+
? [PredicateKeyOfExpression<Right>] extends [never]
|
|
50
50
|
? LiteralValueOfExpression<Left> extends infer LeftLiteral
|
|
51
51
|
? LiteralValueOfExpression<Right> extends infer RightLiteral
|
|
52
52
|
? [LeftLiteral] extends [never]
|
|
@@ -67,24 +67,24 @@ type FormulaOfEq<
|
|
|
67
67
|
? UnknownTag<"eq:unsupported">
|
|
68
68
|
: LeftLiteral extends null
|
|
69
69
|
? False
|
|
70
|
-
: AtomOf<EqLiteralAtom<
|
|
70
|
+
: AtomOf<EqLiteralAtom<PredicateKeyOfExpression<Right>, ValueKey<LeftLiteral>>>
|
|
71
71
|
: UnknownTag<"eq:unsupported">
|
|
72
|
-
: [
|
|
72
|
+
: [PredicateKeyOfExpression<Right>] extends [never]
|
|
73
73
|
? LiteralValueOfExpression<Right> extends infer RightLiteral
|
|
74
74
|
? [RightLiteral] extends [never]
|
|
75
75
|
? UnknownTag<"eq:unsupported">
|
|
76
76
|
: RightLiteral extends null
|
|
77
77
|
? False
|
|
78
|
-
: AtomOf<EqLiteralAtom<
|
|
78
|
+
: AtomOf<EqLiteralAtom<PredicateKeyOfExpression<Left>, ValueKey<RightLiteral>>>
|
|
79
79
|
: UnknownTag<"eq:unsupported">
|
|
80
|
-
: AtomOf<import("./atom.js").EqColumnAtom<
|
|
80
|
+
: AtomOf<import("./atom.js").EqColumnAtom<PredicateKeyOfExpression<Left>, PredicateKeyOfExpression<Right>>>
|
|
81
81
|
|
|
82
82
|
type FormulaOfNeq<
|
|
83
83
|
Left extends Expression.Any,
|
|
84
84
|
Right extends Expression.Any
|
|
85
85
|
> =
|
|
86
|
-
[
|
|
87
|
-
? [
|
|
86
|
+
[PredicateKeyOfExpression<Left>] extends [never]
|
|
87
|
+
? [PredicateKeyOfExpression<Right>] extends [never]
|
|
88
88
|
? LiteralValueOfExpression<Left> extends infer LeftLiteral
|
|
89
89
|
? LiteralValueOfExpression<Right> extends infer RightLiteral
|
|
90
90
|
? [LeftLiteral] extends [never]
|
|
@@ -105,15 +105,15 @@ type FormulaOfNeq<
|
|
|
105
105
|
? UnknownTag<"neq:unsupported">
|
|
106
106
|
: LeftLiteral extends null
|
|
107
107
|
? False
|
|
108
|
-
: AtomOf<NeqLiteralAtom<
|
|
108
|
+
: AtomOf<NeqLiteralAtom<PredicateKeyOfExpression<Right>, ValueKey<LeftLiteral>>>
|
|
109
109
|
: UnknownTag<"neq:unsupported">
|
|
110
|
-
: [
|
|
110
|
+
: [PredicateKeyOfExpression<Right>] extends [never]
|
|
111
111
|
? LiteralValueOfExpression<Right> extends infer RightLiteral
|
|
112
112
|
? [RightLiteral] extends [never]
|
|
113
113
|
? UnknownTag<"neq:unsupported">
|
|
114
114
|
: RightLiteral extends null
|
|
115
115
|
? False
|
|
116
|
-
: AtomOf<NeqLiteralAtom<
|
|
116
|
+
: AtomOf<NeqLiteralAtom<PredicateKeyOfExpression<Left>, ValueKey<RightLiteral>>>
|
|
117
117
|
: UnknownTag<"neq:unsupported">
|
|
118
118
|
: CombineFacts<NonNullFactsOfExpression<Left>, NonNullFactsOfExpression<Right>>
|
|
119
119
|
|
|
@@ -127,23 +127,23 @@ type FormulaOfIsNotDistinctFrom<
|
|
|
127
127
|
? [RightLiteral] extends [never]
|
|
128
128
|
? UnknownTag<"isNotDistinctFrom:unsupported">
|
|
129
129
|
: RightLiteral extends null
|
|
130
|
-
? [
|
|
130
|
+
? [PredicateKeyOfExpression<Left>] extends [never]
|
|
131
131
|
? UnknownTag<"isNotDistinctFrom:unsupported">
|
|
132
|
-
: AtomOf<NullAtom<
|
|
132
|
+
: AtomOf<NullAtom<PredicateKeyOfExpression<Left>>>
|
|
133
133
|
: UnknownTag<"isNotDistinctFrom:unsupported">
|
|
134
134
|
: LeftLiteral extends null
|
|
135
|
-
? [
|
|
135
|
+
? [PredicateKeyOfExpression<Right>] extends [never]
|
|
136
136
|
? UnknownTag<"isNotDistinctFrom:unsupported">
|
|
137
|
-
: AtomOf<NullAtom<
|
|
137
|
+
: AtomOf<NullAtom<PredicateKeyOfExpression<Right>>>
|
|
138
138
|
: RightLiteral extends null
|
|
139
|
-
? [
|
|
139
|
+
? [PredicateKeyOfExpression<Left>] extends [never]
|
|
140
140
|
? UnknownTag<"isNotDistinctFrom:unsupported">
|
|
141
|
-
: AtomOf<NullAtom<
|
|
142
|
-
: [
|
|
143
|
-
? [
|
|
141
|
+
: AtomOf<NullAtom<PredicateKeyOfExpression<Left>>>
|
|
142
|
+
: [PredicateKeyOfExpression<Left>] extends [never]
|
|
143
|
+
? [PredicateKeyOfExpression<Right>] extends [never]
|
|
144
144
|
? CombineFacts<NonNullFactsOfExpression<Left>, NonNullFactsOfExpression<Right>>
|
|
145
|
-
: AtomOf<EqLiteralAtom<
|
|
146
|
-
: AtomOf<EqLiteralAtom<
|
|
145
|
+
: AtomOf<EqLiteralAtom<PredicateKeyOfExpression<Right>, ValueKey<LeftLiteral>>>
|
|
146
|
+
: AtomOf<EqLiteralAtom<PredicateKeyOfExpression<Left>, ValueKey<RightLiteral>>>
|
|
147
147
|
: UnknownTag<"isNotDistinctFrom:unsupported">
|
|
148
148
|
: UnknownTag<"isNotDistinctFrom:unsupported">
|
|
149
149
|
|
|
@@ -157,9 +157,12 @@ type AndFormulas<
|
|
|
157
157
|
|
|
158
158
|
type FormulaTupleOf<
|
|
159
159
|
Values extends readonly Expression.Any[]
|
|
160
|
-
> =
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
> = Values extends readonly [
|
|
161
|
+
infer Head extends Expression.Any,
|
|
162
|
+
...infer Tail extends readonly Expression.Any[]
|
|
163
|
+
]
|
|
164
|
+
? readonly [FormulaOfExpression<Head>, ...FormulaTupleOf<Tail>]
|
|
165
|
+
: readonly []
|
|
163
166
|
|
|
164
167
|
type AllFormulaOfValues<
|
|
165
168
|
Values extends readonly Expression.Any[]
|
|
@@ -167,7 +170,53 @@ type AllFormulaOfValues<
|
|
|
167
170
|
|
|
168
171
|
type AnyFormulaOfValues<
|
|
169
172
|
Values extends readonly Expression.Any[]
|
|
170
|
-
> =
|
|
173
|
+
> = FormulaTupleOf<Values> extends infer Formulas extends readonly PredicateFormula[]
|
|
174
|
+
? [CompactOrLiteralSet<Formulas>] extends [infer Compact extends PredicateFormula]
|
|
175
|
+
? [Compact] extends [never]
|
|
176
|
+
? import("./formula.js").NormalizeBooleanConstants<AnyFormula<Formulas>>
|
|
177
|
+
: Compact
|
|
178
|
+
: import("./formula.js").NormalizeBooleanConstants<AnyFormula<Formulas>>
|
|
179
|
+
: import("./formula.js").NormalizeBooleanConstants<AnyFormula<FormulaTupleOf<Values>>>
|
|
180
|
+
|
|
181
|
+
type LiteralSetDetails<Formula extends PredicateFormula> =
|
|
182
|
+
Formula extends AtomFormula<EqLiteralAtom<infer Key extends string, infer Value extends string>>
|
|
183
|
+
? readonly [Key, Value]
|
|
184
|
+
: Formula extends AtomFormula<LiteralSetAtom<infer Key extends string, infer Values extends string>>
|
|
185
|
+
? readonly [Key, Values]
|
|
186
|
+
: never
|
|
187
|
+
|
|
188
|
+
type IsUnion<Value, Candidate = Value> =
|
|
189
|
+
[Value] extends [never]
|
|
190
|
+
? false
|
|
191
|
+
: Value extends unknown
|
|
192
|
+
? [Candidate] extends [Value] ? false : true
|
|
193
|
+
: false
|
|
194
|
+
|
|
195
|
+
type CompactOrLiteralSet<
|
|
196
|
+
Items extends readonly PredicateFormula[],
|
|
197
|
+
Key extends string = never,
|
|
198
|
+
Values extends string = never,
|
|
199
|
+
Seen extends readonly unknown[] = []
|
|
200
|
+
> = Seen["length"] extends 20
|
|
201
|
+
? never
|
|
202
|
+
: Items extends readonly [
|
|
203
|
+
infer Head extends PredicateFormula,
|
|
204
|
+
...infer Tail extends readonly PredicateFormula[]
|
|
205
|
+
]
|
|
206
|
+
? LiteralSetDetails<Head> extends readonly [infer HeadKey extends string, infer HeadValues extends string]
|
|
207
|
+
? IsUnion<HeadKey> extends true
|
|
208
|
+
? never
|
|
209
|
+
: [Key] extends [never]
|
|
210
|
+
? CompactOrLiteralSet<Tail, HeadKey, HeadValues, readonly [...Seen, unknown]>
|
|
211
|
+
: [HeadKey] extends [Key]
|
|
212
|
+
? [Key] extends [HeadKey]
|
|
213
|
+
? CompactOrLiteralSet<Tail, Key, Values | HeadValues, readonly [...Seen, unknown]>
|
|
214
|
+
: never
|
|
215
|
+
: never
|
|
216
|
+
: never
|
|
217
|
+
: [Key] extends [never]
|
|
218
|
+
? never
|
|
219
|
+
: AtomOf<LiteralSetAtom<Key, Values>>
|
|
171
220
|
|
|
172
221
|
type FormulaOfInValues<
|
|
173
222
|
Left extends Expression.Any,
|
|
@@ -180,6 +229,38 @@ type FormulaOfInValues<
|
|
|
180
229
|
? FormulaOfInValues<Left, Tail, [...Current, FormulaOfEq<Left, Head>]>
|
|
181
230
|
: Current
|
|
182
231
|
|
|
232
|
+
type LiteralSetValuesOf<
|
|
233
|
+
Values extends readonly Expression.Any[],
|
|
234
|
+
Current extends string = never,
|
|
235
|
+
Seen extends readonly unknown[] = []
|
|
236
|
+
> = Seen["length"] extends 20
|
|
237
|
+
? string
|
|
238
|
+
: Values extends readonly [
|
|
239
|
+
infer Head extends Expression.Any,
|
|
240
|
+
...infer Tail extends readonly Expression.Any[]
|
|
241
|
+
]
|
|
242
|
+
? LiteralValueOfExpression<Head> extends infer Literal
|
|
243
|
+
? [Literal] extends [never]
|
|
244
|
+
? never
|
|
245
|
+
: Literal extends null
|
|
246
|
+
? never
|
|
247
|
+
: LiteralSetValuesOf<Tail, Current | ValueKey<Literal>, readonly [...Seen, unknown]>
|
|
248
|
+
: never
|
|
249
|
+
: Current
|
|
250
|
+
|
|
251
|
+
type FormulaOfIn<
|
|
252
|
+
Left extends Expression.Any,
|
|
253
|
+
Values extends readonly Expression.Any[]
|
|
254
|
+
> = [PredicateKeyOfExpression<Left>] extends [never]
|
|
255
|
+
? OrFormulas<FormulaOfInValues<Left, Values>>
|
|
256
|
+
: LiteralSetValuesOf<Values> extends infer ValueSet extends string
|
|
257
|
+
? [ValueSet] extends [never]
|
|
258
|
+
? OrFormulas<FormulaOfInValues<Left, Values>>
|
|
259
|
+
: string extends ValueSet
|
|
260
|
+
? CombineFacts<NonNullFactsOfExpression<Left>, UnknownTag<"in:literal-set-too-large">>
|
|
261
|
+
: AtomOf<LiteralSetAtom<PredicateKeyOfExpression<Left>, ValueSet>>
|
|
262
|
+
: OrFormulas<FormulaOfInValues<Left, Values>>
|
|
263
|
+
|
|
183
264
|
type FormulaOfNotInValues<
|
|
184
265
|
Left extends Expression.Any,
|
|
185
266
|
Values extends readonly Expression.Any[],
|
|
@@ -200,7 +281,7 @@ type FormulaOfVariadic<
|
|
|
200
281
|
? AnyFormulaOfValues<Values>
|
|
201
282
|
: Kind extends "in"
|
|
202
283
|
? Values extends readonly [infer Left extends Expression.Any, ...infer Tail extends readonly Expression.Any[]]
|
|
203
|
-
?
|
|
284
|
+
? FormulaOfIn<Left, Tail>
|
|
204
285
|
: False
|
|
205
286
|
: Kind extends "notIn"
|
|
206
287
|
? Values extends readonly [infer Left extends Expression.Any, ...infer Tail extends readonly Expression.Any[]]
|
|
@@ -218,13 +299,13 @@ type FormulaOfUnary<
|
|
|
218
299
|
Kind extends ExpressionAst.UnaryKind,
|
|
219
300
|
Inner extends Expression.Any
|
|
220
301
|
> = Kind extends "isNull"
|
|
221
|
-
? [
|
|
302
|
+
? [PredicateKeyOfExpression<Inner>] extends [never]
|
|
222
303
|
? UnknownTag<"isNull:unsupported">
|
|
223
|
-
: AtomOf<NullAtom<
|
|
304
|
+
: AtomOf<NullAtom<PredicateKeyOfExpression<Inner>>>
|
|
224
305
|
: Kind extends "isNotNull"
|
|
225
|
-
? [
|
|
306
|
+
? [PredicateKeyOfExpression<Inner>] extends [never]
|
|
226
307
|
? UnknownTag<"isNotNull:unsupported">
|
|
227
|
-
: AtomOf<NonNullAtom<
|
|
308
|
+
: AtomOf<NonNullAtom<PredicateKeyOfExpression<Inner>>>
|
|
228
309
|
: Kind extends "not"
|
|
229
310
|
? import("./formula.js").Not<FormulaOfExpression<Inner>>
|
|
230
311
|
: UnknownTag<`unary:${Kind}`>
|
|
@@ -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
|
|
@@ -123,7 +130,12 @@ const addEqLiteral = (context: MutableContext, key: string, value: string): void
|
|
|
123
130
|
if (neqValues?.has(value)) {
|
|
124
131
|
context.contradiction = true
|
|
125
132
|
}
|
|
133
|
+
const existingSet = context.literalSets.get(key)
|
|
134
|
+
if (existingSet !== undefined && !existingSet.has(value)) {
|
|
135
|
+
context.contradiction = true
|
|
136
|
+
}
|
|
126
137
|
context.eqLiterals.set(key, value)
|
|
138
|
+
context.literalSets.set(key, new Set([value]))
|
|
127
139
|
}
|
|
128
140
|
|
|
129
141
|
const addNeqLiteral = (context: MutableContext, key: string, value: string): void => {
|
|
@@ -136,6 +148,24 @@ const addNeqLiteral = (context: MutableContext, key: string, value: string): voi
|
|
|
136
148
|
context.neqLiterals.set(key, values)
|
|
137
149
|
}
|
|
138
150
|
|
|
151
|
+
const addLiteralSet = (context: MutableContext, key: string, values: ReadonlySet<string>): void => {
|
|
152
|
+
addNonNull(context, key)
|
|
153
|
+
const existingEq = context.eqLiterals.get(key)
|
|
154
|
+
if (existingEq !== undefined && !values.has(existingEq)) {
|
|
155
|
+
context.contradiction = true
|
|
156
|
+
}
|
|
157
|
+
const existing = context.literalSets.get(key)
|
|
158
|
+
context.literalSets.set(
|
|
159
|
+
key,
|
|
160
|
+
existing === undefined
|
|
161
|
+
? new Set(values)
|
|
162
|
+
: new Set(Array.from(existing).filter((value) => values.has(value)))
|
|
163
|
+
)
|
|
164
|
+
if (context.literalSets.get(key)?.size === 0) {
|
|
165
|
+
context.contradiction = true
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
139
169
|
const applyEqColumn = (context: MutableContext, left: string, right: string): void => {
|
|
140
170
|
const leftValue = context.eqLiterals.get(left)
|
|
141
171
|
const rightValue = context.eqLiterals.get(right)
|
|
@@ -176,6 +206,9 @@ const applyAtom = (context: MutableContext, atom: PredicateAtom): void => {
|
|
|
176
206
|
case "neq-literal":
|
|
177
207
|
addNeqLiteral(context, atom.key, atom.value)
|
|
178
208
|
return
|
|
209
|
+
case "literal-set":
|
|
210
|
+
addLiteralSet(context, atom.key, new Set(atom.values))
|
|
211
|
+
return
|
|
179
212
|
case "eq-column":
|
|
180
213
|
applyEqColumn(context, atom.left, atom.right)
|
|
181
214
|
return
|
|
@@ -199,6 +232,9 @@ const applyNegativeAtom = (context: MutableContext, atom: PredicateAtom): void =
|
|
|
199
232
|
case "neq-literal":
|
|
200
233
|
addEqLiteral(context, atom.key, atom.value)
|
|
201
234
|
return
|
|
235
|
+
case "literal-set":
|
|
236
|
+
addNonNull(context, atom.key)
|
|
237
|
+
return
|
|
202
238
|
case "eq-column":
|
|
203
239
|
addNonNull(context, atom.left)
|
|
204
240
|
addNonNull(context, atom.right)
|
|
@@ -240,6 +276,21 @@ const intersectNeqLiterals = (
|
|
|
240
276
|
return result
|
|
241
277
|
}
|
|
242
278
|
|
|
279
|
+
const unionLiteralSets = (
|
|
280
|
+
left: ReadonlyMap<string, ReadonlySet<string>>,
|
|
281
|
+
right: ReadonlyMap<string, ReadonlySet<string>>
|
|
282
|
+
): Map<string, Set<string>> => {
|
|
283
|
+
const result = new Map<string, Set<string>>()
|
|
284
|
+
for (const [key, leftValues] of left) {
|
|
285
|
+
const rightValues = right.get(key)
|
|
286
|
+
if (rightValues === undefined) {
|
|
287
|
+
continue
|
|
288
|
+
}
|
|
289
|
+
result.set(key, new Set([...leftValues, ...rightValues]))
|
|
290
|
+
}
|
|
291
|
+
return result
|
|
292
|
+
}
|
|
293
|
+
|
|
243
294
|
const intersectContexts = (left: MutableContext, right: MutableContext): MutableContext => {
|
|
244
295
|
if (left.contradiction) {
|
|
245
296
|
return cloneContext(right)
|
|
@@ -252,6 +303,7 @@ const intersectContexts = (left: MutableContext, right: MutableContext): Mutable
|
|
|
252
303
|
nullKeys: new Set(Array.from(left.nullKeys).filter((key) => right.nullKeys.has(key))),
|
|
253
304
|
eqLiterals: intersectEqLiterals(left.eqLiterals, right.eqLiterals),
|
|
254
305
|
neqLiterals: intersectNeqLiterals(left.neqLiterals, right.neqLiterals),
|
|
306
|
+
literalSets: unionLiteralSets(left.literalSets, right.literalSets),
|
|
255
307
|
sourceNames: new Set(Array.from(left.sourceNames).filter((name) => right.sourceNames.has(name))),
|
|
256
308
|
contradiction: false,
|
|
257
309
|
unknown: left.unknown || right.unknown
|
|
@@ -337,6 +389,53 @@ const columnKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
|
337
389
|
return ast.kind === "column" ? `${ast.tableName}.${ast.columnName}` : undefined
|
|
338
390
|
}
|
|
339
391
|
|
|
392
|
+
const sameDbType = (left: Expression.DbType.Any, right: Expression.DbType.Any): boolean =>
|
|
393
|
+
left.dialect === right.dialect && left.kind === right.kind
|
|
394
|
+
|
|
395
|
+
const jsonPathPredicateKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
396
|
+
const ast = astOf(value)
|
|
397
|
+
switch (ast.kind) {
|
|
398
|
+
case "jsonGetText":
|
|
399
|
+
case "jsonPathText":
|
|
400
|
+
case "jsonAccessText":
|
|
401
|
+
case "jsonTraverseText": {
|
|
402
|
+
const jsonAst = ast as ExpressionAst.JsonAccessNode
|
|
403
|
+
const segments = jsonAst.segments
|
|
404
|
+
if (segments.length === 0 || segments.length > 8) {
|
|
405
|
+
return undefined
|
|
406
|
+
}
|
|
407
|
+
const path: Array<string> = []
|
|
408
|
+
for (const segment of segments) {
|
|
409
|
+
if (typeof segment !== "object" || segment === null || segment.kind !== "key") {
|
|
410
|
+
return undefined
|
|
411
|
+
}
|
|
412
|
+
path.push(segment.key)
|
|
413
|
+
}
|
|
414
|
+
if (path.length === 0) {
|
|
415
|
+
return undefined
|
|
416
|
+
}
|
|
417
|
+
const baseKey = columnKeyOfExpression(jsonAst.base)
|
|
418
|
+
return baseKey === undefined ? undefined : `${baseKey}#json:${path.join(".")}`
|
|
419
|
+
}
|
|
420
|
+
default:
|
|
421
|
+
return undefined
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const predicateKeyOfExpression = (value: Expression.Any): string | undefined =>
|
|
426
|
+
columnKeyOfExpression(value) ?? castPredicateKeyOfExpression(value) ?? jsonPathPredicateKeyOfExpression(value)
|
|
427
|
+
|
|
428
|
+
const castPredicateKeyOfExpression = (value: Expression.Any): string | undefined => {
|
|
429
|
+
const ast = astOf(value)
|
|
430
|
+
if (ast.kind !== "cast") {
|
|
431
|
+
return undefined
|
|
432
|
+
}
|
|
433
|
+
const source = ast.value as Expression.Any
|
|
434
|
+
return sameDbType(source[Expression.TypeId].dbType, ast.target)
|
|
435
|
+
? predicateKeyOfExpression(source)
|
|
436
|
+
: undefined
|
|
437
|
+
}
|
|
438
|
+
|
|
340
439
|
const valueKeyOfLiteral = (value: unknown): string => {
|
|
341
440
|
if (typeof value === "string") {
|
|
342
441
|
return `string:${value}`
|
|
@@ -357,7 +456,7 @@ const valueKeyOfLiteral = (value: unknown): string => {
|
|
|
357
456
|
}
|
|
358
457
|
|
|
359
458
|
const nonNullFactsOfExpression = (value: Expression.Any): PredicateFormula | undefined => {
|
|
360
|
-
const key =
|
|
459
|
+
const key = predicateKeyOfExpression(value)
|
|
361
460
|
return key === undefined ? undefined : atomFormula<NonNullAtom<string>>({ kind: "is-not-null", key })
|
|
362
461
|
}
|
|
363
462
|
|
|
@@ -375,8 +474,8 @@ const combineFacts = (
|
|
|
375
474
|
}
|
|
376
475
|
|
|
377
476
|
const formulaOfEq = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
378
|
-
const leftKey =
|
|
379
|
-
const rightKey =
|
|
477
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
478
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
380
479
|
const leftAst = astOf(left)
|
|
381
480
|
const rightAst = astOf(right)
|
|
382
481
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -428,8 +527,8 @@ const formulaOfEq = (left: Expression.Any, right: Expression.Any): PredicateForm
|
|
|
428
527
|
}
|
|
429
528
|
|
|
430
529
|
const formulaOfNeq = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
431
|
-
const leftKey =
|
|
432
|
-
const rightKey =
|
|
530
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
531
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
433
532
|
const leftAst = astOf(left)
|
|
434
533
|
const rightAst = astOf(right)
|
|
435
534
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -477,8 +576,8 @@ const formulaOfNeq = (left: Expression.Any, right: Expression.Any): PredicateFor
|
|
|
477
576
|
}
|
|
478
577
|
|
|
479
578
|
const formulaOfIsNotDistinctFrom = (left: Expression.Any, right: Expression.Any): PredicateFormula => {
|
|
480
|
-
const leftKey =
|
|
481
|
-
const rightKey =
|
|
579
|
+
const leftKey = predicateKeyOfExpression(left)
|
|
580
|
+
const rightKey = predicateKeyOfExpression(right)
|
|
482
581
|
const leftAst = astOf(left)
|
|
483
582
|
const rightAst = astOf(right)
|
|
484
583
|
const leftLiteral = leftAst.kind === "literal" ? leftAst.value : undefined
|
|
@@ -587,13 +686,13 @@ export const formulaOfExpression = (value: Expression.Any): PredicateFormula =>
|
|
|
587
686
|
}
|
|
588
687
|
return unknownTag("literal:non-boolean")
|
|
589
688
|
case "isNull": {
|
|
590
|
-
const key =
|
|
689
|
+
const key = predicateKeyOfExpression(ast.value)
|
|
591
690
|
return key === undefined
|
|
592
691
|
? unknownTag("isNull:unsupported")
|
|
593
692
|
: atomFormula<NullAtom<string>>({ kind: "is-null", key })
|
|
594
693
|
}
|
|
595
694
|
case "isNotNull": {
|
|
596
|
-
const key =
|
|
695
|
+
const key = predicateKeyOfExpression(ast.value)
|
|
597
696
|
return key === undefined
|
|
598
697
|
? unknownTag("isNotNull:unsupported")
|
|
599
698
|
: atomFormula<NonNullAtom<string>>({ kind: "is-not-null", key })
|
|
@@ -614,8 +713,16 @@ export const formulaOfExpression = (value: Expression.Any): PredicateFormula =>
|
|
|
614
713
|
return anyFormula(ast.values.map((value: Expression.Any) => formulaOfExpression(value)))
|
|
615
714
|
case "in": {
|
|
616
715
|
const [left, ...rest] = ast.values
|
|
617
|
-
|
|
618
|
-
|
|
716
|
+
if (left === undefined) {
|
|
717
|
+
return falseFormula()
|
|
718
|
+
}
|
|
719
|
+
const key = predicateKeyOfExpression(left)
|
|
720
|
+
const literalValues = rest.map((entry: Expression.Any) => {
|
|
721
|
+
const entryAst = astOf(entry)
|
|
722
|
+
return entryAst.kind === "literal" && entryAst.value !== null ? valueKeyOfLiteral(entryAst.value) : undefined
|
|
723
|
+
})
|
|
724
|
+
return key !== undefined && literalValues.every((entry): entry is string => entry !== undefined)
|
|
725
|
+
? atomFormula<LiteralSetAtom<string, string>>({ kind: "literal-set", key, values: literalValues })
|
|
619
726
|
: anyFormula(rest.map((value: Expression.Any) => formulaOfEq(left, value)))
|
|
620
727
|
}
|
|
621
728
|
case "notIn": {
|