effect-qb 0.17.0 → 0.19.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 +4 -0
- package/dist/index.js +8065 -0
- package/dist/mysql.js +3053 -2505
- package/dist/postgres/metadata.js +1366 -1250
- package/dist/postgres.js +2020 -2719
- package/dist/sqlite.js +3226 -2732
- package/dist/standard.js +8019 -0
- package/package.json +10 -3
- package/src/casing.ts +71 -0
- package/src/index.ts +2 -0
- package/src/internal/casing.ts +89 -0
- package/src/internal/column-state.ts +11 -6
- package/src/internal/column.ts +44 -7
- package/src/internal/datatypes/define.ts +2 -1
- package/src/internal/datatypes/enrich.ts +23 -0
- package/src/internal/datatypes/lookup.ts +14 -7
- package/src/internal/derived-table.ts +4 -36
- package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/mysql.ts} +548 -359
- package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +654 -399
- package/src/{sqlite/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +501 -345
- package/src/internal/dialect.ts +35 -0
- package/src/internal/dsl-mutation-runtime.ts +12 -162
- package/src/internal/dsl-plan-runtime.ts +10 -138
- package/src/internal/dsl-query-runtime.ts +5 -79
- package/src/internal/dsl-transaction-ddl-runtime.ts +41 -65
- package/src/internal/executor.ts +10 -6
- package/src/internal/grouping-key.ts +87 -20
- package/src/internal/implication-runtime.ts +1 -1
- package/src/internal/predicate/runtime.ts +3 -0
- package/src/internal/query.d.ts +38 -11
- package/src/internal/query.ts +64 -25
- package/src/internal/renderer.ts +26 -14
- package/src/internal/runtime/normalize.ts +12 -5
- package/src/internal/scalar.ts +6 -1
- package/src/internal/schema-derivation.d.ts +12 -61
- package/src/internal/schema-derivation.ts +90 -38
- package/src/internal/schema-expression.ts +2 -2
- package/src/internal/sql-expression-renderer.ts +19 -0
- package/src/internal/standard-dsl.ts +6885 -0
- package/src/internal/table-options.ts +126 -66
- package/src/internal/table.d.ts +33 -32
- package/src/internal/table.ts +406 -155
- package/src/mysql/column-extension.ts +3 -0
- package/src/mysql/column.ts +10 -11
- package/src/mysql/datatypes/index.ts +3 -2
- package/src/mysql/executor.ts +7 -5
- package/src/mysql/internal/dialect.ts +9 -4
- package/src/mysql/internal/dsl.ts +219 -155
- package/src/mysql/internal/renderer.ts +6 -2
- package/src/mysql/json.ts +37 -0
- package/src/mysql/query-extension.ts +16 -0
- package/src/mysql/renderer.ts +31 -4
- package/src/mysql.ts +4 -12
- package/src/postgres/column-extension.ts +28 -0
- package/src/postgres/column.ts +5 -11
- package/src/postgres/datatypes/index.d.ts +2 -1
- package/src/postgres/datatypes/index.ts +3 -2
- package/src/postgres/executor.ts +7 -5
- package/src/postgres/function/core.ts +1 -3
- package/src/postgres/function/index.ts +1 -17
- package/src/postgres/internal/dialect.ts +9 -4
- package/src/postgres/internal/dsl.ts +208 -160
- package/src/postgres/internal/renderer.ts +6 -2
- package/src/postgres/internal/schema-ddl.ts +22 -10
- package/src/postgres/internal/schema-model.ts +238 -7
- package/src/postgres/json.ts +43 -7
- package/src/postgres/jsonb.ts +38 -0
- package/src/postgres/query-extension.ts +2 -0
- package/src/postgres/renderer.ts +31 -4
- package/src/postgres/schema-management.ts +17 -12
- package/src/postgres/schema.ts +98 -15
- package/src/postgres/table.ts +193 -524
- package/src/postgres/type.ts +8 -7
- package/src/postgres.ts +9 -11
- package/src/sqlite/column-extension.ts +3 -0
- package/src/sqlite/column.ts +10 -11
- package/src/sqlite/datatypes/index.ts +3 -2
- package/src/sqlite/executor.ts +7 -5
- package/src/sqlite/internal/dialect.ts +9 -4
- package/src/sqlite/internal/dsl.ts +208 -155
- package/src/sqlite/internal/renderer.ts +6 -2
- package/src/sqlite/json.ts +37 -0
- package/src/sqlite/query-extension.ts +2 -0
- package/src/sqlite/renderer.ts +31 -4
- package/src/sqlite.ts +4 -12
- package/src/standard/column.ts +163 -0
- package/src/standard/datatypes/index.ts +83 -0
- package/src/standard/datatypes/spec.ts +98 -0
- package/src/standard/dialect.ts +40 -0
- package/src/standard/function/aggregate.ts +2 -0
- package/src/standard/function/core.ts +2 -0
- package/src/standard/function/index.ts +18 -0
- package/src/standard/function/string.ts +2 -0
- package/src/standard/function/temporal.ts +78 -0
- package/src/standard/function/window.ts +2 -0
- package/src/standard/internal/renderer.ts +45 -0
- package/src/standard/query.ts +152 -0
- package/src/standard/renderer.ts +21 -0
- package/src/standard/table.ts +147 -0
- package/src/standard.ts +18 -0
- package/src/internal/aggregation-validation.ts +0 -57
- package/src/mysql/table.ts +0 -183
- package/src/sqlite/table.ts +0 -183
package/src/internal/query.ts
CHANGED
|
@@ -96,7 +96,7 @@ export { union_query_capabilities } from "./query-requirements.js"
|
|
|
96
96
|
* `Pipeable.pipe(...)` plus the metadata stored under `Expression.TypeId`.
|
|
97
97
|
*/
|
|
98
98
|
const ExpressionProto = {
|
|
99
|
-
pipe(this:
|
|
99
|
+
pipe(this: Pipeable) {
|
|
100
100
|
return pipeArguments(this, arguments)
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -108,7 +108,7 @@ const ExpressionProto = {
|
|
|
108
108
|
* chained through `.pipe(...)`.
|
|
109
109
|
*/
|
|
110
110
|
const PlanProto = {
|
|
111
|
-
pipe(this:
|
|
111
|
+
pipe(this: Pipeable) {
|
|
112
112
|
return pipeArguments(this, arguments)
|
|
113
113
|
}
|
|
114
114
|
}
|
|
@@ -143,6 +143,34 @@ export interface QueryState<
|
|
|
143
143
|
|
|
144
144
|
/** Effective SQL dialect carried by an expression. */
|
|
145
145
|
export type DialectOf<Value extends Expression.Any> = Value[typeof Expression.TypeId]["dialect"]
|
|
146
|
+
type ConcreteDialect<D> = D extends "standard" ? never : D
|
|
147
|
+
type IsDialectUnion<Union, All = Union> = Union extends any
|
|
148
|
+
? [All] extends [Union] ? false : true
|
|
149
|
+
: false
|
|
150
|
+
export type DialectConflictError<A extends string, B extends string> = string & {
|
|
151
|
+
readonly _tag: "DialectConflict"
|
|
152
|
+
readonly left: A
|
|
153
|
+
readonly right: B
|
|
154
|
+
}
|
|
155
|
+
export type MergeDialect<A extends string, B extends string> =
|
|
156
|
+
[ConcreteDialect<A>, ConcreteDialect<B>] extends [never, never] ? "standard"
|
|
157
|
+
: [ConcreteDialect<A>, ConcreteDialect<B>] extends [never, infer C extends string] ? C
|
|
158
|
+
: [ConcreteDialect<A>, ConcreteDialect<B>] extends [infer C extends string, never] ? C
|
|
159
|
+
: ConcreteDialect<A> extends ConcreteDialect<B>
|
|
160
|
+
? ConcreteDialect<B> extends ConcreteDialect<A>
|
|
161
|
+
? A
|
|
162
|
+
: DialectConflictError<A, B>
|
|
163
|
+
: DialectConflictError<A, B>
|
|
164
|
+
|
|
165
|
+
/** Collapses the portable standard tag out of a dialect union. */
|
|
166
|
+
export type NormalizeDialect<Dialect extends string> =
|
|
167
|
+
[Dialect] extends [never]
|
|
168
|
+
? never
|
|
169
|
+
: [Exclude<Dialect, "standard">] extends [never]
|
|
170
|
+
? "standard"
|
|
171
|
+
: IsDialectUnion<Exclude<Dialect, "standard">> extends true
|
|
172
|
+
? DialectConflictError<Exclude<Dialect, "standard">, Exclude<Dialect, "standard">>
|
|
173
|
+
: Exclude<Dialect, "standard">
|
|
146
174
|
/** Source dependency union carried by an expression. */
|
|
147
175
|
export type DependenciesOf<Value extends Expression.Any> = Expression.DependenciesOf<Value>
|
|
148
176
|
/** Aggregation kind carried by an expression. */
|
|
@@ -464,15 +492,17 @@ export type ExtractRequired<Selection> = Selection extends Expression.Any
|
|
|
464
492
|
}[keyof Selection]
|
|
465
493
|
: never
|
|
466
494
|
|
|
467
|
-
|
|
468
|
-
export type ExtractDialect<Selection> = Selection extends Expression.Any
|
|
495
|
+
type ExtractDialectRaw<Selection> = Selection extends Expression.Any
|
|
469
496
|
? DialectOf<Selection>
|
|
470
497
|
: Selection extends Record<string, any>
|
|
471
498
|
? {
|
|
472
|
-
[K in keyof Selection]:
|
|
499
|
+
[K in keyof Selection]: ExtractDialectRaw<Selection[K]>
|
|
473
500
|
}[keyof Selection]
|
|
474
501
|
: never
|
|
475
502
|
|
|
503
|
+
/** Walks a selection tree and extracts the effective dialects referenced by its leaves. */
|
|
504
|
+
export type ExtractDialect<Selection> = NormalizeDialect<Extract<ExtractDialectRaw<Selection>, string>>
|
|
505
|
+
|
|
476
506
|
/**
|
|
477
507
|
* Minimal table-like shape required by `from(...)` and joins.
|
|
478
508
|
*
|
|
@@ -1005,8 +1035,7 @@ export type UpdateInputOfTarget<Target extends MutationTargetInput> =
|
|
|
1005
1035
|
}>
|
|
1006
1036
|
: never
|
|
1007
1037
|
|
|
1008
|
-
|
|
1009
|
-
export type SourceDialectOf<Source extends SourceLike> =
|
|
1038
|
+
type SourceDialectOfRaw<Source extends SourceLike> =
|
|
1010
1039
|
Source extends TableLike<any, infer Dialect> ? Dialect :
|
|
1011
1040
|
Source extends { readonly kind: "derived"; readonly plan: infer PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any> } ? PlanDialectOf<PlanValue> :
|
|
1012
1041
|
Source extends { readonly kind: "cte"; readonly plan: infer PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any> } ? PlanDialectOf<PlanValue> :
|
|
@@ -1014,6 +1043,9 @@ export type SourceDialectOf<Source extends SourceLike> =
|
|
|
1014
1043
|
Source extends { readonly dialect: infer Dialect extends string } ? Dialect :
|
|
1015
1044
|
never
|
|
1016
1045
|
|
|
1046
|
+
/** Extracts the effective dialect from a source. */
|
|
1047
|
+
export type SourceDialectOf<Source extends SourceLike> = NormalizeDialect<SourceDialectOfRaw<Source>>
|
|
1048
|
+
|
|
1017
1049
|
/** Extracts the base table name from a source. */
|
|
1018
1050
|
export type SourceBaseNameOf<Source extends SourceLike> =
|
|
1019
1051
|
Source extends TableLike<any, any> ? Source[typeof Table.TypeId]["baseName"] :
|
|
@@ -1148,6 +1180,21 @@ type DerivedProjectionIssues<Selection> =
|
|
|
1148
1180
|
: | DerivedProjectionDuplicateAliases<Selection>
|
|
1149
1181
|
| DerivedProjectionAliasMismatches<Selection>
|
|
1150
1182
|
|
|
1183
|
+
export type SelectionProjectionDuplicateAliases<Selection> =
|
|
1184
|
+
IsBroadSelection<Selection> extends true
|
|
1185
|
+
? never
|
|
1186
|
+
: DuplicateProjectionAliases<SelectionProjectionEntries<Selection>>
|
|
1187
|
+
|
|
1188
|
+
export type SelectionProjectionAliasCollisionError<Selection> = Selection & {
|
|
1189
|
+
readonly __effect_qb_error__: "effect-qb: projection aliases must be unique"
|
|
1190
|
+
readonly __effect_qb_duplicate_projection_aliases__: SelectionProjectionDuplicateAliases<Selection>
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
export type SelectionProjectionAliasCollisionConstraint<Selection> =
|
|
1194
|
+
[SelectionProjectionDuplicateAliases<Selection>] extends [never]
|
|
1195
|
+
? unknown
|
|
1196
|
+
: SelectionProjectionAliasCollisionError<Selection>
|
|
1197
|
+
|
|
1151
1198
|
export type DerivedSourceProjectionCompatibilityError<
|
|
1152
1199
|
PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>
|
|
1153
1200
|
> = PlanValue & {
|
|
@@ -1254,7 +1301,7 @@ export type AvailableOfPlan<
|
|
|
1254
1301
|
/** Extracts the effective dialect carried by a query plan. */
|
|
1255
1302
|
export type PlanDialectOf<
|
|
1256
1303
|
PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
|
|
1257
|
-
> = QueryPlanParts<PlanValue>["dialect"]
|
|
1304
|
+
> = NormalizeDialect<QueryPlanParts<PlanValue>["dialect"]>
|
|
1258
1305
|
/** Extracts the grouped-source phantom carried by a query plan. */
|
|
1259
1306
|
export type GroupedOfPlan<
|
|
1260
1307
|
PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any, any, any>
|
|
@@ -1465,7 +1512,7 @@ export type MergeNullabilityTuple<
|
|
|
1465
1512
|
/** Dialect union across a tuple of expressions. */
|
|
1466
1513
|
export type TupleDialect<
|
|
1467
1514
|
Values extends readonly Expression.Any[]
|
|
1468
|
-
> = Values[number] extends never ? never : DialectOf<Values[number]
|
|
1515
|
+
> = Values[number] extends never ? never : NormalizeDialect<DialectOf<Values[number]>>
|
|
1469
1516
|
|
|
1470
1517
|
/** Converts a union into an intersection. */
|
|
1471
1518
|
type UnionToIntersection<Union> = (
|
|
@@ -2124,7 +2171,7 @@ type DialectCompatibilityError<
|
|
|
2124
2171
|
EngineDialect extends string
|
|
2125
2172
|
> = PlanValue & {
|
|
2126
2173
|
readonly __effect_qb_error__: "effect-qb: plan dialect is not compatible with the target renderer or executor"
|
|
2127
|
-
readonly __effect_qb_plan_dialect__: PlanValue
|
|
2174
|
+
readonly __effect_qb_plan_dialect__: PlanDialectOf<PlanValue>
|
|
2128
2175
|
readonly __effect_qb_target_dialect__: EngineDialect
|
|
2129
2176
|
readonly __effect_qb_hint__: "Use the matching dialect module or renderer/executor"
|
|
2130
2177
|
}
|
|
@@ -2175,7 +2222,7 @@ type IsDialectCompatible<
|
|
|
2175
2222
|
EngineDialect extends string
|
|
2176
2223
|
> = [PlanDialect] extends [never]
|
|
2177
2224
|
? true
|
|
2178
|
-
: Exclude<PlanDialect, EngineDialect> extends never
|
|
2225
|
+
: Exclude<PlanDialect, EngineDialect | "standard"> extends never
|
|
2179
2226
|
? true
|
|
2180
2227
|
: false
|
|
2181
2228
|
|
|
@@ -2183,7 +2230,7 @@ type IsDialectCompatible<
|
|
|
2183
2230
|
export type DialectCompatiblePlan<
|
|
2184
2231
|
PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
|
|
2185
2232
|
EngineDialect extends string
|
|
2186
|
-
> = IsDialectCompatible<PlanValue
|
|
2233
|
+
> = IsDialectCompatible<PlanDialectOf<PlanValue>, EngineDialect> extends true
|
|
2187
2234
|
? CompletePlan<PlanValue>
|
|
2188
2235
|
: DialectCompatibilityError<PlanValue, EngineDialect>
|
|
2189
2236
|
|
|
@@ -2201,7 +2248,7 @@ type NestedPlanStatementError<
|
|
|
2201
2248
|
export type DialectCompatibleNestedPlan<
|
|
2202
2249
|
PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>,
|
|
2203
2250
|
EngineDialect extends string
|
|
2204
|
-
> = IsDialectCompatible<PlanValue
|
|
2251
|
+
> = IsDialectCompatible<PlanDialectOf<PlanValue>, EngineDialect> extends true
|
|
2205
2252
|
? StatementOfPlan<PlanValue> extends SelectLikeStatement
|
|
2206
2253
|
? AggregationCompatiblePlan<PlanValue>
|
|
2207
2254
|
: NestedPlanStatementError<PlanValue>
|
|
@@ -2427,7 +2474,7 @@ export const makeExpression = <
|
|
|
2427
2474
|
Object.defineProperty(expression, "pipe", {
|
|
2428
2475
|
configurable: true,
|
|
2429
2476
|
writable: true,
|
|
2430
|
-
value: function(this:
|
|
2477
|
+
value: function(this: Pipeable) {
|
|
2431
2478
|
return pipeArguments(expression, arguments)
|
|
2432
2479
|
}
|
|
2433
2480
|
})
|
|
@@ -2477,7 +2524,7 @@ export const makePlan = <
|
|
|
2477
2524
|
Object.defineProperty(plan, "pipe", {
|
|
2478
2525
|
configurable: true,
|
|
2479
2526
|
writable: true,
|
|
2480
|
-
value: function(this:
|
|
2527
|
+
value: function(this: Pipeable) {
|
|
2481
2528
|
return pipeArguments(plan, arguments)
|
|
2482
2529
|
}
|
|
2483
2530
|
})
|
|
@@ -2536,16 +2583,8 @@ export const extractRequiredRuntime = (selection: SelectionShape): readonly stri
|
|
|
2536
2583
|
|
|
2537
2584
|
/** Extracts the single top-level expression from a scalar subquery selection. */
|
|
2538
2585
|
export const extractSingleSelectedExpressionRuntime = (selection: SelectionShape): Expression.Any => {
|
|
2539
|
-
const
|
|
2540
|
-
|
|
2541
|
-
throw new Error("scalar subqueries must select exactly one top-level expression")
|
|
2542
|
-
}
|
|
2543
|
-
const record = selection as Record<string, unknown>
|
|
2544
|
-
const value = record[keys[0]!]
|
|
2545
|
-
if (value === null || typeof value !== "object" || !(Expression.TypeId in (value as object))) {
|
|
2546
|
-
throw new Error("scalar subqueries must select a scalar expression")
|
|
2547
|
-
}
|
|
2548
|
-
return value as unknown as Expression.Any
|
|
2586
|
+
const record = selection as Record<string, Expression.Any>
|
|
2587
|
+
return record[Object.keys(record)[0]!]!
|
|
2549
2588
|
}
|
|
2550
2589
|
|
|
2551
2590
|
/** Converts the plan's runtime `required` metadata into a mutable string list. */
|
package/src/internal/renderer.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as Query from "./query.js"
|
|
2
|
-
import
|
|
2
|
+
import * as Expression from "./scalar.js"
|
|
3
3
|
import { flattenSelection, type Projection, validateProjections } from "./projections.js"
|
|
4
|
-
import * as Plan from "./row-set.js"
|
|
5
4
|
|
|
6
5
|
/** Symbol used to attach rendered-query phantom row metadata. */
|
|
7
6
|
export const TypeId: unique symbol = Symbol.for("effect-qb/Renderer")
|
|
@@ -38,8 +37,7 @@ export type RowOf<Value extends RenderedQuery<any, any>> = Value[typeof TypeId][
|
|
|
38
37
|
*
|
|
39
38
|
* Renderers only accept complete, dialect-compatible plans. The returned
|
|
40
39
|
* `RenderedQuery` keeps the canonical `Query.ResultRow<...>` type attached for
|
|
41
|
-
* downstream executor layers
|
|
42
|
-
* matching runtime aggregate-shape validation.
|
|
40
|
+
* downstream executor layers.
|
|
43
41
|
*/
|
|
44
42
|
export interface Renderer<Dialect extends string = string> {
|
|
45
43
|
readonly dialect: Dialect
|
|
@@ -91,24 +89,38 @@ export function make<Dialect extends string>(
|
|
|
91
89
|
dialect: Dialect,
|
|
92
90
|
render: CustomRender<Dialect>
|
|
93
91
|
): Renderer<Dialect> {
|
|
92
|
+
return makeRenderer(dialect, render, true)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Internal renderer factory for built-in renderers that derive projections from typed plans. */
|
|
96
|
+
export function makeTrusted<Dialect extends string>(
|
|
97
|
+
dialect: Dialect,
|
|
98
|
+
render: CustomRender<Dialect>
|
|
99
|
+
): Renderer<Dialect>
|
|
100
|
+
export function makeTrusted<Dialect extends string>(
|
|
101
|
+
dialect: Dialect,
|
|
102
|
+
render: CustomRender<Dialect>
|
|
103
|
+
): Renderer<Dialect> {
|
|
104
|
+
return makeRenderer(dialect, render, false)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const makeRenderer = <Dialect extends string>(
|
|
108
|
+
dialect: Dialect,
|
|
109
|
+
render: CustomRender<Dialect>,
|
|
110
|
+
validate: boolean
|
|
111
|
+
): Renderer<Dialect> => {
|
|
94
112
|
if (typeof render !== "function") {
|
|
95
113
|
throw new Error(`Renderer.make requires an explicit render implementation for dialect: ${dialect}`)
|
|
96
114
|
}
|
|
97
115
|
return {
|
|
98
116
|
dialect,
|
|
99
117
|
render(plan) {
|
|
100
|
-
const required = Query.currentRequiredList(plan[Plan.TypeId].required)
|
|
101
|
-
if (required.length > 0) {
|
|
102
|
-
throw new Error(`query references sources that are not yet in scope: ${required.join(", ")}`)
|
|
103
|
-
}
|
|
104
|
-
const planDialect = plan[Plan.TypeId].dialect
|
|
105
|
-
if (planDialect !== dialect) {
|
|
106
|
-
throw new Error("effect-qb: plan dialect is not compatible with the target renderer or executor")
|
|
107
|
-
}
|
|
108
118
|
const rendered = render(plan)
|
|
109
119
|
const projections = rendered.projections ?? []
|
|
110
|
-
|
|
111
|
-
|
|
120
|
+
if (validate) {
|
|
121
|
+
validateProjections(projections)
|
|
122
|
+
validateProjectionPathsMatchSelection(plan as Query.Plan.Any, projections)
|
|
123
|
+
}
|
|
112
124
|
return {
|
|
113
125
|
sql: rendered.sql,
|
|
114
126
|
params: rendered.params ?? [],
|
|
@@ -23,6 +23,13 @@ const isPlainRecord = (value: unknown): value is Record<string, unknown> => {
|
|
|
23
23
|
|
|
24
24
|
const pad = (value: number, width = 2): string => value.toString().padStart(width, "0")
|
|
25
25
|
|
|
26
|
+
const validDate = (value: Date): Date => {
|
|
27
|
+
if (Number.isNaN(value.getTime())) {
|
|
28
|
+
throw new Error("Expected a valid Date value")
|
|
29
|
+
}
|
|
30
|
+
return value
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
const formatLocalDate = (value: Date): string =>
|
|
27
34
|
`${pad(value.getUTCFullYear(), 4)}-${pad(value.getUTCMonth() + 1)}-${pad(value.getUTCDate())}`
|
|
28
35
|
|
|
@@ -125,7 +132,7 @@ const normalizeDecimalString = (value: unknown): string => {
|
|
|
125
132
|
|
|
126
133
|
const normalizeLocalDate = (value: unknown): string => {
|
|
127
134
|
if (value instanceof Date) {
|
|
128
|
-
return formatLocalDate(value)
|
|
135
|
+
return formatLocalDate(validDate(value))
|
|
129
136
|
}
|
|
130
137
|
const raw = expectString(value, "local date").trim()
|
|
131
138
|
if (isValidLocalDateString(raw)) {
|
|
@@ -143,7 +150,7 @@ const normalizeLocalDate = (value: unknown): string => {
|
|
|
143
150
|
|
|
144
151
|
const normalizeLocalTime = (value: unknown): string => {
|
|
145
152
|
if (value instanceof Date) {
|
|
146
|
-
return formatLocalTime(value)
|
|
153
|
+
return formatLocalTime(validDate(value))
|
|
147
154
|
}
|
|
148
155
|
const raw = expectString(value, "local time").trim()
|
|
149
156
|
if (isValidLocalTimeString(raw)) {
|
|
@@ -154,7 +161,7 @@ const normalizeLocalTime = (value: unknown): string => {
|
|
|
154
161
|
|
|
155
162
|
const normalizeOffsetTime = (value: unknown): string => {
|
|
156
163
|
if (value instanceof Date) {
|
|
157
|
-
return `${formatLocalTime(value)}Z`
|
|
164
|
+
return `${formatLocalTime(validDate(value))}Z`
|
|
158
165
|
}
|
|
159
166
|
const raw = expectString(value, "offset time").trim()
|
|
160
167
|
if (isValidOffsetTimeString(raw)) {
|
|
@@ -165,7 +172,7 @@ const normalizeOffsetTime = (value: unknown): string => {
|
|
|
165
172
|
|
|
166
173
|
const normalizeLocalDateTime = (value: unknown): string => {
|
|
167
174
|
if (value instanceof Date) {
|
|
168
|
-
return formatLocalDateTime(value)
|
|
175
|
+
return formatLocalDateTime(validDate(value))
|
|
169
176
|
}
|
|
170
177
|
const raw = expectString(value, "local datetime").trim()
|
|
171
178
|
const canonicalLocalDateTime = raw.replace(" ", "T")
|
|
@@ -184,7 +191,7 @@ const normalizeLocalDateTime = (value: unknown): string => {
|
|
|
184
191
|
|
|
185
192
|
const normalizeInstant = (value: unknown): string => {
|
|
186
193
|
if (value instanceof Date) {
|
|
187
|
-
return value.toISOString()
|
|
194
|
+
return validDate(value).toISOString()
|
|
188
195
|
}
|
|
189
196
|
const raw = expectString(value, "instant").trim()
|
|
190
197
|
if (!/[zZ]|[+-]\d{2}:\d{2}$/.test(raw)) {
|
package/src/internal/scalar.ts
CHANGED
|
@@ -143,7 +143,12 @@ export interface DriverValueMapping {
|
|
|
143
143
|
readonly jsonSelectSql?: (sql: string, dbType: DbType.Any) => string
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
export type DriverValueMappings = Readonly<Record<string, DriverValueMapping
|
|
146
|
+
export type DriverValueMappings = Readonly<Partial<Record<string, DriverValueMapping>>>
|
|
147
|
+
|
|
148
|
+
export type DriverValueMappingsFor<
|
|
149
|
+
Kind extends string,
|
|
150
|
+
Family extends string
|
|
151
|
+
> = Readonly<Partial<Record<Kind | Family | RuntimeTag, DriverValueMapping>>>
|
|
147
152
|
|
|
148
153
|
/** Canonical static metadata stored on an expression. */
|
|
149
154
|
export interface State<
|
|
@@ -1,64 +1,7 @@
|
|
|
1
|
-
import * as VariantSchema from "@effect/experimental/VariantSchema";
|
|
2
1
|
import type * as Brand from "effect/Brand";
|
|
3
2
|
import * as Schema from "effect/Schema";
|
|
4
3
|
import { type AnyColumnDefinition, type HasDefault, type InsertType, type IsGenerated, type IsNullable, type SelectType, type UpdateType } from "./column-state.js";
|
|
5
|
-
|
|
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
|
-
};
|
|
4
|
+
export type TableSchemaVariant = "select" | "insert" | "update";
|
|
62
5
|
/** Normalized field map used by table definitions. */
|
|
63
6
|
export type TableFieldMap = Record<string, AnyColumnDefinition>;
|
|
64
7
|
type GeneratedKeys<Fields extends TableFieldMap> = {
|
|
@@ -91,15 +34,23 @@ export type InsertRow<TableName extends string, Fields extends TableFieldMap> =
|
|
|
91
34
|
export type UpdateRow<TableName extends string, Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Simplify<Partial<{
|
|
92
35
|
[K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>;
|
|
93
36
|
}>>;
|
|
37
|
+
type SchemaOfVariant<Variant extends TableSchemaVariant, TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string> = Variant extends "select" ? Schema.Schema<SelectRow<TableName, Fields>> : Variant extends "insert" ? Schema.Schema<InsertRow<TableName, Fields>> : Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>;
|
|
38
|
+
export declare const deriveSchema: <Variant extends TableSchemaVariant, TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(variant: Variant, tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns>;
|
|
39
|
+
export declare const deriveSelectSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Schema<SelectRow<TableName, Fields>>;
|
|
40
|
+
export declare const deriveInsertSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Schema<InsertRow<TableName, Fields>>;
|
|
41
|
+
export declare const deriveUpdateSchema: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>;
|
|
94
42
|
/**
|
|
95
43
|
* Derives the `select`, `insert`, and `update` schemas for a table.
|
|
96
44
|
*
|
|
97
45
|
* This is the central place where the column capability flags are turned into
|
|
98
46
|
* real runtime schemas.
|
|
47
|
+
*
|
|
48
|
+
* @deprecated Prefer `deriveSelectSchema`, `deriveInsertSchema`, and
|
|
49
|
+
* `deriveUpdateSchema` so individual variants are derived lazily.
|
|
99
50
|
*/
|
|
100
51
|
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<
|
|
102
|
-
readonly insert: Schema.Schema<
|
|
103
|
-
readonly update: Schema.Schema<
|
|
52
|
+
readonly select: Schema.Schema<SelectRow<TableName, Fields>>;
|
|
53
|
+
readonly insert: Schema.Schema<InsertRow<TableName, Fields>>;
|
|
54
|
+
readonly update: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>;
|
|
104
55
|
};
|
|
105
56
|
export {};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as VariantSchema from "@effect/experimental/VariantSchema"
|
|
2
1
|
import type * as Brand from "effect/Brand"
|
|
3
2
|
import * as Schema from "effect/Schema"
|
|
4
3
|
|
|
@@ -12,13 +11,7 @@ import {
|
|
|
12
11
|
type UpdateType
|
|
13
12
|
} from "./column-state.js"
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
export const TableSchema = VariantSchema.make({
|
|
17
|
-
variants: ["select", "insert", "update"] as const,
|
|
18
|
-
defaultVariant: "select"
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
type Variants = "select" | "insert" | "update"
|
|
14
|
+
export type TableSchemaVariant = "select" | "insert" | "update"
|
|
22
15
|
|
|
23
16
|
/** Normalized field map used by table definitions. */
|
|
24
17
|
export type TableFieldMap = Record<string, AnyColumnDefinition>
|
|
@@ -153,11 +146,95 @@ const updateSchema = (
|
|
|
153
146
|
return Schema.optional(base)
|
|
154
147
|
}
|
|
155
148
|
|
|
149
|
+
type SchemaOfVariant<
|
|
150
|
+
Variant extends TableSchemaVariant,
|
|
151
|
+
TableName extends string,
|
|
152
|
+
Fields extends TableFieldMap,
|
|
153
|
+
PrimaryKeyColumns extends keyof Fields & string
|
|
154
|
+
> = Variant extends "select" ? Schema.Schema<SelectRow<TableName, Fields>>
|
|
155
|
+
: Variant extends "insert" ? Schema.Schema<InsertRow<TableName, Fields>>
|
|
156
|
+
: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
|
|
157
|
+
|
|
158
|
+
const fieldSchemaForVariant = (
|
|
159
|
+
variant: TableSchemaVariant,
|
|
160
|
+
column: AnyColumnDefinition,
|
|
161
|
+
tableName: string,
|
|
162
|
+
columnName: string,
|
|
163
|
+
primaryKeySet: ReadonlySet<string>
|
|
164
|
+
): any | undefined => {
|
|
165
|
+
switch (variant) {
|
|
166
|
+
case "select":
|
|
167
|
+
return selectSchema(column, tableName, columnName)
|
|
168
|
+
case "insert":
|
|
169
|
+
return insertSchema(column, tableName, columnName)
|
|
170
|
+
case "update":
|
|
171
|
+
return updateSchema(column, tableName, columnName, primaryKeySet.has(columnName))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export const deriveSchema = <
|
|
176
|
+
Variant extends TableSchemaVariant,
|
|
177
|
+
TableName extends string,
|
|
178
|
+
Fields extends TableFieldMap,
|
|
179
|
+
PrimaryKeyColumns extends keyof Fields & string
|
|
180
|
+
>(
|
|
181
|
+
variant: Variant,
|
|
182
|
+
tableName: TableName,
|
|
183
|
+
fields: Fields,
|
|
184
|
+
primaryKeyColumns: readonly PrimaryKeyColumns[]
|
|
185
|
+
): SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns> => {
|
|
186
|
+
const primaryKeySet = new Set<string>(primaryKeyColumns)
|
|
187
|
+
const structFields: Record<string, any> = {}
|
|
188
|
+
for (const [key, column] of Object.entries(fields)) {
|
|
189
|
+
const schema = fieldSchemaForVariant(variant, column, tableName, key, primaryKeySet)
|
|
190
|
+
if (schema !== undefined) {
|
|
191
|
+
structFields[key] = schema
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return Schema.Struct(structFields) as unknown as SchemaOfVariant<Variant, TableName, Fields, PrimaryKeyColumns>
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export const deriveSelectSchema = <
|
|
198
|
+
TableName extends string,
|
|
199
|
+
Fields extends TableFieldMap,
|
|
200
|
+
PrimaryKeyColumns extends keyof Fields & string
|
|
201
|
+
>(
|
|
202
|
+
tableName: TableName,
|
|
203
|
+
fields: Fields,
|
|
204
|
+
primaryKeyColumns: readonly PrimaryKeyColumns[]
|
|
205
|
+
): Schema.Schema<SelectRow<TableName, Fields>> =>
|
|
206
|
+
deriveSchema("select", tableName, fields, primaryKeyColumns)
|
|
207
|
+
|
|
208
|
+
export const deriveInsertSchema = <
|
|
209
|
+
TableName extends string,
|
|
210
|
+
Fields extends TableFieldMap,
|
|
211
|
+
PrimaryKeyColumns extends keyof Fields & string
|
|
212
|
+
>(
|
|
213
|
+
tableName: TableName,
|
|
214
|
+
fields: Fields,
|
|
215
|
+
primaryKeyColumns: readonly PrimaryKeyColumns[]
|
|
216
|
+
): Schema.Schema<InsertRow<TableName, Fields>> =>
|
|
217
|
+
deriveSchema("insert", tableName, fields, primaryKeyColumns)
|
|
218
|
+
|
|
219
|
+
export const deriveUpdateSchema = <
|
|
220
|
+
TableName extends string,
|
|
221
|
+
Fields extends TableFieldMap,
|
|
222
|
+
PrimaryKeyColumns extends keyof Fields & string
|
|
223
|
+
>(
|
|
224
|
+
tableName: TableName,
|
|
225
|
+
fields: Fields,
|
|
226
|
+
primaryKeyColumns: readonly PrimaryKeyColumns[]
|
|
227
|
+
): Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>> =>
|
|
228
|
+
deriveSchema("update", tableName, fields, primaryKeyColumns)
|
|
229
|
+
|
|
156
230
|
/**
|
|
157
231
|
* Derives the `select`, `insert`, and `update` schemas for a table.
|
|
158
232
|
*
|
|
159
233
|
* This is the central place where the column capability flags are turned into
|
|
160
234
|
* real runtime schemas.
|
|
235
|
+
*
|
|
236
|
+
* @deprecated Prefer `deriveSelectSchema`, `deriveInsertSchema`, and
|
|
237
|
+
* `deriveUpdateSchema` so individual variants are derived lazily.
|
|
161
238
|
*/
|
|
162
239
|
export const deriveSchemas = <
|
|
163
240
|
TableName extends string,
|
|
@@ -171,33 +248,8 @@ export const deriveSchemas = <
|
|
|
171
248
|
readonly select: Schema.Schema<SelectRow<TableName, Fields>>
|
|
172
249
|
readonly insert: Schema.Schema<InsertRow<TableName, Fields>>
|
|
173
250
|
readonly update: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
|
|
174
|
-
} => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
select: selectSchema(column, tableName, key),
|
|
180
|
-
insert: undefined,
|
|
181
|
-
update: undefined
|
|
182
|
-
}
|
|
183
|
-
const insert = insertSchema(column, tableName, key)
|
|
184
|
-
const update = updateSchema(column, tableName, key, primaryKeySet.has(key))
|
|
185
|
-
if (insert !== undefined) {
|
|
186
|
-
config.insert = insert
|
|
187
|
-
} else {
|
|
188
|
-
delete config.insert
|
|
189
|
-
}
|
|
190
|
-
if (update !== undefined) {
|
|
191
|
-
config.update = update
|
|
192
|
-
} else {
|
|
193
|
-
delete config.update
|
|
194
|
-
}
|
|
195
|
-
variants[key] = TableSchema.Field(config)
|
|
196
|
-
}
|
|
197
|
-
const struct = TableSchema.Struct(variants as any)
|
|
198
|
-
return {
|
|
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>>
|
|
202
|
-
}
|
|
203
|
-
}
|
|
251
|
+
} => ({
|
|
252
|
+
select: deriveSelectSchema(tableName, fields, primaryKeyColumns),
|
|
253
|
+
insert: deriveInsertSchema(tableName, fields, primaryKeyColumns),
|
|
254
|
+
update: deriveUpdateSchema(tableName, fields, primaryKeyColumns)
|
|
255
|
+
})
|
|
@@ -6,7 +6,7 @@ export const TypeId: unique symbol = Symbol.for("effect-qb/SchemaExpression")
|
|
|
6
6
|
export type TypeId = typeof TypeId
|
|
7
7
|
|
|
8
8
|
const SchemaExpressionProto = {
|
|
9
|
-
pipe(this:
|
|
9
|
+
pipe(this: Pipeable) {
|
|
10
10
|
return pipeArguments(this, arguments)
|
|
11
11
|
}
|
|
12
12
|
}
|
|
@@ -15,7 +15,7 @@ const attachPipe = <Value extends object>(value: Value): Value => {
|
|
|
15
15
|
Object.defineProperty(value, "pipe", {
|
|
16
16
|
configurable: true,
|
|
17
17
|
writable: true,
|
|
18
|
-
value: function(this:
|
|
18
|
+
value: function(this: Value) {
|
|
19
19
|
return pipeArguments(value, arguments)
|
|
20
20
|
}
|
|
21
21
|
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { RenderedAst, RenderState, SqlDialect } from "./dialect.js"
|
|
2
|
+
import type * as Expression from "./scalar.js"
|
|
3
|
+
import type * as QueryAst from "./query-ast.js"
|
|
4
|
+
|
|
5
|
+
export const renderQueryAst = (
|
|
6
|
+
ast: QueryAst.Ast<Record<string, unknown>, any, QueryAst.QueryStatement>,
|
|
7
|
+
state: RenderState,
|
|
8
|
+
dialect: SqlDialect
|
|
9
|
+
): RenderedAst => {
|
|
10
|
+
return dialect.renderQueryAst(ast, state, dialect)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const renderExpression = (
|
|
14
|
+
expression: Expression.Any,
|
|
15
|
+
state: RenderState,
|
|
16
|
+
dialect: SqlDialect
|
|
17
|
+
): string => {
|
|
18
|
+
return dialect.renderExpression(expression, state, dialect)
|
|
19
|
+
}
|