effect-qb 0.14.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 +61555 -4252
- package/dist/postgres/metadata.js +728 -104
- package/dist/postgres.js +6906 -4023
- package/package.json +15 -2
- 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 +43 -47
- package/src/internal/column.ts +43 -305
- package/src/internal/datatypes/define.d.ts +17 -0
- package/src/internal/datatypes/define.ts +18 -4
- 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/dialect.ts +12 -1
- 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 +146 -34
- package/src/internal/expression-ast.ts +15 -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 +4 -4
- 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 +183 -0
- package/src/internal/predicate/atom.d.ts +28 -0
- package/src/internal/{predicate-atom.ts → predicate/atom.ts} +7 -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} +163 -20
- package/src/internal/predicate/formula.d.ts +35 -0
- package/src/internal/{predicate-formula.ts → predicate/formula.ts} +1 -1
- package/src/internal/predicate/key.d.ts +11 -0
- package/src/internal/predicate/key.ts +73 -0
- 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 → predicate/normalize.ts} +130 -49
- package/src/internal/predicate/runtime.d.ts +31 -0
- package/src/internal/{predicate-runtime.ts → predicate/runtime.ts} +127 -17
- 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 +683 -369
- package/src/internal/renderer.ts +11 -21
- package/src/internal/row-set.d.ts +53 -0
- package/src/internal/{plan.ts → row-set.ts} +11 -9
- package/src/internal/runtime/driver-value-mapping.ts +186 -0
- package/src/internal/{runtime-normalize.ts → runtime/normalize.ts} +9 -31
- package/src/internal/{runtime-schema.ts → runtime/schema.ts} +13 -38
- 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 +202 -0
- package/src/internal/schema-derivation.d.ts +105 -0
- package/src/internal/schema-expression.d.ts +18 -0
- package/src/internal/schema-expression.ts +38 -7
- package/src/internal/table-options.d.ts +94 -0
- package/src/internal/table-options.ts +8 -2
- package/src/internal/table.d.ts +173 -0
- package/src/internal/table.ts +32 -14
- package/src/mysql/column.ts +95 -18
- package/src/mysql/datatypes/index.ts +47 -7
- 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 +88 -11
- package/src/mysql/function/aggregate.ts +1 -5
- package/src/mysql/function/core.ts +1 -4
- package/src/mysql/function/index.ts +0 -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} +12 -6
- package/src/{internal/mysql-query.ts → mysql/internal/dsl.ts} +1299 -2143
- package/src/mysql/internal/renderer.ts +46 -0
- package/src/mysql/internal/sql-expression-renderer.ts +1501 -0
- package/src/mysql/json.ts +2 -0
- package/src/mysql/query.ts +111 -91
- package/src/mysql/renderer.ts +8 -3
- package/src/mysql/table.ts +1 -1
- package/src/mysql.ts +6 -4
- package/src/postgres/cast.ts +30 -16
- package/src/postgres/column.ts +179 -46
- package/src/postgres/datatypes/index.d.ts +515 -0
- package/src/postgres/datatypes/index.ts +22 -13
- 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 +54 -7
- package/src/postgres/function/aggregate.ts +1 -5
- package/src/postgres/function/core.ts +12 -6
- package/src/postgres/function/index.ts +0 -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} +12 -6
- package/src/{internal/postgres-query.ts → postgres/internal/dsl.ts} +1356 -2133
- package/src/{internal/postgres-renderer.ts → postgres/internal/renderer.ts} +17 -8
- package/src/postgres/internal/schema-ddl.ts +108 -0
- package/src/{internal/postgres-schema-model.ts → postgres/internal/schema-model.ts} +12 -6
- package/src/{internal → postgres/internal}/sql-expression-renderer.ts +79 -25
- package/src/postgres/{function/json.ts → json.ts} +77 -85
- package/src/postgres/metadata.ts +2 -2
- package/src/postgres/query.ts +113 -89
- package/src/postgres/renderer.ts +8 -13
- package/src/postgres/schema-expression.ts +2 -1
- package/src/postgres/schema-management.ts +1 -1
- package/src/postgres/table.ts +12 -4
- package/src/postgres/type.ts +33 -2
- package/src/postgres.ts +6 -4
- package/src/internal/expression.ts +0 -327
- package/src/internal/mysql-renderer.ts +0 -37
- package/src/internal/predicate-analysis.ts +0 -81
- package/src/internal/predicate-key.ts +0 -28
- package/src/internal/schema-ddl.ts +0 -55
- package/src/mysql/function/json.ts +0 -4
- package/src/mysql/private/query.ts +0 -1
- package/src/postgres/private/query.ts +0 -1
|
@@ -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>;
|
|
@@ -0,0 +1,202 @@
|
|
|
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
|
+
readonly driverValueMapping?: DriverValueMapping
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** JSON-like database type. */
|
|
58
|
+
export interface Json<
|
|
59
|
+
Dialect extends string = string,
|
|
60
|
+
SchemaName extends string = "json"
|
|
61
|
+
> extends Base<Dialect, SchemaName>
|
|
62
|
+
{
|
|
63
|
+
readonly variant: SchemaName extends "jsonb" ? "jsonb" : "json"
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Array database type. */
|
|
67
|
+
export interface Array<
|
|
68
|
+
Dialect extends string = string,
|
|
69
|
+
Element extends Any = any,
|
|
70
|
+
Kind extends string = string
|
|
71
|
+
> extends Base<Dialect, Kind> {
|
|
72
|
+
readonly element: Element
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Range database type. */
|
|
76
|
+
export interface Range<
|
|
77
|
+
Dialect extends string = string,
|
|
78
|
+
Subtype extends Any = any,
|
|
79
|
+
Kind extends string = string
|
|
80
|
+
> extends Base<Dialect, Kind> {
|
|
81
|
+
readonly subtype: Subtype
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Multirange database type. */
|
|
85
|
+
export interface Multirange<
|
|
86
|
+
Dialect extends string = string,
|
|
87
|
+
Subtype extends Any = any,
|
|
88
|
+
Kind extends string = string
|
|
89
|
+
> extends Base<Dialect, Kind> {
|
|
90
|
+
readonly subtype: Subtype
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Composite/record database type. */
|
|
94
|
+
export interface Composite<
|
|
95
|
+
Dialect extends string = string,
|
|
96
|
+
Fields extends Record<string, Any> = Record<string, any>,
|
|
97
|
+
Kind extends string = string
|
|
98
|
+
> extends Base<Dialect, Kind> {
|
|
99
|
+
readonly fields: Fields
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Named domain database type. */
|
|
103
|
+
export interface Domain<
|
|
104
|
+
Dialect extends string = string,
|
|
105
|
+
BaseType extends Any = any,
|
|
106
|
+
Kind extends string = string
|
|
107
|
+
> extends Base<Dialect, Kind> {
|
|
108
|
+
readonly base: BaseType
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Enumeration database type. */
|
|
112
|
+
export interface Enum<
|
|
113
|
+
Dialect extends string = string,
|
|
114
|
+
Kind extends string = string
|
|
115
|
+
> extends Base<Dialect, Kind> {
|
|
116
|
+
readonly variant: "enum"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Set database type. */
|
|
120
|
+
export interface Set<
|
|
121
|
+
Dialect extends string = string,
|
|
122
|
+
Kind extends string = string
|
|
123
|
+
> extends Base<Dialect, Kind> {
|
|
124
|
+
readonly variant: "set"
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export type Any =
|
|
128
|
+
| Json
|
|
129
|
+
| Base<string, string>
|
|
130
|
+
| Array<string, any, string>
|
|
131
|
+
| Range<string, any, string>
|
|
132
|
+
| Multirange<string, any, string>
|
|
133
|
+
| Composite<string, Record<string, any>, string>
|
|
134
|
+
| Domain<string, any, string>
|
|
135
|
+
| Enum<string, string>
|
|
136
|
+
| Set<string, string>
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface DriverValueMapping {
|
|
140
|
+
readonly fromDriver?: (value: unknown, dbType: DbType.Any) => unknown
|
|
141
|
+
readonly toDriver?: (value: unknown, dbType: DbType.Any) => unknown
|
|
142
|
+
readonly selectSql?: (sql: string, dbType: DbType.Any) => string
|
|
143
|
+
readonly jsonSelectSql?: (sql: string, dbType: DbType.Any) => string
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type DriverValueMappings = Readonly<Record<string, DriverValueMapping | undefined>>
|
|
147
|
+
|
|
148
|
+
/** Canonical static metadata stored on an expression. */
|
|
149
|
+
export interface State<
|
|
150
|
+
Runtime,
|
|
151
|
+
Db extends DbType.Any,
|
|
152
|
+
Nullable extends Nullability,
|
|
153
|
+
Dialect extends string,
|
|
154
|
+
Kind extends ScalarKind,
|
|
155
|
+
Deps extends BindingId = never
|
|
156
|
+
> {
|
|
157
|
+
readonly runtime: Runtime
|
|
158
|
+
readonly dbType: Db
|
|
159
|
+
readonly runtimeSchema?: Schema.Schema.Any
|
|
160
|
+
readonly driverValueMapping?: DriverValueMapping
|
|
161
|
+
readonly nullability: Nullable
|
|
162
|
+
readonly dialect: Dialect
|
|
163
|
+
readonly kind: Kind
|
|
164
|
+
readonly dependencies: Record<string, true>
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* A typed scalar SQL expression.
|
|
169
|
+
*
|
|
170
|
+
* `Runtime` is the decoded TypeScript type while `Db` captures the SQL-level
|
|
171
|
+
* type identity. Both are needed: multiple SQL types may decode to the same
|
|
172
|
+
* runtime type but still have different comparison/cast semantics.
|
|
173
|
+
*/
|
|
174
|
+
export interface Scalar<
|
|
175
|
+
Runtime,
|
|
176
|
+
Db extends DbType.Any,
|
|
177
|
+
Nullable extends Nullability = "never",
|
|
178
|
+
Dialect extends string = Db["dialect"],
|
|
179
|
+
Kind extends ScalarKind = "scalar",
|
|
180
|
+
Deps extends BindingId = never,
|
|
181
|
+
GroupKey extends string = string
|
|
182
|
+
> extends Pipeable {
|
|
183
|
+
readonly [TypeId]: State<Runtime, Db, Nullable, Dialect, Kind, Deps>
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Convenience alias for any expression-like value. */
|
|
187
|
+
export type Any = Scalar<any, DbType.Any, Nullability, string, ScalarKind, BindingId, string>
|
|
188
|
+
/** Extracts an expression's decoded runtime type. */
|
|
189
|
+
export type RuntimeOf<Value extends Any> = Value[typeof TypeId]["runtime"]
|
|
190
|
+
/** Extracts an expression's database-type descriptor. */
|
|
191
|
+
export type DbTypeOf<Value extends Any> = Value[typeof TypeId]["dbType"]
|
|
192
|
+
/** Extracts an expression's nullability state. */
|
|
193
|
+
export type NullabilityOf<Value extends Any> = Value[typeof TypeId]["nullability"]
|
|
194
|
+
/** Extracts an expression's kind. */
|
|
195
|
+
export type KindOf<Value extends Any> = Value[typeof TypeId]["kind"]
|
|
196
|
+
/** Extracts an expression's source dependency union. */
|
|
197
|
+
export type DependenciesOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, infer Deps> ? Deps : never
|
|
198
|
+
/** Extracts an expression's grouping identity. */
|
|
199
|
+
export type GroupKeyOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, any, infer GroupKey> ? GroupKey : never
|
|
200
|
+
|
|
201
|
+
/** Maps a database type descriptor back to its decoded runtime type. */
|
|
202
|
+
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 {};
|
|
@@ -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;
|
|
@@ -11,10 +11,21 @@ const SchemaExpressionProto = {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
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
|
+
|
|
14
25
|
export interface SchemaExpression extends Pipeable {
|
|
15
26
|
readonly [TypeId]: {
|
|
16
|
-
readonly
|
|
17
|
-
readonly
|
|
27
|
+
readonly ast?: Expr
|
|
28
|
+
readonly sql?: string
|
|
18
29
|
}
|
|
19
30
|
}
|
|
20
31
|
|
|
@@ -24,21 +35,41 @@ export const isSchemaExpression = (value: unknown): value is SchemaExpression =>
|
|
|
24
35
|
typeof value === "object" && value !== null && TypeId in value
|
|
25
36
|
|
|
26
37
|
export const fromAst = (ast: Expr): SchemaExpression => {
|
|
27
|
-
const expression = Object.create(SchemaExpressionProto)
|
|
38
|
+
const expression = attachPipe(Object.create(SchemaExpressionProto))
|
|
28
39
|
expression[TypeId] = {
|
|
29
|
-
dialect: "postgres",
|
|
30
40
|
ast
|
|
31
41
|
}
|
|
32
42
|
return expression
|
|
33
43
|
}
|
|
34
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
|
+
|
|
35
53
|
export const parseExpression = (sql: string): SchemaExpression =>
|
|
36
54
|
fromAst(parse(sql, "expr"))
|
|
37
55
|
|
|
38
|
-
export const toAst = (expression: SchemaExpression): Expr =>
|
|
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
|
+
}
|
|
39
63
|
|
|
40
64
|
export const render = (expression: SchemaExpression): string =>
|
|
41
|
-
toSql.expr(expression
|
|
65
|
+
expression[TypeId].sql ?? toSql.expr(toAst(expression))
|
|
42
66
|
|
|
43
67
|
export const normalize = (expression: SchemaExpression): SchemaExpression =>
|
|
44
|
-
|
|
68
|
+
(() => {
|
|
69
|
+
const sql = render(expression)
|
|
70
|
+
try {
|
|
71
|
+
return parseExpression(sql)
|
|
72
|
+
} catch {
|
|
73
|
+
return fromSql(sql)
|
|
74
|
+
}
|
|
75
|
+
})()
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { type AnyColumnDefinition, type IsNullable } from "./column-state.js";
|
|
2
|
+
import type { Any as AnyExpression } from "./scalar.js";
|
|
3
|
+
import type { Any as AnySchemaExpression } from "./schema-expression.js";
|
|
4
|
+
import type { TableFieldMap } from "./schema-derivation.js";
|
|
5
|
+
/** Non-empty list of column names. */
|
|
6
|
+
export type ColumnList = readonly [string, ...string[]];
|
|
7
|
+
export type DdlExpressionLike = AnyExpression | AnySchemaExpression;
|
|
8
|
+
export type ReferentialAction = "noAction" | "restrict" | "cascade" | "setNull" | "setDefault";
|
|
9
|
+
export type IndexKeySpec = {
|
|
10
|
+
readonly kind: "column";
|
|
11
|
+
readonly column: string;
|
|
12
|
+
readonly order?: "asc" | "desc";
|
|
13
|
+
readonly nulls?: "first" | "last";
|
|
14
|
+
readonly operatorClass?: string;
|
|
15
|
+
readonly collation?: string;
|
|
16
|
+
} | {
|
|
17
|
+
readonly kind: "expression";
|
|
18
|
+
readonly expression: DdlExpressionLike;
|
|
19
|
+
readonly order?: "asc" | "desc";
|
|
20
|
+
readonly nulls?: "first" | "last";
|
|
21
|
+
readonly operatorClass?: string;
|
|
22
|
+
readonly collation?: string;
|
|
23
|
+
};
|
|
24
|
+
/** Normalized table-level option record. */
|
|
25
|
+
export type TableOptionSpec = {
|
|
26
|
+
readonly kind: "index";
|
|
27
|
+
readonly columns?: ColumnList;
|
|
28
|
+
readonly name?: string;
|
|
29
|
+
readonly unique?: boolean;
|
|
30
|
+
readonly method?: string;
|
|
31
|
+
readonly include?: readonly string[];
|
|
32
|
+
readonly predicate?: DdlExpressionLike;
|
|
33
|
+
readonly keys?: readonly [IndexKeySpec, ...IndexKeySpec[]];
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: "unique";
|
|
36
|
+
readonly columns: ColumnList;
|
|
37
|
+
readonly name?: string;
|
|
38
|
+
readonly nullsNotDistinct?: boolean;
|
|
39
|
+
readonly deferrable?: boolean;
|
|
40
|
+
readonly initiallyDeferred?: boolean;
|
|
41
|
+
} | {
|
|
42
|
+
readonly kind: "primaryKey";
|
|
43
|
+
readonly columns: ColumnList;
|
|
44
|
+
readonly name?: string;
|
|
45
|
+
readonly deferrable?: boolean;
|
|
46
|
+
readonly initiallyDeferred?: boolean;
|
|
47
|
+
} | {
|
|
48
|
+
readonly kind: "foreignKey";
|
|
49
|
+
readonly columns: ColumnList;
|
|
50
|
+
readonly name?: string;
|
|
51
|
+
readonly references: () => {
|
|
52
|
+
readonly tableName: string;
|
|
53
|
+
readonly schemaName?: string;
|
|
54
|
+
readonly columns: ColumnList;
|
|
55
|
+
readonly knownColumns?: readonly string[];
|
|
56
|
+
};
|
|
57
|
+
readonly onUpdate?: ReferentialAction;
|
|
58
|
+
readonly onDelete?: ReferentialAction;
|
|
59
|
+
readonly deferrable?: boolean;
|
|
60
|
+
readonly initiallyDeferred?: boolean;
|
|
61
|
+
} | {
|
|
62
|
+
readonly kind: "check";
|
|
63
|
+
readonly name: string;
|
|
64
|
+
readonly predicate: DdlExpressionLike;
|
|
65
|
+
readonly noInherit?: boolean;
|
|
66
|
+
};
|
|
67
|
+
/** Thin wrapper used by the public `Table.*` option builders. */
|
|
68
|
+
export interface TableOptionBuilder<Spec extends TableOptionSpec = TableOptionSpec> {
|
|
69
|
+
readonly option: Spec;
|
|
70
|
+
}
|
|
71
|
+
/** Collection of declared table options. */
|
|
72
|
+
export type DeclaredTableOptions = readonly TableOptionBuilder[];
|
|
73
|
+
type ColumnNameUnion<Fields extends TableFieldMap> = Extract<keyof Fields, string>;
|
|
74
|
+
type NullableColumnNames<Fields extends TableFieldMap> = {
|
|
75
|
+
[K in keyof Fields]: Fields[K] extends AnyColumnDefinition ? IsNullable<Fields[K]> extends true ? K : never : never;
|
|
76
|
+
}[keyof Fields];
|
|
77
|
+
type TupleFromColumns<Columns> = Columns extends readonly [infer Head extends string, ...infer Tail extends string[]] ? readonly [Head, ...Tail] : Columns extends readonly string[] ? Columns extends readonly [string, ...string[]] ? Columns : never : Columns extends string ? readonly [Columns] : never;
|
|
78
|
+
type AssertKnownColumns<Fields extends TableFieldMap, Columns extends readonly string[]> = Exclude<Columns[number], ColumnNameUnion<Fields>> extends never ? Columns : never;
|
|
79
|
+
type AssertPrimaryKeyColumns<Fields extends TableFieldMap, Columns extends readonly string[]> = Extract<Columns[number], NullableColumnNames<Fields>> extends never ? Columns : never;
|
|
80
|
+
/** Normalizes a string or tuple input into a non-empty column list. */
|
|
81
|
+
export declare const normalizeColumnList: (columns: string | readonly string[]) => ColumnList;
|
|
82
|
+
/** Converts inline column flags into normalized table option records. */
|
|
83
|
+
export declare const collectInlineOptions: <Fields extends TableFieldMap>(fields: Fields) => readonly TableOptionSpec[];
|
|
84
|
+
/** Resolves the effective primary-key columns for a table. */
|
|
85
|
+
export declare const resolvePrimaryKeyColumns: <Fields extends TableFieldMap>(fields: Fields, declaredOptions: readonly TableOptionSpec[]) => readonly (keyof Fields & string)[];
|
|
86
|
+
/** Validates that options reference known, legal columns for the table. */
|
|
87
|
+
export declare const validateOptions: <Fields extends TableFieldMap>(tableName: string, fields: Fields, options: readonly TableOptionSpec[]) => void;
|
|
88
|
+
/** Compile-time validation that option columns exist on the table. */
|
|
89
|
+
export type ValidateKnownColumns<Fields extends TableFieldMap, Columns extends readonly string[]> = AssertKnownColumns<Fields, Columns>;
|
|
90
|
+
/** Compile-time validation that primary-key columns are known and non-nullable. */
|
|
91
|
+
export type ValidatePrimaryKeyColumns<Fields extends TableFieldMap, Columns extends readonly string[]> = AssertPrimaryKeyColumns<Fields, AssertKnownColumns<Fields, Columns>>;
|
|
92
|
+
/** Normalizes a public column input into the internal tuple form. */
|
|
93
|
+
export type NormalizeColumns<Columns extends string | readonly string[]> = TupleFromColumns<Columns>;
|
|
94
|
+
export {};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type AnyColumnDefinition,
|
|
5
5
|
type IsNullable
|
|
6
6
|
} from "./column-state.js"
|
|
7
|
-
import type { Any as AnyExpression } from "./
|
|
7
|
+
import type { Any as AnyExpression } from "./scalar.js"
|
|
8
8
|
import type { Any as AnySchemaExpression } from "./schema-expression.js"
|
|
9
9
|
import type { TableFieldMap } from "./schema-derivation.js"
|
|
10
10
|
|
|
@@ -21,12 +21,16 @@ export type IndexKeySpec =
|
|
|
21
21
|
readonly column: string
|
|
22
22
|
readonly order?: "asc" | "desc"
|
|
23
23
|
readonly nulls?: "first" | "last"
|
|
24
|
+
readonly operatorClass?: string
|
|
25
|
+
readonly collation?: string
|
|
24
26
|
}
|
|
25
27
|
| {
|
|
26
28
|
readonly kind: "expression"
|
|
27
29
|
readonly expression: DdlExpressionLike
|
|
28
30
|
readonly order?: "asc" | "desc"
|
|
29
31
|
readonly nulls?: "first" | "last"
|
|
32
|
+
readonly operatorClass?: string
|
|
33
|
+
readonly collation?: string
|
|
30
34
|
}
|
|
31
35
|
|
|
32
36
|
/** Normalized table-level option record. */
|
|
@@ -182,7 +186,9 @@ export const collectInlineOptions = <Fields extends TableFieldMap>(
|
|
|
182
186
|
kind: "column",
|
|
183
187
|
column: columnName,
|
|
184
188
|
order: column.metadata.index.order,
|
|
185
|
-
nulls: column.metadata.index.nulls
|
|
189
|
+
nulls: column.metadata.index.nulls,
|
|
190
|
+
operatorClass: column.metadata.index.operatorClass,
|
|
191
|
+
collation: column.metadata.index.collation
|
|
186
192
|
}],
|
|
187
193
|
name: column.metadata.index.name,
|
|
188
194
|
method: column.metadata.index.method,
|