effect-qb 0.17.0 → 4.0.0-beta.66
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 +7 -0
- package/dist/mysql.js +207 -134
- package/dist/postgres/metadata.js +121 -52
- package/dist/postgres.js +210 -138
- package/dist/sqlite.js +207 -134
- package/package.json +2 -4
- package/src/internal/column-state.d.ts +3 -3
- package/src/internal/column-state.ts +3 -3
- package/src/internal/column.ts +8 -8
- package/src/internal/dialect.ts +1 -1
- package/src/internal/executor.ts +54 -35
- package/src/internal/query.d.ts +1 -1
- package/src/internal/query.ts +1 -1
- package/src/internal/runtime/driver-value-mapping.ts +3 -3
- package/src/internal/runtime/schema.ts +28 -38
- package/src/internal/runtime/value.ts +20 -23
- package/src/internal/scalar.d.ts +1 -1
- package/src/internal/scalar.ts +1 -1
- package/src/internal/schema-derivation.d.ts +12 -61
- package/src/internal/schema-derivation.ts +95 -43
- package/src/internal/table.d.ts +29 -22
- package/src/internal/table.ts +178 -29
- package/src/mysql/column.ts +6 -6
- package/src/mysql/executor.ts +4 -4
- package/src/mysql/function/temporal.ts +1 -1
- package/src/mysql/internal/dsl.ts +23 -17
- package/src/mysql/table.ts +28 -25
- package/src/postgres/column.ts +11 -11
- package/src/postgres/executor.ts +4 -4
- package/src/postgres/function/temporal.ts +1 -1
- package/src/postgres/internal/dsl.ts +23 -17
- package/src/postgres/schema-management.ts +1 -2
- package/src/postgres/table.ts +13 -21
- package/src/sqlite/column.ts +6 -6
- package/src/sqlite/executor.ts +4 -4
- package/src/sqlite/function/temporal.ts +1 -1
- package/src/sqlite/internal/dsl.ts +7 -6
- package/src/sqlite/table.ts +17 -25
|
@@ -70,7 +70,7 @@ export interface ColumnState<Select, Insert, Update, Db extends Expression.DbTyp
|
|
|
70
70
|
export interface ColumnDefinition<Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends Expression.BindingId = never> extends Pipeable, Expression.Scalar<Select, Db, Nullable extends true ? "maybe" : "never", Db["dialect"], "scalar", Dependencies> {
|
|
71
71
|
readonly pipe: Pipeable["pipe"];
|
|
72
72
|
readonly [ColumnTypeId]: ColumnState<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>;
|
|
73
|
-
readonly schema: Schema.Schema<NonNullable<Select
|
|
73
|
+
readonly schema: Schema.Schema<NonNullable<Select>>;
|
|
74
74
|
readonly metadata: {
|
|
75
75
|
readonly dbType: Db;
|
|
76
76
|
readonly nullable: Nullable;
|
|
@@ -111,7 +111,7 @@ export type AnyColumnDefinition = ColumnDefinition<any, any, any, Expression.DbT
|
|
|
111
111
|
/** Convenience alias for any bound column. */
|
|
112
112
|
export type AnyBoundColumn = BoundColumn<any, any, any, Expression.DbType.Any, boolean, boolean, boolean, boolean, boolean, any, string, string, string>;
|
|
113
113
|
/** Constructs a runtime column-definition object from schema and metadata. */
|
|
114
|
-
export declare const makeColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(schema: Schema.Schema<NonNullable<Select
|
|
114
|
+
export declare const makeColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(schema: Schema.Schema<NonNullable<Select>>, metadata: {
|
|
115
115
|
readonly dbType: Db;
|
|
116
116
|
readonly nullable: Nullable;
|
|
117
117
|
readonly hasDefault: HasDefault;
|
|
@@ -135,7 +135,7 @@ export declare const makeColumnDefinition: <Select, Insert, Update, Db extends E
|
|
|
135
135
|
} | undefined;
|
|
136
136
|
}) => ColumnDefinition<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>;
|
|
137
137
|
export declare const remapColumnDefinition: <Select, Insert, Update, Db extends Expression.DbType.Any, Nullable extends boolean, HasDefault extends boolean, Generated extends boolean, PrimaryKey extends boolean, Unique extends boolean, Ref, Dependencies extends string = never>(column: ColumnDefinition<Select, Insert, Update, Db, Nullable, HasDefault, Generated, PrimaryKey, Unique, Ref, Dependencies>, options?: {
|
|
138
|
-
readonly schema?: Schema.
|
|
138
|
+
readonly schema?: Schema.Top | undefined;
|
|
139
139
|
readonly metadata?: {
|
|
140
140
|
readonly dbType: Db;
|
|
141
141
|
readonly nullable: Nullable;
|
|
@@ -123,7 +123,7 @@ export interface ColumnDefinition<
|
|
|
123
123
|
Ref,
|
|
124
124
|
Dependencies
|
|
125
125
|
>
|
|
126
|
-
readonly schema: Schema.Schema<NonNullable<Select
|
|
126
|
+
readonly schema: Schema.Schema<NonNullable<Select>>
|
|
127
127
|
readonly metadata: {
|
|
128
128
|
readonly dbType: Db
|
|
129
129
|
readonly nullable: Nullable
|
|
@@ -257,7 +257,7 @@ export const makeColumnDefinition = <
|
|
|
257
257
|
Ref,
|
|
258
258
|
Dependencies extends Expression.BindingId = never
|
|
259
259
|
>(
|
|
260
|
-
schema: Schema.Schema<NonNullable<Select
|
|
260
|
+
schema: Schema.Schema<NonNullable<Select>>,
|
|
261
261
|
metadata: ColumnDefinition<
|
|
262
262
|
Select,
|
|
263
263
|
Insert,
|
|
@@ -345,7 +345,7 @@ export const remapColumnDefinition = <
|
|
|
345
345
|
Dependencies
|
|
346
346
|
>,
|
|
347
347
|
options: {
|
|
348
|
-
readonly schema?: Schema.
|
|
348
|
+
readonly schema?: Schema.Top
|
|
349
349
|
readonly metadata?: ColumnDefinition<
|
|
350
350
|
Select,
|
|
351
351
|
Insert,
|
package/src/internal/column.ts
CHANGED
|
@@ -225,21 +225,21 @@ type ForeignKeyOptions<Target extends AnyBoundColumn> = {
|
|
|
225
225
|
|
|
226
226
|
type SchemaCompatibleColumn<
|
|
227
227
|
Column extends AnyColumnDefinition,
|
|
228
|
-
SchemaType extends Schema.
|
|
229
|
-
> = [BaseSelectType<Column>] extends [Schema.
|
|
228
|
+
SchemaType extends Schema.Top
|
|
229
|
+
> = [BaseSelectType<Column>] extends [Schema.Codec.Encoded<SchemaType>]
|
|
230
230
|
? Column
|
|
231
231
|
: never
|
|
232
232
|
|
|
233
233
|
type ColumnSchemaOutput<
|
|
234
234
|
Column extends AnyColumnDefinition,
|
|
235
|
-
SchemaType extends Schema.
|
|
235
|
+
SchemaType extends Schema.Top
|
|
236
236
|
> = IsNullable<Column> extends true
|
|
237
237
|
? Schema.Schema.Type<SchemaType> | null
|
|
238
238
|
: Schema.Schema.Type<SchemaType>
|
|
239
239
|
|
|
240
240
|
type ColumnWithSchema<
|
|
241
241
|
Column extends AnyColumnDefinition,
|
|
242
|
-
SchemaType extends Schema.
|
|
242
|
+
SchemaType extends Schema.Top
|
|
243
243
|
> = ColumnDefinition<
|
|
244
244
|
ColumnSchemaOutput<Column, SchemaType>,
|
|
245
245
|
ColumnSchemaOutput<Column, SchemaType>,
|
|
@@ -376,7 +376,7 @@ const isColumnDefinitionValue = (value: unknown): value is AnyColumnDefinition =
|
|
|
376
376
|
typeof value === "object" && value !== null && ColumnTypeId in value
|
|
377
377
|
|
|
378
378
|
const primitive = <Type, Db extends Expression.DbType.Any>(
|
|
379
|
-
schema: Schema.Schema<Type
|
|
379
|
+
schema: Schema.Schema<Type>,
|
|
380
380
|
dbType: Db
|
|
381
381
|
): ColumnDefinition<Type, Type, Type, Db, false, false, false, false, false, undefined> =>
|
|
382
382
|
makeColumnDefinition(schema as Schema.Schema<NonNullable<Type>>, {
|
|
@@ -401,7 +401,7 @@ type ColumnModule<
|
|
|
401
401
|
JsonKind extends string
|
|
402
402
|
> = {
|
|
403
403
|
readonly custom: <
|
|
404
|
-
SchemaType extends Schema.
|
|
404
|
+
SchemaType extends Schema.Top,
|
|
405
405
|
Db extends Expression.DbType.Any
|
|
406
406
|
>(
|
|
407
407
|
schema: SchemaType,
|
|
@@ -425,7 +425,7 @@ type ColumnModule<
|
|
|
425
425
|
readonly boolean: () => ColumnDefinition<boolean, boolean, boolean, Expression.DbType.Base<Dialect, BooleanKind>, false, false, false, false, false, undefined>
|
|
426
426
|
readonly date: () => ColumnDefinition<LocalDateString, LocalDateString, LocalDateString, Expression.DbType.Base<Dialect, DateKind>, false, false, false, false, false, undefined>
|
|
427
427
|
readonly timestamp: () => ColumnDefinition<LocalDateTimeString, LocalDateTimeString, LocalDateTimeString, Expression.DbType.Base<Dialect, TimestampKind>, false, false, false, false, false, undefined>
|
|
428
|
-
readonly json: <SchemaType extends Schema.
|
|
428
|
+
readonly json: <SchemaType extends Schema.Top>(
|
|
429
429
|
schema: SchemaType
|
|
430
430
|
) => ColumnDefinition<
|
|
431
431
|
Schema.Schema.Type<SchemaType>,
|
|
@@ -442,7 +442,7 @@ type ColumnModule<
|
|
|
442
442
|
}
|
|
443
443
|
|
|
444
444
|
/** Replaces a column's runtime schema while preserving its SQL type metadata. */
|
|
445
|
-
export const schema = <SchemaType extends Schema.
|
|
445
|
+
export const schema = <SchemaType extends Schema.Top>(nextSchema: SchemaType) =>
|
|
446
446
|
<Column extends AnyColumnDefinition>(
|
|
447
447
|
column: SchemaCompatibleColumn<Column, SchemaType>
|
|
448
448
|
): ColumnWithSchema<Column, SchemaType> =>
|
package/src/internal/dialect.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface RenderState {
|
|
|
23
23
|
|
|
24
24
|
export interface RenderValueContext {
|
|
25
25
|
readonly dbType?: Expression.DbType.Any
|
|
26
|
-
readonly runtimeSchema?: Schema.
|
|
26
|
+
readonly runtimeSchema?: Schema.Top
|
|
27
27
|
readonly driverValueMapping?: Expression.DriverValueMapping
|
|
28
28
|
}
|
|
29
29
|
|
package/src/internal/executor.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as Chunk from "effect/Chunk"
|
|
2
2
|
import * as Effect from "effect/Effect"
|
|
3
|
+
import * as Exit from "effect/Exit"
|
|
3
4
|
import * as Option from "effect/Option"
|
|
4
5
|
import * as Schema from "effect/Schema"
|
|
5
|
-
import * as SqlClient from "
|
|
6
|
-
import * as SqlError from "
|
|
6
|
+
import * as SqlClient from "effect/unstable/sql/SqlClient"
|
|
7
|
+
import * as SqlError from "effect/unstable/sql/SqlError"
|
|
7
8
|
import * as Stream from "effect/Stream"
|
|
8
9
|
|
|
9
10
|
import * as Expression from "./scalar.js"
|
|
@@ -44,6 +45,10 @@ export interface RowDecodeError {
|
|
|
44
45
|
readonly normalized?: unknown
|
|
45
46
|
readonly stage: "normalize" | "schema"
|
|
46
47
|
readonly cause: unknown
|
|
48
|
+
readonly schemaError?: {
|
|
49
|
+
readonly message: string
|
|
50
|
+
readonly issue: unknown
|
|
51
|
+
}
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
/**
|
|
@@ -183,26 +188,35 @@ const makeRowDecodeError = (
|
|
|
183
188
|
stage: RowDecodeError["stage"],
|
|
184
189
|
cause: unknown,
|
|
185
190
|
normalized?: unknown
|
|
186
|
-
): RowDecodeError =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
191
|
+
): RowDecodeError => {
|
|
192
|
+
const schemaError = Schema.isSchemaError(cause)
|
|
193
|
+
? {
|
|
194
|
+
message: cause.message,
|
|
195
|
+
issue: cause.issue
|
|
196
|
+
}
|
|
197
|
+
: undefined
|
|
198
|
+
return {
|
|
199
|
+
_tag: "RowDecodeError",
|
|
200
|
+
message: stage === "normalize"
|
|
201
|
+
? `Failed to normalize projection '${projection.alias}'`
|
|
202
|
+
: `Failed to decode projection '${projection.alias}' against its runtime schema`,
|
|
203
|
+
dialect: rendered.dialect,
|
|
204
|
+
query: {
|
|
205
|
+
sql: rendered.sql,
|
|
206
|
+
params: rendered.params
|
|
207
|
+
},
|
|
208
|
+
projection: {
|
|
209
|
+
alias: projection.alias,
|
|
210
|
+
path: projection.path
|
|
211
|
+
},
|
|
212
|
+
dbType: expression[Expression.TypeId].dbType,
|
|
213
|
+
raw,
|
|
214
|
+
normalized,
|
|
215
|
+
stage,
|
|
216
|
+
cause,
|
|
217
|
+
...(schemaError === undefined ? {} : { schemaError })
|
|
218
|
+
}
|
|
219
|
+
}
|
|
206
220
|
|
|
207
221
|
const hasOptionalSourceDependency = (
|
|
208
222
|
expression: Expression.Any,
|
|
@@ -249,7 +263,7 @@ const dbTypeAllowsTopLevelJsonNull = (
|
|
|
249
263
|
}
|
|
250
264
|
|
|
251
265
|
const schemaAcceptsNull = (
|
|
252
|
-
schema: Schema.
|
|
266
|
+
schema: Schema.Top | undefined
|
|
253
267
|
): boolean =>
|
|
254
268
|
schema !== undefined && (Schema.is(schema) as (value: unknown) => boolean)(null)
|
|
255
269
|
|
|
@@ -325,15 +339,20 @@ const decodeProjectionValue = (
|
|
|
325
339
|
return normalized
|
|
326
340
|
}
|
|
327
341
|
|
|
328
|
-
if ((Schema.is(schema as Schema.
|
|
342
|
+
if ((Schema.is(schema as Schema.Top) as (value: unknown) => boolean)(normalized)) {
|
|
329
343
|
return normalized
|
|
330
344
|
}
|
|
331
345
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
throw makeRowDecodeError(rendered, projection, expression, raw, "schema", cause, normalized)
|
|
346
|
+
const decoded = (Schema.decodeUnknownExit as any)(schema)(normalized)
|
|
347
|
+
if (Exit.isSuccess(decoded)) {
|
|
348
|
+
return decoded.value
|
|
336
349
|
}
|
|
350
|
+
|
|
351
|
+
const cause = Option.match(Exit.findErrorOption(decoded), {
|
|
352
|
+
onNone: () => decoded.cause,
|
|
353
|
+
onSome: (schemaError) => schemaError
|
|
354
|
+
})
|
|
355
|
+
throw makeRowDecodeError(rendered, projection, expression, raw, "schema", cause, normalized)
|
|
337
356
|
}
|
|
338
357
|
|
|
339
358
|
export const makeRowDecoder = (
|
|
@@ -390,7 +409,7 @@ export const decodeChunk = (
|
|
|
390
409
|
} = {}
|
|
391
410
|
): Chunk.Chunk<any> => {
|
|
392
411
|
const decodeRow = makeRowDecoder(rendered, plan, options)
|
|
393
|
-
return Chunk.
|
|
412
|
+
return Chunk.fromIterable(Chunk.toReadonlyArray(rows).map((row) => decodeRow(row)))
|
|
394
413
|
}
|
|
395
414
|
|
|
396
415
|
export const decodeRows = (
|
|
@@ -520,9 +539,9 @@ export const fromDriver = <
|
|
|
520
539
|
},
|
|
521
540
|
stream(plan: any) {
|
|
522
541
|
const rendered = renderer.render(plan) as Renderer.RenderedQuery<any, Dialect>
|
|
523
|
-
return Stream.
|
|
542
|
+
return Stream.mapArray(
|
|
524
543
|
sqlDriver.stream(rendered),
|
|
525
|
-
(rows) =>
|
|
544
|
+
(rows) => remapRows<any>(rendered, rows) as never
|
|
526
545
|
)
|
|
527
546
|
}
|
|
528
547
|
}
|
|
@@ -532,10 +551,10 @@ export const fromDriver = <
|
|
|
532
551
|
export const streamFromSqlClient = <Dialect extends string>(
|
|
533
552
|
query: Renderer.RenderedQuery<any, Dialect>
|
|
534
553
|
): Stream.Stream<FlatRow, SqlError.SqlError, SqlClient.SqlClient> =>
|
|
535
|
-
Stream.
|
|
554
|
+
Stream.unwrap(
|
|
536
555
|
Effect.flatMap(SqlClient.SqlClient, (sql) =>
|
|
537
556
|
Effect.flatMap(
|
|
538
|
-
Effect.serviceOption(
|
|
557
|
+
Effect.serviceOption(sql.transactionService),
|
|
539
558
|
Option.match({
|
|
540
559
|
onNone: () => sql.reserve,
|
|
541
560
|
onSome: ([connection]) => Effect.succeed(connection)
|
|
@@ -556,7 +575,7 @@ export const fromSqlClient = <Dialect extends string>(
|
|
|
556
575
|
stream: (query) => streamFromSqlClient(query)
|
|
557
576
|
}))
|
|
558
577
|
|
|
559
|
-
/** Runs an effect within the ambient
|
|
578
|
+
/** Runs an effect within the ambient `effect/unstable/sql` transaction service. */
|
|
560
579
|
export const withTransaction = <A, E, R>(
|
|
561
580
|
effect: Effect.Effect<A, E, R>
|
|
562
581
|
): Effect.Effect<A, E | SqlError.SqlError, R | SqlClient.SqlClient> =>
|
|
@@ -565,7 +584,7 @@ export const withTransaction = <A, E, R>(
|
|
|
565
584
|
/**
|
|
566
585
|
* Runs an effect in a nested transaction scope.
|
|
567
586
|
*
|
|
568
|
-
* When the ambient
|
|
587
|
+
* When the ambient `effect/unstable/sql` client is already inside a transaction, the
|
|
569
588
|
* underlying client implementation uses a savepoint.
|
|
570
589
|
*/
|
|
571
590
|
export const withSavepoint = <A, E, R>(
|
package/src/internal/query.d.ts
CHANGED
|
@@ -743,7 +743,7 @@ export declare const mergeManyDependencies: <Values extends readonly Expression.
|
|
|
743
743
|
export declare const makeExpression: <Runtime, Db extends Expression.DbType.Any, Nullable extends Expression.Nullability, Dialect extends string, Kind extends Expression.ScalarKind, Deps extends string = never, Ast extends ExpressionAst.Any = ExpressionAst.Any, GroupKey extends string = GroupingKeyOfAst<Ast>>(state: {
|
|
744
744
|
readonly runtime: Runtime;
|
|
745
745
|
readonly dbType: Db;
|
|
746
|
-
readonly runtimeSchema?: Schema.
|
|
746
|
+
readonly runtimeSchema?: Schema.Top | undefined;
|
|
747
747
|
readonly nullability: Nullable;
|
|
748
748
|
readonly dialect: Dialect;
|
|
749
749
|
readonly kind?: Kind | undefined;
|
package/src/internal/query.ts
CHANGED
|
@@ -2412,7 +2412,7 @@ export const makeExpression = <
|
|
|
2412
2412
|
state: {
|
|
2413
2413
|
readonly runtime: Runtime
|
|
2414
2414
|
readonly dbType: Db
|
|
2415
|
-
readonly runtimeSchema?: Schema.
|
|
2415
|
+
readonly runtimeSchema?: Schema.Top
|
|
2416
2416
|
readonly driverValueMapping?: Expression.DriverValueMapping
|
|
2417
2417
|
readonly nullability: Nullable
|
|
2418
2418
|
readonly dialect: Dialect
|
|
@@ -9,7 +9,7 @@ export type DriverValueMappings = Expression.DriverValueMappings
|
|
|
9
9
|
export interface DriverValueContext {
|
|
10
10
|
readonly dialect?: string
|
|
11
11
|
readonly dbType?: Expression.DbType.Any
|
|
12
|
-
readonly runtimeSchema?: Schema.
|
|
12
|
+
readonly runtimeSchema?: Schema.Top
|
|
13
13
|
readonly driverValueMapping?: DriverValueMapping
|
|
14
14
|
readonly valueMappings?: DriverValueMappings
|
|
15
15
|
}
|
|
@@ -99,13 +99,13 @@ const isJsonDbType = (dbType: Expression.DbType.Any | undefined): boolean => {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
const schemaAccepts = (
|
|
102
|
-
schema: Schema.
|
|
102
|
+
schema: Schema.Top | undefined,
|
|
103
103
|
value: unknown
|
|
104
104
|
): boolean =>
|
|
105
105
|
schema !== undefined && (Schema.is(schema) as (candidate: unknown) => boolean)(value)
|
|
106
106
|
|
|
107
107
|
const encodeWithSchema = (
|
|
108
|
-
schema: Schema.
|
|
108
|
+
schema: Schema.Top | undefined,
|
|
109
109
|
value: unknown
|
|
110
110
|
): { readonly value: unknown; readonly encoded: boolean } => {
|
|
111
111
|
if (schema === undefined) {
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
} from "./value.js"
|
|
28
28
|
import type { RuntimeTag } from "../datatypes/shape.js"
|
|
29
29
|
|
|
30
|
-
export type RuntimeSchema = Schema.
|
|
30
|
+
export type RuntimeSchema = Schema.Top
|
|
31
31
|
|
|
32
32
|
type SchemaContext = {
|
|
33
33
|
readonly assumptions: PredicateFormula
|
|
@@ -38,7 +38,7 @@ const schemaCache = new WeakMap<Expression.Any, RuntimeSchema | undefined>()
|
|
|
38
38
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
39
39
|
typeof value === "object" && value !== null && !Array.isArray(value)
|
|
40
40
|
|
|
41
|
-
const FiniteNumberSchema = Schema.Number.
|
|
41
|
+
const FiniteNumberSchema = Schema.Number.check(Schema.isFinite())
|
|
42
42
|
|
|
43
43
|
const runtimeSchemaForTag = (tag: RuntimeTag): RuntimeSchema | undefined => {
|
|
44
44
|
switch (tag) {
|
|
@@ -67,14 +67,11 @@ const runtimeSchemaForTag = (tag: RuntimeTag): RuntimeSchema | undefined => {
|
|
|
67
67
|
case "decimalString":
|
|
68
68
|
return DecimalStringSchema
|
|
69
69
|
case "bytes":
|
|
70
|
-
return Schema.
|
|
70
|
+
return Schema.Uint8Array
|
|
71
71
|
case "array":
|
|
72
72
|
return Schema.Array(Schema.Unknown)
|
|
73
73
|
case "record":
|
|
74
|
-
return Schema.Record(
|
|
75
|
-
key: Schema.String,
|
|
76
|
-
value: Schema.Unknown
|
|
77
|
-
})
|
|
74
|
+
return Schema.Record(Schema.String, Schema.Unknown)
|
|
78
75
|
case "null":
|
|
79
76
|
return Schema.Null
|
|
80
77
|
case "unknown":
|
|
@@ -114,7 +111,7 @@ export const runtimeSchemaForDbType = (
|
|
|
114
111
|
}
|
|
115
112
|
|
|
116
113
|
const makeSchemaFromAst = (ast: SchemaAST.AST): RuntimeSchema =>
|
|
117
|
-
Schema.make(ast)
|
|
114
|
+
Schema.make<RuntimeSchema>(ast)
|
|
118
115
|
|
|
119
116
|
const unionAst = (asts: ReadonlyArray<SchemaAST.AST>): SchemaAST.AST | undefined => {
|
|
120
117
|
if (asts.length === 0) {
|
|
@@ -123,7 +120,7 @@ const unionAst = (asts: ReadonlyArray<SchemaAST.AST>): SchemaAST.AST | undefined
|
|
|
123
120
|
if (asts.length === 1) {
|
|
124
121
|
return asts[0]
|
|
125
122
|
}
|
|
126
|
-
return SchemaAST.Union
|
|
123
|
+
return new SchemaAST.Union(asts, "anyOf")
|
|
127
124
|
}
|
|
128
125
|
|
|
129
126
|
const propertyAstOf = (
|
|
@@ -131,18 +128,14 @@ const propertyAstOf = (
|
|
|
131
128
|
key: string
|
|
132
129
|
): SchemaAST.AST | undefined => {
|
|
133
130
|
switch (ast._tag) {
|
|
134
|
-
case "Transformation":
|
|
135
|
-
return propertyAstOf(SchemaAST.typeAST(ast), key)
|
|
136
|
-
case "Refinement":
|
|
137
|
-
return propertyAstOf(ast.from, key)
|
|
138
131
|
case "Suspend":
|
|
139
|
-
return propertyAstOf(ast.
|
|
140
|
-
case "
|
|
132
|
+
return propertyAstOf(ast.thunk(), key)
|
|
133
|
+
case "Objects": {
|
|
141
134
|
const property = ast.propertySignatures.find((entry) => entry.name === key)
|
|
142
135
|
if (property !== undefined) {
|
|
143
136
|
return property.type
|
|
144
137
|
}
|
|
145
|
-
const index = ast.indexSignatures.find((entry) => entry.parameter._tag === "
|
|
138
|
+
const index = ast.indexSignatures.find((entry) => entry.parameter._tag === "String")
|
|
146
139
|
return index?.type
|
|
147
140
|
}
|
|
148
141
|
case "Union": {
|
|
@@ -162,21 +155,17 @@ const numberAstOf = (
|
|
|
162
155
|
index: number
|
|
163
156
|
): SchemaAST.AST | undefined => {
|
|
164
157
|
switch (ast._tag) {
|
|
165
|
-
case "Transformation":
|
|
166
|
-
return numberAstOf(SchemaAST.typeAST(ast), index)
|
|
167
|
-
case "Refinement":
|
|
168
|
-
return numberAstOf(ast.from, index)
|
|
169
158
|
case "Suspend":
|
|
170
|
-
return numberAstOf(ast.
|
|
171
|
-
case "
|
|
159
|
+
return numberAstOf(ast.thunk(), index)
|
|
160
|
+
case "Arrays": {
|
|
172
161
|
const element = ast.elements[index]
|
|
173
162
|
if (element !== undefined) {
|
|
174
|
-
return element
|
|
163
|
+
return element
|
|
175
164
|
}
|
|
176
165
|
if (ast.rest.length === 0) {
|
|
177
166
|
return undefined
|
|
178
167
|
}
|
|
179
|
-
return unionAst(ast.rest
|
|
168
|
+
return unionAst(ast.rest)
|
|
180
169
|
}
|
|
181
170
|
case "Union": {
|
|
182
171
|
const values = ast.types.flatMap((member) => {
|
|
@@ -199,7 +188,9 @@ const schemaAstAtExactJsonPath = (
|
|
|
199
188
|
schema: RuntimeSchema,
|
|
200
189
|
segments: readonly JsonPath.CanonicalSegment[]
|
|
201
190
|
): SchemaAST.AST | undefined => {
|
|
202
|
-
|
|
191
|
+
// JSON path operators return encoded JSON subvalues, so preserve field-level
|
|
192
|
+
// encoding links instead of walking the type-side AST.
|
|
193
|
+
let current: SchemaAST.AST = schema.ast
|
|
203
194
|
for (const segment of segments) {
|
|
204
195
|
if (segment.kind === "key") {
|
|
205
196
|
const property = propertyAstOf(current, segment.key)
|
|
@@ -230,7 +221,7 @@ const unionSchemas = (schemas: ReadonlyArray<RuntimeSchema | undefined>): Runtim
|
|
|
230
221
|
if (resolved.length === 1) {
|
|
231
222
|
return resolved[0]
|
|
232
223
|
}
|
|
233
|
-
return Schema.Union(
|
|
224
|
+
return Schema.Union(resolved)
|
|
234
225
|
}
|
|
235
226
|
|
|
236
227
|
const firstSelectedExpression = (
|
|
@@ -241,24 +232,23 @@ const firstSelectedExpression = (
|
|
|
241
232
|
}
|
|
242
233
|
|
|
243
234
|
const isJsonCompatibleAst = (ast: SchemaAST.AST): boolean => {
|
|
235
|
+
ast = SchemaAST.toType(ast)
|
|
244
236
|
switch (ast._tag) {
|
|
245
|
-
case "
|
|
246
|
-
case "
|
|
247
|
-
case "
|
|
248
|
-
case "
|
|
249
|
-
case "
|
|
237
|
+
case "String":
|
|
238
|
+
case "Number":
|
|
239
|
+
case "Boolean":
|
|
240
|
+
case "Null":
|
|
241
|
+
case "Arrays":
|
|
242
|
+
case "Objects":
|
|
250
243
|
return true
|
|
251
244
|
case "Literal":
|
|
252
|
-
return ast.literal ===
|
|
253
|
-
typeof ast.literal === "string" ||
|
|
245
|
+
return typeof ast.literal === "string" ||
|
|
254
246
|
typeof ast.literal === "number" ||
|
|
255
247
|
typeof ast.literal === "boolean"
|
|
256
248
|
case "Union":
|
|
257
249
|
return ast.types.every(isJsonCompatibleAst)
|
|
258
|
-
case "Transformation":
|
|
259
|
-
return isJsonCompatibleAst(SchemaAST.typeAST(ast))
|
|
260
250
|
case "Suspend":
|
|
261
|
-
return isJsonCompatibleAst(ast.
|
|
251
|
+
return isJsonCompatibleAst(ast.thunk())
|
|
262
252
|
default:
|
|
263
253
|
return false
|
|
264
254
|
}
|
|
@@ -268,7 +258,7 @@ const jsonCompatibleSchema = (schema: RuntimeSchema | undefined): RuntimeSchema
|
|
|
268
258
|
if (schema === undefined) {
|
|
269
259
|
return undefined
|
|
270
260
|
}
|
|
271
|
-
const ast = SchemaAST.
|
|
261
|
+
const ast = SchemaAST.toType(schema.ast)
|
|
272
262
|
return isJsonCompatibleAst(ast) ? schema : JsonValueSchema
|
|
273
263
|
}
|
|
274
264
|
|
|
@@ -283,7 +273,7 @@ const buildStructSchema = (
|
|
|
283
273
|
}
|
|
284
274
|
|
|
285
275
|
const buildTupleSchema = (values: readonly Expression.Any[], context?: SchemaContext): RuntimeSchema =>
|
|
286
|
-
Schema.Tuple(
|
|
276
|
+
Schema.Tuple(values.map((value) => expressionRuntimeSchema(value, context) ?? JsonValueSchema))
|
|
287
277
|
|
|
288
278
|
const deriveCaseSchema = (
|
|
289
279
|
ast: ExpressionAst.CaseNode,
|
|
@@ -19,7 +19,7 @@ const brandString = <BrandName extends string>(
|
|
|
19
19
|
brand: BrandName
|
|
20
20
|
): Schema.Schema<string & Brand.Brand<BrandName>> =>
|
|
21
21
|
Schema.String.pipe(
|
|
22
|
-
Schema.
|
|
22
|
+
Schema.check(Schema.isPattern(pattern)),
|
|
23
23
|
Schema.brand(brand)
|
|
24
24
|
) as unknown as Schema.Schema<string & Brand.Brand<BrandName>>
|
|
25
25
|
|
|
@@ -100,32 +100,32 @@ export const isValidInstantString = (value: string): boolean => {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
export const LocalDateStringSchema = Schema.String.pipe(
|
|
103
|
-
Schema.
|
|
104
|
-
Schema.
|
|
103
|
+
Schema.check(Schema.isPattern(localDatePattern)),
|
|
104
|
+
Schema.check(Schema.makeFilter((value) => isValidLocalDateString(value))),
|
|
105
105
|
Schema.brand("LocalDateString")
|
|
106
106
|
) as unknown as Schema.Schema<LocalDateString>
|
|
107
107
|
|
|
108
108
|
export const LocalTimeStringSchema = Schema.String.pipe(
|
|
109
|
-
Schema.
|
|
110
|
-
Schema.
|
|
109
|
+
Schema.check(Schema.isPattern(localTimePattern)),
|
|
110
|
+
Schema.check(Schema.makeFilter((value) => isValidLocalTimeString(value))),
|
|
111
111
|
Schema.brand("LocalTimeString")
|
|
112
112
|
) as unknown as Schema.Schema<LocalTimeString>
|
|
113
113
|
|
|
114
114
|
export const OffsetTimeStringSchema = Schema.String.pipe(
|
|
115
|
-
Schema.
|
|
116
|
-
Schema.
|
|
115
|
+
Schema.check(Schema.isPattern(offsetTimePattern)),
|
|
116
|
+
Schema.check(Schema.makeFilter((value) => isValidOffsetTimeString(value))),
|
|
117
117
|
Schema.brand("OffsetTimeString")
|
|
118
118
|
) as unknown as Schema.Schema<OffsetTimeString>
|
|
119
119
|
|
|
120
120
|
export const LocalDateTimeStringSchema = Schema.String.pipe(
|
|
121
|
-
Schema.
|
|
122
|
-
Schema.
|
|
121
|
+
Schema.check(Schema.isPattern(localDateTimePattern)),
|
|
122
|
+
Schema.check(Schema.makeFilter((value) => isValidLocalDateTimeString(value))),
|
|
123
123
|
Schema.brand("LocalDateTimeString")
|
|
124
124
|
) as unknown as Schema.Schema<LocalDateTimeString>
|
|
125
125
|
|
|
126
126
|
export const InstantStringSchema = Schema.String.pipe(
|
|
127
|
-
Schema.
|
|
128
|
-
Schema.
|
|
127
|
+
Schema.check(Schema.isPattern(instantPattern)),
|
|
128
|
+
Schema.check(Schema.makeFilter((value) => isValidInstantString(value))),
|
|
129
129
|
Schema.brand("InstantString")
|
|
130
130
|
) as unknown as Schema.Schema<InstantString>
|
|
131
131
|
|
|
@@ -177,32 +177,29 @@ export const isCanonicalDecimalString = (value: string): boolean => {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
export const BigIntStringSchema = Schema.String.pipe(
|
|
180
|
-
Schema.
|
|
180
|
+
Schema.check(Schema.makeFilter((value) => isCanonicalBigIntString(value))),
|
|
181
181
|
Schema.brand("BigIntString")
|
|
182
182
|
) as unknown as Schema.Schema<BigIntString>
|
|
183
183
|
|
|
184
184
|
export const DecimalStringSchema = Schema.String.pipe(
|
|
185
|
-
Schema.
|
|
185
|
+
Schema.check(Schema.makeFilter((value) => isCanonicalDecimalString(value))),
|
|
186
186
|
Schema.brand("DecimalString")
|
|
187
187
|
) as unknown as Schema.Schema<DecimalString>
|
|
188
188
|
|
|
189
189
|
export const JsonValueSchema: Schema.Schema<JsonValue> = Schema.suspend(() =>
|
|
190
|
-
Schema.Union(
|
|
190
|
+
Schema.Union([
|
|
191
191
|
Schema.String,
|
|
192
|
-
Schema.Number.
|
|
192
|
+
Schema.Number.check(Schema.isFinite()),
|
|
193
193
|
Schema.Boolean,
|
|
194
194
|
Schema.Null,
|
|
195
195
|
Schema.Array(JsonValueSchema),
|
|
196
|
-
Schema.Record(
|
|
197
|
-
|
|
198
|
-
value: JsonValueSchema
|
|
199
|
-
})
|
|
200
|
-
)
|
|
196
|
+
Schema.Record(Schema.String, JsonValueSchema)
|
|
197
|
+
])
|
|
201
198
|
)
|
|
202
199
|
|
|
203
|
-
export const JsonPrimitiveSchema: Schema.Schema<JsonPrimitive> = Schema.Union(
|
|
200
|
+
export const JsonPrimitiveSchema: Schema.Schema<JsonPrimitive> = Schema.Union([
|
|
204
201
|
Schema.String,
|
|
205
|
-
Schema.Number.
|
|
202
|
+
Schema.Number.check(Schema.isFinite()),
|
|
206
203
|
Schema.Boolean,
|
|
207
204
|
Schema.Null
|
|
208
|
-
)
|
|
205
|
+
])
|
package/src/internal/scalar.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export declare namespace DbType {
|
|
|
73
73
|
export interface State<Runtime, Db extends DbType.Any, Nullable extends Nullability, Dialect extends string, Kind extends ScalarKind, Deps extends BindingId = never> {
|
|
74
74
|
readonly runtime: Runtime;
|
|
75
75
|
readonly dbType: Db;
|
|
76
|
-
readonly runtimeSchema?: Schema.
|
|
76
|
+
readonly runtimeSchema?: Schema.Top;
|
|
77
77
|
readonly nullability: Nullable;
|
|
78
78
|
readonly dialect: Dialect;
|
|
79
79
|
readonly kind: Kind;
|
package/src/internal/scalar.ts
CHANGED
|
@@ -156,7 +156,7 @@ export interface State<
|
|
|
156
156
|
> {
|
|
157
157
|
readonly runtime: Runtime
|
|
158
158
|
readonly dbType: Db
|
|
159
|
-
readonly runtimeSchema?: Schema.
|
|
159
|
+
readonly runtimeSchema?: Schema.Top
|
|
160
160
|
readonly driverValueMapping?: DriverValueMapping
|
|
161
161
|
readonly nullability: Nullable
|
|
162
162
|
readonly dialect: Dialect
|