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
package/src/internal/renderer.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as Query from "./query.js"
|
|
2
2
|
import { type Projection, validateProjections } from "./projections.js"
|
|
3
|
-
import { renderPostgresPlan } from "./postgres-renderer.js"
|
|
4
3
|
|
|
5
4
|
/** Symbol used to attach rendered-query phantom row metadata. */
|
|
6
5
|
export const TypeId: unique symbol = Symbol.for("effect-qb/Renderer")
|
|
@@ -41,12 +40,12 @@ export type RowOf<Value extends RenderedQuery<any, any>> = Value[typeof TypeId][
|
|
|
41
40
|
*/
|
|
42
41
|
export interface Renderer<Dialect extends string = string> {
|
|
43
42
|
readonly dialect: Dialect
|
|
44
|
-
render<PlanValue extends Query.
|
|
43
|
+
render<PlanValue extends Query.Plan.Any>(
|
|
45
44
|
plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
|
|
46
45
|
): RenderedQuery<any, Dialect>
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
type CustomRender<Dialect extends string> = <PlanValue extends Query.
|
|
48
|
+
type CustomRender<Dialect extends string> = <PlanValue extends Query.Plan.Any>(
|
|
50
49
|
plan: Query.DialectCompatiblePlan<PlanValue, Dialect>
|
|
51
50
|
) => {
|
|
52
51
|
readonly sql: string
|
|
@@ -55,33 +54,23 @@ type CustomRender<Dialect extends string> = <PlanValue extends Query.QueryPlan<a
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
/**
|
|
58
|
-
* Constructs a renderer from a dialect and
|
|
59
|
-
*
|
|
60
|
-
* When no callback is provided, the library supplies a built-in renderer for
|
|
61
|
-
* `"postgres"` that consumes the query AST directly and produces SQL text plus
|
|
62
|
-
* parameter values.
|
|
57
|
+
* Constructs a renderer from a dialect and implementation callback.
|
|
63
58
|
*/
|
|
64
|
-
export function make(dialect: "postgres"): Renderer<"postgres">
|
|
65
59
|
export function make<Dialect extends string>(
|
|
66
60
|
dialect: Dialect,
|
|
67
61
|
render: CustomRender<Dialect>
|
|
68
62
|
): Renderer<Dialect>
|
|
69
63
|
export function make<Dialect extends string>(
|
|
70
64
|
dialect: Dialect,
|
|
71
|
-
render
|
|
65
|
+
render: CustomRender<Dialect>
|
|
72
66
|
): Renderer<Dialect> {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
: undefined) as CustomRender<Dialect> | undefined)
|
|
76
|
-
|
|
77
|
-
if (!implementation) {
|
|
78
|
-
throw new Error(`No built-in renderer for dialect: ${dialect}`)
|
|
67
|
+
if (typeof render !== "function") {
|
|
68
|
+
throw new Error(`Renderer.make requires an explicit render implementation for dialect: ${dialect}`)
|
|
79
69
|
}
|
|
80
|
-
|
|
81
70
|
return {
|
|
82
71
|
dialect,
|
|
83
72
|
render(plan) {
|
|
84
|
-
const rendered =
|
|
73
|
+
const rendered = render(plan)
|
|
85
74
|
const projections = rendered.projections ?? []
|
|
86
75
|
validateProjections(projections)
|
|
87
76
|
return {
|
|
@@ -97,6 +86,3 @@ export function make<Dialect extends string>(
|
|
|
97
86
|
}
|
|
98
87
|
} as Renderer<Dialect>
|
|
99
88
|
}
|
|
100
|
-
|
|
101
|
-
/** Built-in Postgres renderer backed by the current query AST. */
|
|
102
|
-
export const postgres = make("postgres")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { Pipeable } from "effect/Pipeable";
|
|
2
|
+
import type { PredicateFormula } from "./predicate/formula.js";
|
|
3
|
+
/** Symbol used to attach logical-plan metadata to runtime values. */
|
|
4
|
+
export declare const TypeId: unique symbol;
|
|
5
|
+
export type TypeId = typeof TypeId;
|
|
6
|
+
/**
|
|
7
|
+
* Source availability mode within a query scope.
|
|
8
|
+
*
|
|
9
|
+
* `required` means the source is guaranteed to produce a row at this point in
|
|
10
|
+
* the plan. `optional` means the source may be absent, such as the nullable
|
|
11
|
+
* side of a left join.
|
|
12
|
+
*/
|
|
13
|
+
export type SourceMode = "required" | "optional";
|
|
14
|
+
/** Source made available to a plan. */
|
|
15
|
+
export interface Source<Name extends string = string, Mode extends SourceMode = SourceMode, PresentFormula extends PredicateFormula = PredicateFormula, PresenceWitness extends string = never> {
|
|
16
|
+
readonly name: Name;
|
|
17
|
+
readonly mode: Mode;
|
|
18
|
+
readonly baseName?: string;
|
|
19
|
+
readonly _presentFormula?: PresentFormula;
|
|
20
|
+
readonly _presenceWitnesses?: readonly PresenceWitness[];
|
|
21
|
+
}
|
|
22
|
+
export type AnySource = Source<string, SourceMode, PredicateFormula, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Canonical static metadata stored on a plan.
|
|
25
|
+
*
|
|
26
|
+
* `required` tracks sources that the selection references but which are not yet
|
|
27
|
+
* in scope. `available` tracks sources already in scope for subsequent query
|
|
28
|
+
* operations.
|
|
29
|
+
*/
|
|
30
|
+
export interface State<Columns, Required, Available extends Record<string, AnySource>, Dialect extends string> {
|
|
31
|
+
readonly selection: Columns;
|
|
32
|
+
readonly required: Required;
|
|
33
|
+
readonly available: Available;
|
|
34
|
+
readonly dialect: Dialect;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A composable logical row set.
|
|
38
|
+
*
|
|
39
|
+
* Tables implement this interface as already-complete plans. Future query
|
|
40
|
+
* builders such as `select()` and `from()` should produce and transform values
|
|
41
|
+
* with this same structure.
|
|
42
|
+
*/
|
|
43
|
+
export interface RowSet<Columns, Required = never, Available extends Record<string, AnySource> = {}, Dialect extends string = never> extends Pipeable {
|
|
44
|
+
readonly [TypeId]: State<Columns, Required, Available, Dialect>;
|
|
45
|
+
}
|
|
46
|
+
/** Convenience alias for any plan-like value. */
|
|
47
|
+
export type Any = RowSet<any, any, Record<string, AnySource>, string>;
|
|
48
|
+
/** Extracts a row set's columns shape. */
|
|
49
|
+
export type ColumnsOf<Value extends Any> = Value[typeof TypeId]["selection"];
|
|
50
|
+
/** Extracts a plan's selection shape. */
|
|
51
|
+
export type SelectionOf<Value extends Any> = ColumnsOf<Value>;
|
|
52
|
+
/** Extracts a plan's effective dialect. */
|
|
53
|
+
export type DialectOf<Value extends Any> = Value[typeof TypeId]["dialect"];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Pipeable } from "effect/Pipeable"
|
|
2
|
+
import type { PredicateFormula } from "./predicate/formula.js"
|
|
2
3
|
|
|
3
4
|
/** Symbol used to attach logical-plan metadata to runtime values. */
|
|
4
5
|
export const TypeId: unique symbol = Symbol.for("effect-qb/Plan")
|
|
@@ -15,12 +16,21 @@ export type TypeId = typeof TypeId
|
|
|
15
16
|
export type SourceMode = "required" | "optional"
|
|
16
17
|
|
|
17
18
|
/** Source made available to a plan. */
|
|
18
|
-
export interface Source<
|
|
19
|
+
export interface Source<
|
|
20
|
+
Name extends string = string,
|
|
21
|
+
Mode extends SourceMode = SourceMode,
|
|
22
|
+
PresentFormula extends PredicateFormula = PredicateFormula,
|
|
23
|
+
PresenceWitness extends string = never
|
|
24
|
+
> {
|
|
19
25
|
readonly name: Name
|
|
20
26
|
readonly mode: Mode
|
|
21
27
|
readonly baseName?: string
|
|
28
|
+
readonly _presentFormula?: PresentFormula
|
|
29
|
+
readonly _presenceWitnesses?: readonly PresenceWitness[]
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
export type AnySource = Source<string, SourceMode, PredicateFormula, string>
|
|
33
|
+
|
|
24
34
|
/**
|
|
25
35
|
* Canonical static metadata stored on a plan.
|
|
26
36
|
*
|
|
@@ -29,36 +39,38 @@ export interface Source<Name extends string = string, Mode extends SourceMode =
|
|
|
29
39
|
* operations.
|
|
30
40
|
*/
|
|
31
41
|
export interface State<
|
|
32
|
-
|
|
42
|
+
Columns,
|
|
33
43
|
Required,
|
|
34
|
-
Available extends Record<string,
|
|
44
|
+
Available extends Record<string, AnySource>,
|
|
35
45
|
Dialect extends string
|
|
36
46
|
> {
|
|
37
|
-
readonly selection:
|
|
47
|
+
readonly selection: Columns
|
|
38
48
|
readonly required: Required
|
|
39
49
|
readonly available: Available
|
|
40
50
|
readonly dialect: Dialect
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
/**
|
|
44
|
-
* A composable logical
|
|
54
|
+
* A composable logical row set.
|
|
45
55
|
*
|
|
46
56
|
* Tables implement this interface as already-complete plans. Future query
|
|
47
57
|
* builders such as `select()` and `from()` should produce and transform values
|
|
48
58
|
* with this same structure.
|
|
49
59
|
*/
|
|
50
|
-
export interface
|
|
51
|
-
|
|
60
|
+
export interface RowSet<
|
|
61
|
+
Columns,
|
|
52
62
|
Required = never,
|
|
53
|
-
Available extends Record<string,
|
|
63
|
+
Available extends Record<string, AnySource> = {},
|
|
54
64
|
Dialect extends string = never
|
|
55
65
|
> extends Pipeable {
|
|
56
|
-
readonly [TypeId]: State<
|
|
66
|
+
readonly [TypeId]: State<Columns, Required, Available, Dialect>
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
/** Convenience alias for any plan-like value. */
|
|
60
|
-
export type Any =
|
|
70
|
+
export type Any = RowSet<any, any, Record<string, AnySource>, string>
|
|
71
|
+
/** Extracts a row set's columns shape. */
|
|
72
|
+
export type ColumnsOf<Value extends Any> = Value[typeof TypeId]["selection"]
|
|
61
73
|
/** Extracts a plan's selection shape. */
|
|
62
|
-
export type SelectionOf<Value extends Any> = Value
|
|
74
|
+
export type SelectionOf<Value extends Any> = ColumnsOf<Value>
|
|
63
75
|
/** Extracts a plan's effective dialect. */
|
|
64
76
|
export type DialectOf<Value extends Any> = Value[typeof TypeId]["dialect"]
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
import type * as Expression from "
|
|
2
|
-
import {
|
|
3
|
-
import { postgresDatatypeKinds } from "../postgres/datatypes/spec.js"
|
|
4
|
-
import type { RuntimeTag } from "./datatypes/shape.js"
|
|
5
|
-
|
|
6
|
-
const stripParameterizedKind = (kind: string): string => {
|
|
7
|
-
const openParen = kind.indexOf("(")
|
|
8
|
-
return openParen === -1 ? kind : kind.slice(0, openParen)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const stripArrayKind = (kind: string): string => {
|
|
12
|
-
let current = kind
|
|
13
|
-
while (current.endsWith("[]")) {
|
|
14
|
-
current = current.slice(0, -2)
|
|
15
|
-
}
|
|
16
|
-
return current
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const baseKind = (kind: string): string => stripArrayKind(stripParameterizedKind(kind))
|
|
1
|
+
import type * as Expression from "../scalar.js"
|
|
2
|
+
import type { RuntimeTag } from "../datatypes/shape.js"
|
|
20
3
|
|
|
21
4
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
22
5
|
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
@@ -39,17 +22,9 @@ const formatLocalDateTime = (value: Date): string => {
|
|
|
39
22
|
}
|
|
40
23
|
|
|
41
24
|
const runtimeTagOfBaseDbType = (
|
|
42
|
-
|
|
43
|
-
kind: string
|
|
25
|
+
dbType: Expression.DbType.Base<string, string>
|
|
44
26
|
): RuntimeTag | undefined => {
|
|
45
|
-
|
|
46
|
-
if (dialect === "postgres") {
|
|
47
|
-
return postgresDatatypeKinds[normalizedKind as keyof typeof postgresDatatypeKinds]?.runtime
|
|
48
|
-
}
|
|
49
|
-
if (dialect === "mysql") {
|
|
50
|
-
return mysqlDatatypeKinds[normalizedKind as keyof typeof mysqlDatatypeKinds]?.runtime
|
|
51
|
-
}
|
|
52
|
-
return undefined
|
|
27
|
+
return dbType.runtime
|
|
53
28
|
}
|
|
54
29
|
|
|
55
30
|
const expectString = (value: unknown, label: string): string => {
|
|
@@ -225,7 +200,10 @@ const normalizeBytes = (value: unknown): Uint8Array => {
|
|
|
225
200
|
if (value instanceof Uint8Array) {
|
|
226
201
|
return new Uint8Array(value)
|
|
227
202
|
}
|
|
228
|
-
|
|
203
|
+
const BufferConstructor = (globalThis as {
|
|
204
|
+
readonly Buffer?: abstract new (...args: never[]) => Uint8Array
|
|
205
|
+
}).Buffer
|
|
206
|
+
if (BufferConstructor !== undefined && value instanceof BufferConstructor) {
|
|
229
207
|
return new Uint8Array(value)
|
|
230
208
|
}
|
|
231
209
|
throw new Error("Expected a byte array value")
|
|
@@ -298,7 +276,7 @@ export const normalizeDbValue = (
|
|
|
298
276
|
if ("variant" in dbType && (dbType.variant === "enum" || dbType.variant === "set")) {
|
|
299
277
|
return expectString(value, "text")
|
|
300
278
|
}
|
|
301
|
-
switch (runtimeTagOfBaseDbType(dbType
|
|
279
|
+
switch (runtimeTagOfBaseDbType(dbType)) {
|
|
302
280
|
case "string":
|
|
303
281
|
return expectString(value, "text")
|
|
304
282
|
case "number":
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import * as Schema from "effect/Schema"
|
|
2
2
|
import * as SchemaAST from "effect/SchemaAST"
|
|
3
3
|
|
|
4
|
-
import * as Expression from "
|
|
5
|
-
import * as ExpressionAst from "
|
|
6
|
-
import * as Query from "
|
|
7
|
-
import * as JsonPath from "
|
|
8
|
-
import {
|
|
4
|
+
import * as Expression from "../scalar.js"
|
|
5
|
+
import * as ExpressionAst from "../expression-ast.js"
|
|
6
|
+
import * as Query from "../query.js"
|
|
7
|
+
import * as JsonPath from "../json/path.js"
|
|
8
|
+
import type { PredicateFormula } from "../predicate/formula.js"
|
|
9
|
+
import {
|
|
10
|
+
assumeFormulaFalse,
|
|
11
|
+
assumeFormulaTrue,
|
|
12
|
+
contradictsFormula,
|
|
13
|
+
formulaOfExpression as formulaOfExpressionRuntime,
|
|
14
|
+
impliesFormula
|
|
15
|
+
} from "../predicate/runtime.js"
|
|
16
|
+
import { flattenSelection } from "../projections.js"
|
|
9
17
|
import {
|
|
10
18
|
BigIntStringSchema,
|
|
11
19
|
DecimalStringSchema,
|
|
@@ -16,29 +24,16 @@ import {
|
|
|
16
24
|
LocalTimeStringSchema,
|
|
17
25
|
OffsetTimeStringSchema,
|
|
18
26
|
YearStringSchema
|
|
19
|
-
} from "./
|
|
20
|
-
import {
|
|
21
|
-
import { postgresDatatypeKinds } from "../postgres/datatypes/spec.js"
|
|
22
|
-
import type { RuntimeTag } from "./datatypes/shape.js"
|
|
27
|
+
} from "./value.js"
|
|
28
|
+
import type { RuntimeTag } from "../datatypes/shape.js"
|
|
23
29
|
|
|
24
30
|
export type RuntimeSchema = Schema.Schema<any, any, any>
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const stripParameterizedKind = (kind: string): string => {
|
|
29
|
-
const openParen = kind.indexOf("(")
|
|
30
|
-
return openParen === -1 ? kind : kind.slice(0, openParen)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const stripArrayKind = (kind: string): string => {
|
|
34
|
-
let current = kind
|
|
35
|
-
while (current.endsWith("[]")) {
|
|
36
|
-
current = current.slice(0, -2)
|
|
37
|
-
}
|
|
38
|
-
return current
|
|
32
|
+
type SchemaContext = {
|
|
33
|
+
readonly assumptions: PredicateFormula
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
const
|
|
36
|
+
const schemaCache = new WeakMap<Expression.Any, RuntimeSchema | undefined>()
|
|
42
37
|
|
|
43
38
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
44
39
|
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
@@ -86,17 +81,9 @@ const runtimeSchemaForTag = (tag: RuntimeTag): RuntimeSchema | undefined => {
|
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
const runtimeTagOfBaseDbType = (
|
|
89
|
-
|
|
90
|
-
kind: string
|
|
84
|
+
dbType: Expression.DbType.Base<string, string>
|
|
91
85
|
): RuntimeTag | undefined => {
|
|
92
|
-
|
|
93
|
-
if (dialect === "postgres") {
|
|
94
|
-
return postgresDatatypeKinds[normalizedKind as keyof typeof postgresDatatypeKinds]?.runtime
|
|
95
|
-
}
|
|
96
|
-
if (dialect === "mysql") {
|
|
97
|
-
return mysqlDatatypeKinds[normalizedKind as keyof typeof mysqlDatatypeKinds]?.runtime
|
|
98
|
-
}
|
|
99
|
-
return undefined
|
|
86
|
+
return dbType.runtime
|
|
100
87
|
}
|
|
101
88
|
|
|
102
89
|
export const runtimeSchemaForDbType = (
|
|
@@ -120,7 +107,7 @@ export const runtimeSchemaForDbType = (
|
|
|
120
107
|
if ("variant" in dbType && (dbType.variant === "enum" || dbType.variant === "set")) {
|
|
121
108
|
return Schema.String
|
|
122
109
|
}
|
|
123
|
-
const runtimeTag = runtimeTagOfBaseDbType(dbType
|
|
110
|
+
const runtimeTag = runtimeTagOfBaseDbType(dbType)
|
|
124
111
|
return runtimeTag === undefined ? undefined : runtimeSchemaForTag(runtimeTag)
|
|
125
112
|
}
|
|
126
113
|
|
|
@@ -245,7 +232,7 @@ const unionSchemas = (schemas: ReadonlyArray<RuntimeSchema | undefined>): Runtim
|
|
|
245
232
|
}
|
|
246
233
|
|
|
247
234
|
const firstSelectedExpression = (
|
|
248
|
-
plan: Query.
|
|
235
|
+
plan: Query.Plan.Any
|
|
249
236
|
): Expression.Any | undefined => {
|
|
250
237
|
const selection = Query.getAst(plan).select
|
|
251
238
|
return flattenSelection(selection as Record<string, unknown>)[0]?.expression
|
|
@@ -284,18 +271,59 @@ const jsonCompatibleSchema = (schema: RuntimeSchema | undefined): RuntimeSchema
|
|
|
284
271
|
}
|
|
285
272
|
|
|
286
273
|
const buildStructSchema = (
|
|
287
|
-
entries: readonly { readonly key: string; readonly value: Expression.Any }[]
|
|
274
|
+
entries: readonly { readonly key: string; readonly value: Expression.Any }[],
|
|
275
|
+
context?: SchemaContext
|
|
288
276
|
): RuntimeSchema => {
|
|
289
277
|
const fields = Object.fromEntries(
|
|
290
|
-
entries.map((entry) => [entry.key, expressionRuntimeSchema(entry.value) ?? JsonValueSchema])
|
|
278
|
+
entries.map((entry) => [entry.key, expressionRuntimeSchema(entry.value, context) ?? JsonValueSchema])
|
|
291
279
|
)
|
|
292
280
|
return Schema.Struct(fields as Record<string, RuntimeSchema>)
|
|
293
281
|
}
|
|
294
282
|
|
|
295
|
-
const buildTupleSchema = (values: readonly Expression.Any[]): RuntimeSchema =>
|
|
296
|
-
Schema.Tuple(...values.map((value) => expressionRuntimeSchema(value) ?? JsonValueSchema))
|
|
283
|
+
const buildTupleSchema = (values: readonly Expression.Any[], context?: SchemaContext): RuntimeSchema =>
|
|
284
|
+
Schema.Tuple(...values.map((value) => expressionRuntimeSchema(value, context) ?? JsonValueSchema))
|
|
285
|
+
|
|
286
|
+
const deriveCaseSchema = (
|
|
287
|
+
ast: ExpressionAst.CaseNode,
|
|
288
|
+
context?: SchemaContext
|
|
289
|
+
): RuntimeSchema | undefined => {
|
|
290
|
+
if (context === undefined) {
|
|
291
|
+
return unionSchemas([
|
|
292
|
+
...ast.branches.map((branch) => expressionRuntimeSchema(branch.then)),
|
|
293
|
+
expressionRuntimeSchema(ast.else)
|
|
294
|
+
])
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const schemas: RuntimeSchema[] = []
|
|
298
|
+
let elseAssumptions = context.assumptions
|
|
297
299
|
|
|
298
|
-
const
|
|
300
|
+
for (const branch of ast.branches) {
|
|
301
|
+
const whenFormula = formulaOfExpressionRuntime(branch.when)
|
|
302
|
+
if (contradictsFormula(elseAssumptions, whenFormula)) {
|
|
303
|
+
continue
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const branchContext = { assumptions: assumeFormulaTrue(elseAssumptions, whenFormula) }
|
|
307
|
+
const branchSchema = expressionRuntimeSchema(branch.then, branchContext)
|
|
308
|
+
if (branchSchema !== undefined) {
|
|
309
|
+
schemas.push(branchSchema)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (impliesFormula(elseAssumptions, whenFormula)) {
|
|
313
|
+
return unionSchemas(schemas)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
elseAssumptions = assumeFormulaFalse(elseAssumptions, whenFormula)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const elseSchema = expressionRuntimeSchema(ast.else, { assumptions: elseAssumptions })
|
|
320
|
+
return unionSchemas(elseSchema === undefined ? schemas : [...schemas, elseSchema])
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const deriveRuntimeSchema = (
|
|
324
|
+
expression: Expression.Any,
|
|
325
|
+
context?: SchemaContext
|
|
326
|
+
): RuntimeSchema | undefined => {
|
|
299
327
|
const state = expression[Expression.TypeId]
|
|
300
328
|
if (state.runtimeSchema !== undefined) {
|
|
301
329
|
return state.runtimeSchema
|
|
@@ -363,28 +391,25 @@ const deriveRuntimeSchema = (expression: Expression.Any): RuntimeSchema | undefi
|
|
|
363
391
|
return Schema.Number
|
|
364
392
|
case "max":
|
|
365
393
|
case "min":
|
|
366
|
-
return expressionRuntimeSchema(ast.value)
|
|
394
|
+
return expressionRuntimeSchema(ast.value, context)
|
|
367
395
|
case "case":
|
|
368
|
-
return
|
|
369
|
-
...ast.branches.map((branch) => expressionRuntimeSchema(branch.then)),
|
|
370
|
-
expressionRuntimeSchema(ast.else)
|
|
371
|
-
])
|
|
396
|
+
return deriveCaseSchema(ast, context)
|
|
372
397
|
case "coalesce":
|
|
373
|
-
return unionSchemas(ast.values.map(expressionRuntimeSchema))
|
|
398
|
+
return unionSchemas(ast.values.map((value) => expressionRuntimeSchema(value, context)))
|
|
374
399
|
case "scalarSubquery":
|
|
375
400
|
{
|
|
376
401
|
const selection = firstSelectedExpression(ast.plan)
|
|
377
|
-
return selection === undefined ? undefined : expressionRuntimeSchema(selection)
|
|
402
|
+
return selection === undefined ? undefined : expressionRuntimeSchema(selection, context)
|
|
378
403
|
}
|
|
379
404
|
case "window":
|
|
380
405
|
return ast.function === "over" && ast.value !== undefined
|
|
381
|
-
? expressionRuntimeSchema(ast.value)
|
|
406
|
+
? expressionRuntimeSchema(ast.value, context)
|
|
382
407
|
: Schema.Number
|
|
383
408
|
case "jsonGet":
|
|
384
409
|
case "jsonPath":
|
|
385
410
|
case "jsonAccess":
|
|
386
411
|
case "jsonTraverse": {
|
|
387
|
-
const baseSchema = expressionRuntimeSchema(ast.base
|
|
412
|
+
const baseSchema = expressionRuntimeSchema(ast.base!, context)
|
|
388
413
|
const segments = ast.segments
|
|
389
414
|
if (baseSchema === undefined || segments === undefined || !exactJsonSegments(segments)) {
|
|
390
415
|
return JsonValueSchema
|
|
@@ -397,27 +422,31 @@ const deriveRuntimeSchema = (expression: Expression.Any): RuntimeSchema | undefi
|
|
|
397
422
|
case "jsonRemove":
|
|
398
423
|
case "jsonSet":
|
|
399
424
|
case "jsonInsert":
|
|
400
|
-
return expressionRuntimeSchema(ast.base
|
|
425
|
+
return expressionRuntimeSchema(ast.base!, context)
|
|
401
426
|
case "jsonStripNulls":
|
|
402
|
-
return expressionRuntimeSchema(ast.value
|
|
427
|
+
return expressionRuntimeSchema(ast.value!, context)
|
|
403
428
|
case "jsonConcat":
|
|
404
429
|
case "jsonMerge":
|
|
405
430
|
return JsonValueSchema
|
|
406
431
|
case "jsonBuildObject":
|
|
407
|
-
return buildStructSchema(ast.entries ?? [])
|
|
432
|
+
return buildStructSchema(ast.entries ?? [], context)
|
|
408
433
|
case "jsonBuildArray":
|
|
409
|
-
return buildTupleSchema(ast.values ?? [])
|
|
434
|
+
return buildTupleSchema(ast.values ?? [], context)
|
|
410
435
|
case "jsonToJson":
|
|
411
436
|
case "jsonToJsonb":
|
|
412
|
-
return jsonCompatibleSchema(expressionRuntimeSchema(ast.value
|
|
437
|
+
return jsonCompatibleSchema(expressionRuntimeSchema(ast.value!, context))
|
|
413
438
|
case "jsonKeys":
|
|
414
439
|
return Schema.Array(Schema.String)
|
|
415
440
|
}
|
|
416
441
|
}
|
|
417
442
|
|
|
418
443
|
export const expressionRuntimeSchema = (
|
|
419
|
-
expression: Expression.Any
|
|
444
|
+
expression: Expression.Any,
|
|
445
|
+
context?: SchemaContext
|
|
420
446
|
): RuntimeSchema | undefined => {
|
|
447
|
+
if (context !== undefined) {
|
|
448
|
+
return deriveRuntimeSchema(expression, context) ?? runtimeSchemaForDbType(expression[Expression.TypeId].dbType)
|
|
449
|
+
}
|
|
421
450
|
const cached = schemaCache.get(expression)
|
|
422
451
|
if (cached !== undefined || schemaCache.has(expression)) {
|
|
423
452
|
return cached
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as Brand from "effect/Brand";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import type { JsonPrimitive, JsonValue } from "../json/types.js";
|
|
4
|
+
export type { JsonPrimitive, JsonValue } from "../json/types.js";
|
|
5
|
+
export type LocalDateString = string & Brand.Brand<"LocalDateString">;
|
|
6
|
+
export type LocalTimeString = string & Brand.Brand<"LocalTimeString">;
|
|
7
|
+
export type OffsetTimeString = string & Brand.Brand<"OffsetTimeString">;
|
|
8
|
+
export type LocalDateTimeString = string & Brand.Brand<"LocalDateTimeString">;
|
|
9
|
+
export type InstantString = string & Brand.Brand<"InstantString">;
|
|
10
|
+
export type YearString = string & Brand.Brand<"YearString">;
|
|
11
|
+
export type BigIntString = string & Brand.Brand<"BigIntString">;
|
|
12
|
+
export type DecimalString = string & Brand.Brand<"DecimalString">;
|
|
13
|
+
export declare const LocalDateStringSchema: Schema.Schema<string & Brand.Brand<"LocalDateString">, string & Brand.Brand<"LocalDateString">, never>;
|
|
14
|
+
export declare const LocalTimeStringSchema: Schema.Schema<string & Brand.Brand<"LocalTimeString">, string & Brand.Brand<"LocalTimeString">, never>;
|
|
15
|
+
export declare const OffsetTimeStringSchema: Schema.Schema<string & Brand.Brand<"OffsetTimeString">, string & Brand.Brand<"OffsetTimeString">, never>;
|
|
16
|
+
export declare const LocalDateTimeStringSchema: Schema.Schema<string & Brand.Brand<"LocalDateTimeString">, string & Brand.Brand<"LocalDateTimeString">, never>;
|
|
17
|
+
export declare const InstantStringSchema: Schema.Schema<string & Brand.Brand<"InstantString">, string & Brand.Brand<"InstantString">, never>;
|
|
18
|
+
export declare const YearStringSchema: Schema.Schema<string & Brand.Brand<"YearString">, string & Brand.Brand<"YearString">, never>;
|
|
19
|
+
export declare const BigIntStringSchema: Schema.Schema<string & Brand.Brand<"BigIntString">, string & Brand.Brand<"BigIntString">, never>;
|
|
20
|
+
export declare const DecimalStringSchema: Schema.Schema<string & Brand.Brand<"DecimalString">, string & Brand.Brand<"DecimalString">, never>;
|
|
21
|
+
export declare const JsonValueSchema: Schema.Schema<JsonValue>;
|
|
22
|
+
export declare const JsonPrimitiveSchema: Schema.Schema<JsonPrimitive>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type * as Brand from "effect/Brand"
|
|
2
2
|
import * as Schema from "effect/Schema"
|
|
3
3
|
|
|
4
|
-
import type { JsonPrimitive, JsonValue } from "
|
|
4
|
+
import type { JsonPrimitive, JsonValue } from "../json/types.js"
|
|
5
5
|
|
|
6
|
-
export type { JsonPrimitive, JsonValue } from "
|
|
6
|
+
export type { JsonPrimitive, JsonValue } from "../json/types.js"
|
|
7
7
|
|
|
8
8
|
export type LocalDateString = string & Brand.Brand<"LocalDateString">
|
|
9
9
|
export type LocalTimeString = string & Brand.Brand<"LocalTimeString">
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Pipeable } from "effect/Pipeable";
|
|
2
|
+
import type * as Schema from "effect/Schema";
|
|
3
|
+
import type { RuntimeOfDbType as RuntimeOfDbTypeLookup } from "./datatypes/lookup.js";
|
|
4
|
+
import type { DatatypeTraits, RuntimeTag } from "./datatypes/shape.js";
|
|
5
|
+
export type { BigIntString, DecimalString, InstantString, JsonPrimitive, JsonValue, LocalDateString, LocalDateTimeString, LocalTimeString, OffsetTimeString, YearString } from "./runtime/value.js";
|
|
6
|
+
/** Symbol used to attach expression metadata to runtime values. */
|
|
7
|
+
export declare const TypeId: unique symbol;
|
|
8
|
+
export type TypeId = typeof TypeId;
|
|
9
|
+
/** Scope-local binding identifier used for dependency tracking. */
|
|
10
|
+
export type BindingId = string;
|
|
11
|
+
/**
|
|
12
|
+
* Three-state nullability lattice.
|
|
13
|
+
*
|
|
14
|
+
* `"never"` means non-null, `"maybe"` means nullable, and `"always"` means the
|
|
15
|
+
* expression is known to be `null`.
|
|
16
|
+
*/
|
|
17
|
+
export type Nullability = "never" | "maybe" | "always";
|
|
18
|
+
/**
|
|
19
|
+
* High-level classification of an expression.
|
|
20
|
+
*
|
|
21
|
+
* - `scalar`: regular per-row expression
|
|
22
|
+
* - `aggregate`: grouped expression such as `count(*)`
|
|
23
|
+
* - `window`: windowed expression such as `row_number() over (...)`
|
|
24
|
+
*/
|
|
25
|
+
export type ScalarKind = "scalar" | "aggregate" | "window";
|
|
26
|
+
/** Database-type descriptors carried alongside decoded runtime types. */
|
|
27
|
+
export declare namespace DbType {
|
|
28
|
+
/** Base SQL type descriptor. */
|
|
29
|
+
interface Base<Dialect extends string, Kind extends string> {
|
|
30
|
+
readonly dialect: Dialect;
|
|
31
|
+
readonly kind: Kind;
|
|
32
|
+
readonly family?: string;
|
|
33
|
+
readonly runtime?: RuntimeTag;
|
|
34
|
+
readonly compareGroup?: string;
|
|
35
|
+
readonly castTargets?: readonly string[];
|
|
36
|
+
readonly traits?: DatatypeTraits;
|
|
37
|
+
}
|
|
38
|
+
/** JSON-like database type. */
|
|
39
|
+
interface Json<Dialect extends string = string, SchemaName extends string = "json"> extends Base<Dialect, SchemaName> {
|
|
40
|
+
readonly variant: SchemaName extends "jsonb" ? "jsonb" : "json";
|
|
41
|
+
}
|
|
42
|
+
/** Array database type. */
|
|
43
|
+
interface Array<Dialect extends string = string, Element extends Any = any, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
44
|
+
readonly element: Element;
|
|
45
|
+
}
|
|
46
|
+
/** Range database type. */
|
|
47
|
+
interface Range<Dialect extends string = string, Subtype extends Any = any, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
48
|
+
readonly subtype: Subtype;
|
|
49
|
+
}
|
|
50
|
+
/** Multirange database type. */
|
|
51
|
+
interface Multirange<Dialect extends string = string, Subtype extends Any = any, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
52
|
+
readonly subtype: Subtype;
|
|
53
|
+
}
|
|
54
|
+
/** Composite/record database type. */
|
|
55
|
+
interface Composite<Dialect extends string = string, Fields extends Record<string, Any> = Record<string, any>, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
56
|
+
readonly fields: Fields;
|
|
57
|
+
}
|
|
58
|
+
/** Named domain database type. */
|
|
59
|
+
interface Domain<Dialect extends string = string, BaseType extends Any = any, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
60
|
+
readonly base: BaseType;
|
|
61
|
+
}
|
|
62
|
+
/** Enumeration database type. */
|
|
63
|
+
interface Enum<Dialect extends string = string, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
64
|
+
readonly variant: "enum";
|
|
65
|
+
}
|
|
66
|
+
/** Set database type. */
|
|
67
|
+
interface Set<Dialect extends string = string, Kind extends string = string> extends Base<Dialect, Kind> {
|
|
68
|
+
readonly variant: "set";
|
|
69
|
+
}
|
|
70
|
+
type Any = Json | Base<string, string> | Array<string, any, string> | Range<string, any, string> | Multirange<string, any, string> | Composite<string, Record<string, any>, string> | Domain<string, any, string> | Enum<string, string> | Set<string, string>;
|
|
71
|
+
}
|
|
72
|
+
/** Canonical static metadata stored on an expression. */
|
|
73
|
+
export interface State<Runtime, Db extends DbType.Any, Nullable extends Nullability, Dialect extends string, Kind extends ScalarKind, Deps extends BindingId = never> {
|
|
74
|
+
readonly runtime: Runtime;
|
|
75
|
+
readonly dbType: Db;
|
|
76
|
+
readonly runtimeSchema?: Schema.Schema.Any;
|
|
77
|
+
readonly nullability: Nullable;
|
|
78
|
+
readonly dialect: Dialect;
|
|
79
|
+
readonly kind: Kind;
|
|
80
|
+
readonly dependencies: Record<string, true>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A typed scalar SQL expression.
|
|
84
|
+
*
|
|
85
|
+
* `Runtime` is the decoded TypeScript type while `Db` captures the SQL-level
|
|
86
|
+
* type identity. Both are needed: multiple SQL types may decode to the same
|
|
87
|
+
* runtime type but still have different comparison/cast semantics.
|
|
88
|
+
*/
|
|
89
|
+
export interface Scalar<Runtime, Db extends DbType.Any, Nullable extends Nullability = "never", Dialect extends string = Db["dialect"], Kind extends ScalarKind = "scalar", Deps extends BindingId = never, GroupKey extends string = string> extends Pipeable {
|
|
90
|
+
readonly [TypeId]: State<Runtime, Db, Nullable, Dialect, Kind, Deps>;
|
|
91
|
+
}
|
|
92
|
+
/** Convenience alias for any expression-like value. */
|
|
93
|
+
export type Any = Scalar<any, DbType.Any, Nullability, string, ScalarKind, BindingId, string>;
|
|
94
|
+
/** Extracts an expression's decoded runtime type. */
|
|
95
|
+
export type RuntimeOf<Value extends Any> = Value[typeof TypeId]["runtime"];
|
|
96
|
+
/** Extracts an expression's database-type descriptor. */
|
|
97
|
+
export type DbTypeOf<Value extends Any> = Value[typeof TypeId]["dbType"];
|
|
98
|
+
/** Extracts an expression's nullability state. */
|
|
99
|
+
export type NullabilityOf<Value extends Any> = Value[typeof TypeId]["nullability"];
|
|
100
|
+
/** Extracts an expression's kind. */
|
|
101
|
+
export type KindOf<Value extends Any> = Value[typeof TypeId]["kind"];
|
|
102
|
+
/** Extracts an expression's source dependency union. */
|
|
103
|
+
export type DependenciesOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, infer Deps> ? Deps : never;
|
|
104
|
+
/** Extracts an expression's grouping identity. */
|
|
105
|
+
export type GroupKeyOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, any, infer GroupKey> ? GroupKey : never;
|
|
106
|
+
/** Maps a database type descriptor back to its decoded runtime type. */
|
|
107
|
+
export type RuntimeOfDbType<Db extends DbType.Any> = RuntimeOfDbTypeLookup<Db>;
|