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,191 @@
|
|
|
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
|
+
|
|
6
|
+
export type {
|
|
7
|
+
BigIntString,
|
|
8
|
+
DecimalString,
|
|
9
|
+
InstantString,
|
|
10
|
+
JsonPrimitive,
|
|
11
|
+
JsonValue,
|
|
12
|
+
LocalDateString,
|
|
13
|
+
LocalDateTimeString,
|
|
14
|
+
LocalTimeString,
|
|
15
|
+
OffsetTimeString,
|
|
16
|
+
YearString
|
|
17
|
+
} from "./runtime/value.js"
|
|
18
|
+
|
|
19
|
+
/** Symbol used to attach expression metadata to runtime values. */
|
|
20
|
+
export const TypeId: unique symbol = Symbol.for("effect-qb/Expression")
|
|
21
|
+
|
|
22
|
+
export type TypeId = typeof TypeId
|
|
23
|
+
|
|
24
|
+
/** Scope-local binding identifier used for dependency tracking. */
|
|
25
|
+
export type BindingId = string
|
|
26
|
+
/**
|
|
27
|
+
* Three-state nullability lattice.
|
|
28
|
+
*
|
|
29
|
+
* `"never"` means non-null, `"maybe"` means nullable, and `"always"` means the
|
|
30
|
+
* expression is known to be `null`.
|
|
31
|
+
*/
|
|
32
|
+
export type Nullability = "never" | "maybe" | "always"
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* High-level classification of an expression.
|
|
36
|
+
*
|
|
37
|
+
* - `scalar`: regular per-row expression
|
|
38
|
+
* - `aggregate`: grouped expression such as `count(*)`
|
|
39
|
+
* - `window`: windowed expression such as `row_number() over (...)`
|
|
40
|
+
*/
|
|
41
|
+
export type ScalarKind = "scalar" | "aggregate" | "window"
|
|
42
|
+
|
|
43
|
+
/** Database-type descriptors carried alongside decoded runtime types. */
|
|
44
|
+
export declare namespace DbType {
|
|
45
|
+
/** Base SQL type descriptor. */
|
|
46
|
+
export interface Base<Dialect extends string, Kind extends string> {
|
|
47
|
+
readonly dialect: Dialect
|
|
48
|
+
readonly kind: Kind
|
|
49
|
+
readonly family?: string
|
|
50
|
+
readonly runtime?: RuntimeTag
|
|
51
|
+
readonly compareGroup?: string
|
|
52
|
+
readonly castTargets?: readonly string[]
|
|
53
|
+
readonly traits?: DatatypeTraits
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** JSON-like database type. */
|
|
57
|
+
export interface Json<
|
|
58
|
+
Dialect extends string = string,
|
|
59
|
+
SchemaName extends string = "json"
|
|
60
|
+
> extends Base<Dialect, SchemaName>
|
|
61
|
+
{
|
|
62
|
+
readonly variant: SchemaName extends "jsonb" ? "jsonb" : "json"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Array database type. */
|
|
66
|
+
export interface Array<
|
|
67
|
+
Dialect extends string = string,
|
|
68
|
+
Element extends Any = any,
|
|
69
|
+
Kind extends string = string
|
|
70
|
+
> extends Base<Dialect, Kind> {
|
|
71
|
+
readonly element: Element
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Range database type. */
|
|
75
|
+
export interface Range<
|
|
76
|
+
Dialect extends string = string,
|
|
77
|
+
Subtype extends Any = any,
|
|
78
|
+
Kind extends string = string
|
|
79
|
+
> extends Base<Dialect, Kind> {
|
|
80
|
+
readonly subtype: Subtype
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Multirange database type. */
|
|
84
|
+
export interface Multirange<
|
|
85
|
+
Dialect extends string = string,
|
|
86
|
+
Subtype extends Any = any,
|
|
87
|
+
Kind extends string = string
|
|
88
|
+
> extends Base<Dialect, Kind> {
|
|
89
|
+
readonly subtype: Subtype
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Composite/record database type. */
|
|
93
|
+
export interface Composite<
|
|
94
|
+
Dialect extends string = string,
|
|
95
|
+
Fields extends Record<string, Any> = Record<string, any>,
|
|
96
|
+
Kind extends string = string
|
|
97
|
+
> extends Base<Dialect, Kind> {
|
|
98
|
+
readonly fields: Fields
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Named domain database type. */
|
|
102
|
+
export interface Domain<
|
|
103
|
+
Dialect extends string = string,
|
|
104
|
+
BaseType extends Any = any,
|
|
105
|
+
Kind extends string = string
|
|
106
|
+
> extends Base<Dialect, Kind> {
|
|
107
|
+
readonly base: BaseType
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Enumeration database type. */
|
|
111
|
+
export interface Enum<
|
|
112
|
+
Dialect extends string = string,
|
|
113
|
+
Kind extends string = string
|
|
114
|
+
> extends Base<Dialect, Kind> {
|
|
115
|
+
readonly variant: "enum"
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Set database type. */
|
|
119
|
+
export interface Set<
|
|
120
|
+
Dialect extends string = string,
|
|
121
|
+
Kind extends string = string
|
|
122
|
+
> extends Base<Dialect, Kind> {
|
|
123
|
+
readonly variant: "set"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export type Any =
|
|
127
|
+
| Json
|
|
128
|
+
| Base<string, string>
|
|
129
|
+
| Array<string, any, string>
|
|
130
|
+
| Range<string, any, string>
|
|
131
|
+
| Multirange<string, any, string>
|
|
132
|
+
| Composite<string, Record<string, any>, string>
|
|
133
|
+
| Domain<string, any, string>
|
|
134
|
+
| Enum<string, string>
|
|
135
|
+
| Set<string, string>
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Canonical static metadata stored on an expression. */
|
|
139
|
+
export interface State<
|
|
140
|
+
Runtime,
|
|
141
|
+
Db extends DbType.Any,
|
|
142
|
+
Nullable extends Nullability,
|
|
143
|
+
Dialect extends string,
|
|
144
|
+
Kind extends ScalarKind,
|
|
145
|
+
Deps extends BindingId = never
|
|
146
|
+
> {
|
|
147
|
+
readonly runtime: Runtime
|
|
148
|
+
readonly dbType: Db
|
|
149
|
+
readonly runtimeSchema?: Schema.Schema.Any
|
|
150
|
+
readonly nullability: Nullable
|
|
151
|
+
readonly dialect: Dialect
|
|
152
|
+
readonly kind: Kind
|
|
153
|
+
readonly dependencies: Record<string, true>
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A typed scalar SQL expression.
|
|
158
|
+
*
|
|
159
|
+
* `Runtime` is the decoded TypeScript type while `Db` captures the SQL-level
|
|
160
|
+
* type identity. Both are needed: multiple SQL types may decode to the same
|
|
161
|
+
* runtime type but still have different comparison/cast semantics.
|
|
162
|
+
*/
|
|
163
|
+
export interface Scalar<
|
|
164
|
+
Runtime,
|
|
165
|
+
Db extends DbType.Any,
|
|
166
|
+
Nullable extends Nullability = "never",
|
|
167
|
+
Dialect extends string = Db["dialect"],
|
|
168
|
+
Kind extends ScalarKind = "scalar",
|
|
169
|
+
Deps extends BindingId = never,
|
|
170
|
+
GroupKey extends string = string
|
|
171
|
+
> extends Pipeable {
|
|
172
|
+
readonly [TypeId]: State<Runtime, Db, Nullable, Dialect, Kind, Deps>
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Convenience alias for any expression-like value. */
|
|
176
|
+
export type Any = Scalar<any, DbType.Any, Nullability, string, ScalarKind, BindingId, string>
|
|
177
|
+
/** Extracts an expression's decoded runtime type. */
|
|
178
|
+
export type RuntimeOf<Value extends Any> = Value[typeof TypeId]["runtime"]
|
|
179
|
+
/** Extracts an expression's database-type descriptor. */
|
|
180
|
+
export type DbTypeOf<Value extends Any> = Value[typeof TypeId]["dbType"]
|
|
181
|
+
/** Extracts an expression's nullability state. */
|
|
182
|
+
export type NullabilityOf<Value extends Any> = Value[typeof TypeId]["nullability"]
|
|
183
|
+
/** Extracts an expression's kind. */
|
|
184
|
+
export type KindOf<Value extends Any> = Value[typeof TypeId]["kind"]
|
|
185
|
+
/** Extracts an expression's source dependency union. */
|
|
186
|
+
export type DependenciesOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, infer Deps> ? Deps : never
|
|
187
|
+
/** Extracts an expression's grouping identity. */
|
|
188
|
+
export type GroupKeyOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, any, infer GroupKey> ? GroupKey : never
|
|
189
|
+
|
|
190
|
+
/** Maps a database type descriptor back to its decoded runtime type. */
|
|
191
|
+
export type RuntimeOfDbType<Db extends DbType.Any> = RuntimeOfDbTypeLookup<Db>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as VariantSchema from "@effect/experimental/VariantSchema";
|
|
2
|
+
import type * as Brand from "effect/Brand";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { type AnyColumnDefinition, type HasDefault, type InsertType, type IsGenerated, type IsNullable, type SelectType, type UpdateType } from "./column-state.js";
|
|
5
|
+
/** Variant-schema helper used to derive select / insert / update schemas. */
|
|
6
|
+
export declare const TableSchema: {
|
|
7
|
+
readonly Struct: <const A extends VariantSchema.Struct.Fields>(fields: A & VariantSchema.Struct.Validate<A, "insert" | "select" | "update">) => VariantSchema.Struct<A>;
|
|
8
|
+
readonly Field: <const A extends VariantSchema.Field.ConfigWithKeys<"insert" | "select" | "update">>(config: A & { readonly [K in Exclude<keyof A, "insert" | "select" | "update">]: never; }) => VariantSchema.Field<A>;
|
|
9
|
+
readonly FieldOnly: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Keys[number]]: S; }>;
|
|
10
|
+
readonly FieldExcept: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Exclude<"insert", Keys[number]> | Exclude<"select", Keys[number]> | Exclude<"update", Keys[number]>]: S; }>;
|
|
11
|
+
readonly fieldEvolve: {
|
|
12
|
+
<Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
|
|
13
|
+
readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
14
|
+
readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
15
|
+
readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
16
|
+
}>(f: Mapping): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping ? Mapping[K] extends (arg: any) => any ? ReturnType<Mapping[K]> : S_1[K] : S_1[K]; } : {
|
|
17
|
+
readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping ? Mapping[T] extends (arg: any) => any ? ReturnType<Mapping[T]> : Self : Self : never : never;
|
|
18
|
+
readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping ? Mapping[T_1] extends (arg: any) => any ? ReturnType<Mapping[T_1]> : Self : Self : never : never;
|
|
19
|
+
readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping ? Mapping[T_2] extends (arg: any) => any ? ReturnType<Mapping[T_2]> : Self : Self : never : never;
|
|
20
|
+
}>;
|
|
21
|
+
<Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_1 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
|
|
22
|
+
readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
23
|
+
readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
24
|
+
readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
|
|
25
|
+
}>(self: Self, f: Mapping_1): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_1 ? Mapping_1[K] extends (arg: any) => any ? ReturnType<Mapping_1[K]> : S_1[K] : S_1[K]; } : {
|
|
26
|
+
readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_1 ? Mapping_1[T] extends (arg: any) => any ? ReturnType<Mapping_1[T]> : Self : Self : never : never;
|
|
27
|
+
readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_1 ? Mapping_1[T_1] extends (arg: any) => any ? ReturnType<Mapping_1[T_1]> : Self : Self : never : never;
|
|
28
|
+
readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_1 ? Mapping_1[T_2] extends (arg: any) => any ? ReturnType<Mapping_1[T_2]> : Self : Self : never : never;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
readonly fieldFromKey: {
|
|
32
|
+
<Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_2 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
|
|
33
|
+
readonly insert?: string | undefined;
|
|
34
|
+
readonly select?: string | undefined;
|
|
35
|
+
readonly update?: string | undefined;
|
|
36
|
+
}>(mapping: Mapping_2): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_2 ? Mapping_2[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_2[K]> : S_1[K] : S_1[K]; } : {
|
|
37
|
+
readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_2 ? Mapping_2[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T]> : Self : Self : never : never;
|
|
38
|
+
readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_2 ? Mapping_2[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_1]> : Self : Self : never : never;
|
|
39
|
+
readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_2 ? Mapping_2[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_2]> : Self : Self : never : never;
|
|
40
|
+
}>;
|
|
41
|
+
<Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_3 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
|
|
42
|
+
readonly insert?: string | undefined;
|
|
43
|
+
readonly select?: string | undefined;
|
|
44
|
+
readonly update?: string | undefined;
|
|
45
|
+
}>(self: Self, mapping: Mapping_3): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_3 ? Mapping_3[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_3[K]> : S_1[K] : S_1[K]; } : {
|
|
46
|
+
readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_3 ? Mapping_3[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T]> : Self : Self : never : never;
|
|
47
|
+
readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_3 ? Mapping_3[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_1]> : Self : Self : never : never;
|
|
48
|
+
readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_3 ? Mapping_3[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_2]> : Self : Self : never : never;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
readonly Class: <Self = never>(identifier: string) => <const Fields extends VariantSchema.Struct.Fields>(fields: Fields & VariantSchema.Struct.Validate<Fields, "insert" | "select" | "update">, annotations?: Schema.Annotations.Schema<Self, readonly []> | undefined) => [Self] extends [never] ? "Missing `Self` generic - use `class Self extends Class<Self>()({ ... })`" : VariantSchema.Class<Self, Fields, VariantSchema.ExtractFields<"select", Fields, true>, Schema.Struct.Type<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Struct.Encoded<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Schema.Context<VariantSchema.ExtractFields<"select", Fields, true>[keyof VariantSchema.ExtractFields<"select", Fields, true>]>, Schema.Struct.Constructor<VariantSchema.ExtractFields<"select", Fields, true>>> & {
|
|
52
|
+
readonly insert: Schema.Struct<VariantSchema.ExtractFields<"insert", Fields, false> extends infer T ? { [K in keyof T]: T[K]; } : never>;
|
|
53
|
+
readonly select: Schema.Struct<VariantSchema.ExtractFields<"select", Fields, false> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
|
|
54
|
+
readonly update: Schema.Struct<VariantSchema.ExtractFields<"update", Fields, false> extends infer T_2 ? { [K in keyof T_2]: T_2[K]; } : never>;
|
|
55
|
+
};
|
|
56
|
+
readonly Union: <const Members extends readonly VariantSchema.Struct<any>[]>(...members: Members) => VariantSchema.Union<Members> & VariantSchema.Union.Variants<Members, "insert" | "select" | "update">;
|
|
57
|
+
readonly extract: {
|
|
58
|
+
<V extends "insert" | "select" | "update">(variant: V): <A extends VariantSchema.Struct<any>>(self: A) => VariantSchema.Extract<V, A, V extends "select" ? true : false>;
|
|
59
|
+
<V extends "insert" | "select" | "update", A extends VariantSchema.Struct<any>>(self: A, variant: V): VariantSchema.Extract<V, A, V extends "select" ? true : false>;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/** Normalized field map used by table definitions. */
|
|
63
|
+
export type TableFieldMap = Record<string, AnyColumnDefinition>;
|
|
64
|
+
type GeneratedKeys<Fields extends TableFieldMap> = {
|
|
65
|
+
[K in keyof Fields]: IsGenerated<Fields[K]> extends true ? K : never;
|
|
66
|
+
}[keyof Fields];
|
|
67
|
+
type OptionalInsertKeys<Fields extends TableFieldMap> = {
|
|
68
|
+
[K in keyof Fields]: IsGenerated<Fields[K]> extends true ? never : IsNullable<Fields[K]> extends true ? K : HasDefault<Fields[K]> extends true ? K : never;
|
|
69
|
+
}[keyof Fields];
|
|
70
|
+
type RequiredInsertKeys<Fields extends TableFieldMap> = Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>;
|
|
71
|
+
type UpdateKeys<Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Exclude<keyof Fields, GeneratedKeys<Fields> | PrimaryKey>;
|
|
72
|
+
type Simplify<T> = {
|
|
73
|
+
[K in keyof T]: T[K];
|
|
74
|
+
} & {};
|
|
75
|
+
type BrandedValue<Value, BrandName extends string> = [Extract<Value, null | undefined>] extends [never] ? Value & Brand.Brand<BrandName> : (Exclude<Value, null | undefined> & Brand.Brand<BrandName>) | Extract<Value, null | undefined>;
|
|
76
|
+
type BrandNameOf<TableName extends string, ColumnName extends string> = `${TableName}.${ColumnName}`;
|
|
77
|
+
type BrandedSelectType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<SelectType<Column>, BrandNameOf<TableName, ColumnName>> : SelectType<Column>;
|
|
78
|
+
type BrandedInsertType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<InsertType<Column>, BrandNameOf<TableName, ColumnName>> : InsertType<Column>;
|
|
79
|
+
type BrandedUpdateType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<UpdateType<Column>, BrandNameOf<TableName, ColumnName>> : UpdateType<Column>;
|
|
80
|
+
/** Row shape returned by selecting from a table. */
|
|
81
|
+
export type SelectRow<TableName extends string, Fields extends TableFieldMap> = Simplify<{
|
|
82
|
+
[K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>;
|
|
83
|
+
}>;
|
|
84
|
+
/** Insert payload derived from a table field map. */
|
|
85
|
+
export type InsertRow<TableName extends string, Fields extends TableFieldMap> = Simplify<{
|
|
86
|
+
[K in RequiredInsertKeys<Fields>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>;
|
|
87
|
+
} & {
|
|
88
|
+
[K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>>;
|
|
89
|
+
}>;
|
|
90
|
+
/** Update payload derived from a table field map and primary key. */
|
|
91
|
+
export type UpdateRow<TableName extends string, Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Simplify<Partial<{
|
|
92
|
+
[K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>;
|
|
93
|
+
}>>;
|
|
94
|
+
/**
|
|
95
|
+
* Derives the `select`, `insert`, and `update` schemas for a table.
|
|
96
|
+
*
|
|
97
|
+
* This is the central place where the column capability flags are turned into
|
|
98
|
+
* real runtime schemas.
|
|
99
|
+
*/
|
|
100
|
+
export declare const deriveSchemas: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => {
|
|
101
|
+
readonly select: Schema.Schema<{ [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, { [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, never>;
|
|
102
|
+
readonly insert: Schema.Schema<{ [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, { [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, never>;
|
|
103
|
+
readonly update: Schema.Schema<Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, never>;
|
|
104
|
+
};
|
|
105
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as VariantSchema from "@effect/experimental/VariantSchema"
|
|
2
|
+
import type * as Brand from "effect/Brand"
|
|
2
3
|
import * as Schema from "effect/Schema"
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -43,43 +44,112 @@ type UpdateKeys<Fields extends TableFieldMap, PrimaryKey extends keyof Fields> =
|
|
|
43
44
|
|
|
44
45
|
type Simplify<T> = { [K in keyof T]: T[K] } & {}
|
|
45
46
|
|
|
47
|
+
type BrandedValue<
|
|
48
|
+
Value,
|
|
49
|
+
BrandName extends string
|
|
50
|
+
> = [Extract<Value, null | undefined>] extends [never]
|
|
51
|
+
? Value & Brand.Brand<BrandName>
|
|
52
|
+
: Exclude<Value, null | undefined> & Brand.Brand<BrandName> | Extract<Value, null | undefined>
|
|
53
|
+
|
|
54
|
+
type BrandNameOf<
|
|
55
|
+
TableName extends string,
|
|
56
|
+
ColumnName extends string
|
|
57
|
+
> = `${TableName}.${ColumnName}`
|
|
58
|
+
|
|
59
|
+
type BrandedSelectType<
|
|
60
|
+
Column extends AnyColumnDefinition,
|
|
61
|
+
TableName extends string,
|
|
62
|
+
ColumnName extends string
|
|
63
|
+
> = Column["metadata"]["brand"] extends true
|
|
64
|
+
? BrandedValue<SelectType<Column>, BrandNameOf<TableName, ColumnName>>
|
|
65
|
+
: SelectType<Column>
|
|
66
|
+
|
|
67
|
+
type BrandedInsertType<
|
|
68
|
+
Column extends AnyColumnDefinition,
|
|
69
|
+
TableName extends string,
|
|
70
|
+
ColumnName extends string
|
|
71
|
+
> = Column["metadata"]["brand"] extends true
|
|
72
|
+
? BrandedValue<InsertType<Column>, BrandNameOf<TableName, ColumnName>>
|
|
73
|
+
: InsertType<Column>
|
|
74
|
+
|
|
75
|
+
type BrandedUpdateType<
|
|
76
|
+
Column extends AnyColumnDefinition,
|
|
77
|
+
TableName extends string,
|
|
78
|
+
ColumnName extends string
|
|
79
|
+
> = Column["metadata"]["brand"] extends true
|
|
80
|
+
? BrandedValue<UpdateType<Column>, BrandNameOf<TableName, ColumnName>>
|
|
81
|
+
: UpdateType<Column>
|
|
82
|
+
|
|
46
83
|
/** Row shape returned by selecting from a table. */
|
|
47
|
-
export type SelectRow<
|
|
48
|
-
|
|
84
|
+
export type SelectRow<
|
|
85
|
+
TableName extends string,
|
|
86
|
+
Fields extends TableFieldMap
|
|
87
|
+
> = Simplify<{
|
|
88
|
+
[K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>
|
|
49
89
|
}>
|
|
50
90
|
|
|
51
91
|
/** Insert payload derived from a table field map. */
|
|
52
|
-
export type InsertRow<
|
|
53
|
-
|
|
54
|
-
|
|
92
|
+
export type InsertRow<
|
|
93
|
+
TableName extends string,
|
|
94
|
+
Fields extends TableFieldMap
|
|
95
|
+
> = Simplify<
|
|
96
|
+
{ [K in RequiredInsertKeys<Fields>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>> } &
|
|
97
|
+
{ [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> }
|
|
55
98
|
>
|
|
56
99
|
|
|
57
100
|
/** Update payload derived from a table field map and primary key. */
|
|
58
|
-
export type UpdateRow<
|
|
101
|
+
export type UpdateRow<
|
|
102
|
+
TableName extends string,
|
|
103
|
+
Fields extends TableFieldMap,
|
|
104
|
+
PrimaryKey extends keyof Fields
|
|
105
|
+
> = Simplify<
|
|
59
106
|
Partial<{
|
|
60
|
-
[K in UpdateKeys<Fields, PrimaryKey>]:
|
|
107
|
+
[K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>
|
|
61
108
|
}>
|
|
62
109
|
>
|
|
63
110
|
|
|
64
|
-
const
|
|
65
|
-
column
|
|
111
|
+
const maybeBrandSchema = (
|
|
112
|
+
column: AnyColumnDefinition,
|
|
113
|
+
tableName: string,
|
|
114
|
+
columnName: string
|
|
115
|
+
): Schema.Schema.Any =>
|
|
116
|
+
column.metadata.brand === true
|
|
117
|
+
? Schema.brand(`${tableName}.${columnName}`)(column.schema)
|
|
118
|
+
: column.schema
|
|
119
|
+
|
|
120
|
+
const selectSchema = (
|
|
121
|
+
column: AnyColumnDefinition,
|
|
122
|
+
tableName: string,
|
|
123
|
+
columnName: string
|
|
124
|
+
): Schema.Schema.Any =>
|
|
125
|
+
column.metadata.nullable ? Schema.NullOr(maybeBrandSchema(column, tableName, columnName)) : maybeBrandSchema(column, tableName, columnName)
|
|
66
126
|
|
|
67
|
-
const insertSchema = (
|
|
127
|
+
const insertSchema = (
|
|
128
|
+
column: AnyColumnDefinition,
|
|
129
|
+
tableName: string,
|
|
130
|
+
columnName: string
|
|
131
|
+
): any | undefined => {
|
|
68
132
|
if (column.metadata.generated) {
|
|
69
133
|
return undefined
|
|
70
134
|
}
|
|
71
|
-
const base = column.metadata.nullable
|
|
135
|
+
const base = column.metadata.nullable
|
|
136
|
+
? Schema.NullOr(maybeBrandSchema(column, tableName, columnName))
|
|
137
|
+
: maybeBrandSchema(column, tableName, columnName)
|
|
72
138
|
return column.metadata.nullable || column.metadata.hasDefault ? Schema.optional(base) : base
|
|
73
139
|
}
|
|
74
140
|
|
|
75
141
|
const updateSchema = (
|
|
76
142
|
column: AnyColumnDefinition,
|
|
143
|
+
tableName: string,
|
|
144
|
+
columnName: string,
|
|
77
145
|
isPrimaryKey: boolean
|
|
78
146
|
): any | undefined => {
|
|
79
147
|
if (column.metadata.generated || isPrimaryKey) {
|
|
80
148
|
return undefined
|
|
81
149
|
}
|
|
82
|
-
const base = column.metadata.nullable
|
|
150
|
+
const base = column.metadata.nullable
|
|
151
|
+
? Schema.NullOr(maybeBrandSchema(column, tableName, columnName))
|
|
152
|
+
: maybeBrandSchema(column, tableName, columnName)
|
|
83
153
|
return Schema.optional(base)
|
|
84
154
|
}
|
|
85
155
|
|
|
@@ -90,26 +160,28 @@ const updateSchema = (
|
|
|
90
160
|
* real runtime schemas.
|
|
91
161
|
*/
|
|
92
162
|
export const deriveSchemas = <
|
|
163
|
+
TableName extends string,
|
|
93
164
|
Fields extends TableFieldMap,
|
|
94
165
|
PrimaryKeyColumns extends keyof Fields & string
|
|
95
166
|
>(
|
|
167
|
+
tableName: TableName,
|
|
96
168
|
fields: Fields,
|
|
97
169
|
primaryKeyColumns: readonly PrimaryKeyColumns[]
|
|
98
170
|
): {
|
|
99
|
-
readonly select: Schema.Schema<SelectRow<Fields>>
|
|
100
|
-
readonly insert: Schema.Schema<InsertRow<Fields>>
|
|
101
|
-
readonly update: Schema.Schema<UpdateRow<Fields, PrimaryKeyColumns>>
|
|
171
|
+
readonly select: Schema.Schema<SelectRow<TableName, Fields>>
|
|
172
|
+
readonly insert: Schema.Schema<InsertRow<TableName, Fields>>
|
|
173
|
+
readonly update: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
|
|
102
174
|
} => {
|
|
103
175
|
const primaryKeySet = new Set<string>(primaryKeyColumns)
|
|
104
176
|
const variants: Record<string, VariantSchema.Field<any>> = {}
|
|
105
177
|
for (const [key, column] of Object.entries(fields)) {
|
|
106
178
|
const config: Record<Variants, any> = {
|
|
107
|
-
select: selectSchema(column),
|
|
179
|
+
select: selectSchema(column, tableName, key),
|
|
108
180
|
insert: undefined,
|
|
109
181
|
update: undefined
|
|
110
182
|
}
|
|
111
|
-
const insert = insertSchema(column)
|
|
112
|
-
const update = updateSchema(column, primaryKeySet.has(key))
|
|
183
|
+
const insert = insertSchema(column, tableName, key)
|
|
184
|
+
const update = updateSchema(column, tableName, key, primaryKeySet.has(key))
|
|
113
185
|
if (insert !== undefined) {
|
|
114
186
|
config.insert = insert
|
|
115
187
|
} else {
|
|
@@ -124,8 +196,8 @@ export const deriveSchemas = <
|
|
|
124
196
|
}
|
|
125
197
|
const struct = TableSchema.Struct(variants as any)
|
|
126
198
|
return {
|
|
127
|
-
select: TableSchema.extract(struct, "select") as unknown as Schema.Schema<SelectRow<Fields>>,
|
|
128
|
-
insert: TableSchema.extract(struct, "insert") as unknown as Schema.Schema<InsertRow<Fields>>,
|
|
129
|
-
update: TableSchema.extract(struct, "update") as unknown as Schema.Schema<UpdateRow<Fields, PrimaryKeyColumns>>
|
|
199
|
+
select: TableSchema.extract(struct, "select") as unknown as Schema.Schema<SelectRow<TableName, Fields>>,
|
|
200
|
+
insert: TableSchema.extract(struct, "insert") as unknown as Schema.Schema<InsertRow<TableName, Fields>>,
|
|
201
|
+
update: TableSchema.extract(struct, "update") as unknown as Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
|
|
130
202
|
}
|
|
131
203
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Expr } from "pgsql-ast-parser";
|
|
2
|
+
import { type Pipeable } from "effect/Pipeable";
|
|
3
|
+
export declare const TypeId: unique symbol;
|
|
4
|
+
export type TypeId = typeof TypeId;
|
|
5
|
+
export interface SchemaExpression extends Pipeable {
|
|
6
|
+
readonly [TypeId]: {
|
|
7
|
+
readonly ast?: Expr;
|
|
8
|
+
readonly sql?: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export type Any = SchemaExpression;
|
|
12
|
+
export declare const isSchemaExpression: (value: unknown) => value is SchemaExpression;
|
|
13
|
+
export declare const fromAst: (ast: Expr) => SchemaExpression;
|
|
14
|
+
export declare const fromSql: (sql: string) => SchemaExpression;
|
|
15
|
+
export declare const parseExpression: (sql: string) => SchemaExpression;
|
|
16
|
+
export declare const toAst: (expression: SchemaExpression) => Expr;
|
|
17
|
+
export declare const render: (expression: SchemaExpression) => string;
|
|
18
|
+
export declare const normalize: (expression: SchemaExpression) => SchemaExpression;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { parse, toSql, type Expr } from "pgsql-ast-parser"
|
|
2
|
+
import { pipeArguments, type Pipeable } from "effect/Pipeable"
|
|
3
|
+
|
|
4
|
+
export const TypeId: unique symbol = Symbol.for("effect-qb/SchemaExpression")
|
|
5
|
+
|
|
6
|
+
export type TypeId = typeof TypeId
|
|
7
|
+
|
|
8
|
+
const SchemaExpressionProto = {
|
|
9
|
+
pipe(this: unknown) {
|
|
10
|
+
return pipeArguments(this, arguments)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const attachPipe = <Value extends object>(value: Value): Value => {
|
|
15
|
+
Object.defineProperty(value, "pipe", {
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: function(this: unknown) {
|
|
19
|
+
return pipeArguments(value, arguments)
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
return value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SchemaExpression extends Pipeable {
|
|
26
|
+
readonly [TypeId]: {
|
|
27
|
+
readonly ast?: Expr
|
|
28
|
+
readonly sql?: string
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type Any = SchemaExpression
|
|
33
|
+
|
|
34
|
+
export const isSchemaExpression = (value: unknown): value is SchemaExpression =>
|
|
35
|
+
typeof value === "object" && value !== null && TypeId in value
|
|
36
|
+
|
|
37
|
+
export const fromAst = (ast: Expr): SchemaExpression => {
|
|
38
|
+
const expression = attachPipe(Object.create(SchemaExpressionProto))
|
|
39
|
+
expression[TypeId] = {
|
|
40
|
+
ast
|
|
41
|
+
}
|
|
42
|
+
return expression
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const fromSql = (sql: string): SchemaExpression => {
|
|
46
|
+
const expression = attachPipe(Object.create(SchemaExpressionProto))
|
|
47
|
+
expression[TypeId] = {
|
|
48
|
+
sql: sql.trim()
|
|
49
|
+
}
|
|
50
|
+
return expression
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const parseExpression = (sql: string): SchemaExpression =>
|
|
54
|
+
fromAst(parse(sql, "expr"))
|
|
55
|
+
|
|
56
|
+
export const toAst = (expression: SchemaExpression): Expr => {
|
|
57
|
+
const ast = expression[TypeId].ast
|
|
58
|
+
if (ast !== undefined) {
|
|
59
|
+
return ast
|
|
60
|
+
}
|
|
61
|
+
return parse(render(expression), "expr")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const render = (expression: SchemaExpression): string =>
|
|
65
|
+
expression[TypeId].sql ?? toSql.expr(toAst(expression))
|
|
66
|
+
|
|
67
|
+
export const normalize = (expression: SchemaExpression): SchemaExpression =>
|
|
68
|
+
(() => {
|
|
69
|
+
const sql = render(expression)
|
|
70
|
+
try {
|
|
71
|
+
return parseExpression(sql)
|
|
72
|
+
} catch {
|
|
73
|
+
return fromSql(sql)
|
|
74
|
+
}
|
|
75
|
+
})()
|