effect-qb 0.19.0 → 0.20.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.
Files changed (92) hide show
  1. package/README.md +7 -1
  2. package/dist/index.js +1990 -679
  3. package/dist/mysql.js +1490 -617
  4. package/dist/postgres/metadata.js +1334 -263
  5. package/dist/postgres.js +3376 -2307
  6. package/dist/sqlite.js +1573 -628
  7. package/dist/standard.js +1984 -673
  8. package/package.json +2 -4
  9. package/src/internal/coercion/rules.ts +13 -1
  10. package/src/internal/column-state.d.ts +3 -3
  11. package/src/internal/column-state.ts +13 -12
  12. package/src/internal/column.ts +8 -8
  13. package/src/internal/datatypes/define.ts +5 -0
  14. package/src/internal/datatypes/lookup.ts +67 -18
  15. package/src/internal/datatypes/matrix.ts +903 -0
  16. package/src/internal/datatypes/shape.ts +2 -0
  17. package/src/internal/dialect-renderers/mysql.ts +6 -4
  18. package/src/internal/dialect-renderers/postgres.ts +6 -4
  19. package/src/internal/dialect-renderers/sqlite.ts +6 -4
  20. package/src/internal/dialect.ts +1 -1
  21. package/src/internal/executor.ts +56 -43
  22. package/src/internal/json/path-access.ts +351 -0
  23. package/src/internal/query.d.ts +1 -1
  24. package/src/internal/query.ts +1 -1
  25. package/src/internal/runtime/driver-value-mapping.ts +3 -3
  26. package/src/internal/runtime/schema.ts +28 -38
  27. package/src/internal/runtime/value.ts +20 -23
  28. package/src/internal/scalar.d.ts +1 -1
  29. package/src/internal/scalar.ts +2 -1
  30. package/src/internal/schema-derivation.d.ts +7 -7
  31. package/src/internal/schema-derivation.ts +11 -11
  32. package/src/internal/standard-dsl.ts +121 -28
  33. package/src/internal/table.ts +451 -120
  34. package/src/mysql/column.ts +6 -6
  35. package/src/mysql/datatypes/index.ts +1 -0
  36. package/src/mysql/datatypes/spec.ts +6 -176
  37. package/src/mysql/errors/normalize.ts +0 -1
  38. package/src/mysql/executor.ts +4 -6
  39. package/src/mysql/function/temporal.ts +1 -1
  40. package/src/mysql/internal/dsl.ts +116 -16
  41. package/src/mysql/json.ts +1 -33
  42. package/src/mysql/renderer.ts +13 -6
  43. package/src/mysql/type.ts +60 -0
  44. package/src/mysql.ts +3 -1
  45. package/src/postgres/check.ts +1 -0
  46. package/src/postgres/column.ts +11 -11
  47. package/src/postgres/datatypes/index.ts +1 -0
  48. package/src/postgres/datatypes/spec.ts +6 -260
  49. package/src/postgres/errors/normalize.ts +0 -1
  50. package/src/postgres/executor.ts +4 -6
  51. package/src/postgres/foreign-key.ts +24 -0
  52. package/src/postgres/function/temporal.ts +1 -1
  53. package/src/postgres/index.ts +1 -0
  54. package/src/postgres/internal/dsl.ts +122 -21
  55. package/src/postgres/json-extension.ts +7 -0
  56. package/src/postgres/json.ts +726 -173
  57. package/src/postgres/jsonb.ts +0 -1
  58. package/src/postgres/primary-key.ts +24 -0
  59. package/src/postgres/renderer.ts +13 -6
  60. package/src/postgres/schema-management.ts +1 -6
  61. package/src/postgres/schema.ts +16 -8
  62. package/src/postgres/table.ts +111 -113
  63. package/src/postgres/type.ts +86 -4
  64. package/src/postgres/unique.ts +32 -0
  65. package/src/postgres.ts +12 -6
  66. package/src/sqlite/column.ts +6 -6
  67. package/src/sqlite/datatypes/index.ts +1 -0
  68. package/src/sqlite/datatypes/spec.ts +6 -94
  69. package/src/sqlite/errors/normalize.ts +0 -1
  70. package/src/sqlite/executor.ts +4 -6
  71. package/src/sqlite/function/temporal.ts +1 -1
  72. package/src/sqlite/internal/dsl.ts +100 -5
  73. package/src/sqlite/json.ts +1 -32
  74. package/src/sqlite/renderer.ts +13 -6
  75. package/src/sqlite/type.ts +40 -0
  76. package/src/sqlite.ts +3 -1
  77. package/src/standard/cast.ts +113 -0
  78. package/src/standard/check.ts +17 -0
  79. package/src/standard/column.ts +10 -10
  80. package/src/standard/datatypes/index.ts +2 -2
  81. package/src/standard/datatypes/spec.ts +10 -96
  82. package/src/standard/foreign-key.ts +37 -0
  83. package/src/standard/function/temporal.ts +1 -1
  84. package/src/standard/index.ts +17 -0
  85. package/src/standard/json.ts +883 -0
  86. package/src/standard/primary-key.ts +17 -0
  87. package/src/standard/renderer.ts +31 -3
  88. package/src/standard/table.ts +25 -21
  89. package/src/standard/unique.ts +17 -0
  90. package/src/standard.ts +14 -0
  91. package/src/internal/table.d.ts +0 -174
  92. package/src/postgres/cast.ts +0 -45
@@ -18,7 +18,7 @@ import {
18
18
  import { sqliteDatatypes } from "./datatypes/index.js"
19
19
 
20
20
  const primitive = <Type, Db extends Expression.DbType.Any>(
21
- schema: Schema.Schema<Type, any, any>,
21
+ schema: Schema.Schema<Type>,
22
22
  dbType: Db
23
23
  ): ColumnDefinition<Type, Type, Type, Db, false, false, false, false, false, undefined> =>
24
24
  makeColumnDefinition(schema as Schema.Schema<NonNullable<Type>>, {
@@ -43,11 +43,11 @@ const renderNumericDdlType = (
43
43
  : `${kind}(${options.precision},${options.scale})`
44
44
  }
45
45
 
46
- export const custom = <SchemaType extends Schema.Schema.Any, Db extends Expression.DbType.Any>(
46
+ export const custom = <SchemaType extends Schema.Top, Db extends Expression.DbType.Any>(
47
47
  schema: SchemaType,
48
48
  dbType: Db
49
49
  ) =>
50
- makeColumnDefinition(schema as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>, any, any>, {
50
+ makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>>, {
51
51
  dbType: enrichDbType(sqliteDatatypes, dbType),
52
52
  nullable: false,
53
53
  hasDefault: false,
@@ -59,7 +59,7 @@ export const custom = <SchemaType extends Schema.Schema.Any, Db extends Expressi
59
59
  identity: undefined
60
60
  })
61
61
 
62
- export const uuid = () => primitive(Schema.UUID, sqliteDatatypes.uuid())
62
+ export const uuid = () => primitive(Schema.String.check(Schema.isUUID()), sqliteDatatypes.uuid())
63
63
  export const text = () => primitive(Schema.String, sqliteDatatypes.text())
64
64
  export const int = () => primitive(Schema.Int, sqliteDatatypes.int())
65
65
  export const number = (options?: BaseColumn.NumericOptions) =>
@@ -79,8 +79,8 @@ export const date = () => primitive(LocalDateStringSchema, sqliteDatatypes.date(
79
79
  export const time = () => primitive(LocalTimeStringSchema, sqliteDatatypes.time())
80
80
  export const datetime = () => primitive(LocalDateTimeStringSchema, sqliteDatatypes.datetime())
81
81
  export const timestamp = () => primitive(LocalDateTimeStringSchema, sqliteDatatypes.timestamp())
82
- export const json = <SchemaType extends Schema.Schema.Any>(schema: SchemaType) =>
83
- makeColumnDefinition(schema as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>, any, any>, {
82
+ export const json = <SchemaType extends Schema.Top>(schema: SchemaType) =>
83
+ makeColumnDefinition(schema as unknown as Schema.Schema<NonNullable<Schema.Schema.Type<SchemaType>>>, {
84
84
  dbType: { ...sqliteDatatypes.json(), variant: "json" } as Expression.DbType.Json<"sqlite", "json">,
85
85
  nullable: false,
86
86
  hasDefault: false,
@@ -15,6 +15,7 @@ const withMetadata = <Kind extends keyof typeof sqliteDatatypeKinds & string>(
15
15
  runtime: kindSpec.runtime,
16
16
  compareGroup: familySpec?.compareGroup,
17
17
  castTargets: familySpec?.castTargets,
18
+ implicitTargets: (familySpec as { readonly implicitTargets?: readonly string[] }).implicitTargets,
18
19
  traits: familySpec?.traits
19
20
  }
20
21
  }
@@ -1,98 +1,10 @@
1
- import type { DatatypeFamilySpec, DatatypeKindSpec } from "../../internal/datatypes/shape.js"
1
+ import {
2
+ sqliteDatatypeFamilies as matrixSqliteDatatypeFamilies,
3
+ sqliteDatatypeKinds as matrixSqliteDatatypeKinds
4
+ } from "../../internal/datatypes/matrix.js"
2
5
 
3
- export const sqliteDatatypeFamilies = {
4
- text: {
5
- compareGroup: "text",
6
- castTargets: ["text", "numeric", "integer", "real", "boolean", "date", "time", "datetime", "json", "blob", "null"],
7
- traits: {
8
- textual: true,
9
- ordered: true
10
- }
11
- },
12
- numeric: {
13
- compareGroup: "numeric",
14
- castTargets: ["numeric", "integer", "real", "text", "boolean", "date", "time", "datetime"],
15
- traits: {
16
- ordered: true
17
- }
18
- },
19
- integer: {
20
- compareGroup: "numeric",
21
- castTargets: ["integer", "numeric", "real", "text", "boolean", "date", "time", "datetime"],
22
- traits: {
23
- ordered: true
24
- }
25
- },
26
- real: {
27
- compareGroup: "numeric",
28
- castTargets: ["real", "numeric", "integer", "text", "boolean"],
29
- traits: {
30
- ordered: true
31
- }
32
- },
33
- boolean: {
34
- compareGroup: "boolean",
35
- castTargets: ["boolean", "integer", "numeric", "text"],
36
- traits: {}
37
- },
38
- date: {
39
- compareGroup: "date",
40
- castTargets: ["date", "time", "datetime", "text", "numeric", "integer"],
41
- traits: {
42
- ordered: true
43
- }
44
- },
45
- time: {
46
- compareGroup: "time",
47
- castTargets: ["time", "date", "datetime", "text", "numeric", "integer"],
48
- traits: {
49
- ordered: true
50
- }
51
- },
52
- datetime: {
53
- compareGroup: "datetime",
54
- castTargets: ["datetime", "date", "time", "text", "numeric", "integer"],
55
- traits: {
56
- ordered: true
57
- }
58
- },
59
- json: {
60
- compareGroup: "json",
61
- castTargets: ["json", "text"],
62
- traits: {}
63
- },
64
- blob: {
65
- compareGroup: "blob",
66
- castTargets: ["blob", "text"],
67
- traits: {}
68
- },
69
- null: {
70
- compareGroup: "null",
71
- castTargets: ["text", "numeric", "integer", "real", "boolean", "date", "time", "datetime", "json", "blob", "null"],
72
- traits: {}
73
- }
74
- } as const satisfies Record<string, DatatypeFamilySpec>
75
-
76
- export const sqliteDatatypeKinds = {
77
- text: { family: "text", runtime: "string" },
78
- varchar: { family: "text", runtime: "string" },
79
- char: { family: "text", runtime: "string" },
80
- clob: { family: "text", runtime: "string" },
81
- int: { family: "integer", runtime: "number" },
82
- integer: { family: "integer", runtime: "number" },
83
- bigint: { family: "integer", runtime: "bigintString" },
84
- numeric: { family: "numeric", runtime: "decimalString" },
85
- decimal: { family: "numeric", runtime: "decimalString" },
86
- real: { family: "real", runtime: "number" },
87
- double: { family: "real", runtime: "number" },
88
- boolean: { family: "boolean", runtime: "boolean" },
89
- date: { family: "date", runtime: "localDate" },
90
- time: { family: "time", runtime: "localTime" },
91
- datetime: { family: "datetime", runtime: "localDateTime" },
92
- timestamp: { family: "datetime", runtime: "localDateTime" },
93
- json: { family: "json", runtime: "json" },
94
- blob: { family: "blob", runtime: "bytes" }
95
- } as const satisfies Record<string, DatatypeKindSpec>
6
+ export const sqliteDatatypeFamilies = matrixSqliteDatatypeFamilies
7
+ export const sqliteDatatypeKinds = matrixSqliteDatatypeKinds
96
8
 
97
9
  export type SqliteDatatypeFamily = keyof typeof sqliteDatatypeFamilies
98
10
  export type SqliteDatatypeKind = keyof typeof sqliteDatatypeKinds
@@ -25,7 +25,6 @@ const unwrapSqliteDriverCause = (cause: unknown): unknown => {
25
25
  while (
26
26
  isRecord(current) &&
27
27
  "_tag" in current &&
28
- current._tag === "SqlError" &&
29
28
  "cause" in current
30
29
  ) {
31
30
  current = current.cause
@@ -1,5 +1,5 @@
1
1
  import * as Effect from "effect/Effect"
2
- import * as SqlClient from "@effect/sql/SqlClient"
2
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
3
3
  import * as Stream from "effect/Stream"
4
4
 
5
5
  import * as CoreExecutor from "../internal/executor.js"
@@ -41,8 +41,6 @@ export type SqliteQueryError<PlanValue extends CoreQuery.QueryPlan<any, any, any
41
41
 
42
42
  /** Runs an effect within the ambient SQLite SQL transaction service. */
43
43
  export const withTransaction = CoreExecutor.withTransaction
44
- /** Runs an effect in a nested SQLite SQL transaction scope. */
45
- export const withSavepoint = CoreExecutor.withSavepoint
46
44
 
47
45
  /** SQLite executor whose error channel narrows based on the query plan. */
48
46
  export interface QueryExecutor<Context = never> {
@@ -142,10 +140,10 @@ const fromDriver = <
142
140
  stream(plan) {
143
141
  const rendered = renderer.render(plan)
144
142
  return Stream.mapError(
145
- Stream.mapChunksEffect(
143
+ Stream.mapArrayEffect(
146
144
  sqlDriver.stream(rendered),
147
145
  (rows) => Effect.try({
148
- try: () => CoreExecutor.decodeChunk(rendered, plan, rows, { driverMode, valueMappings }),
146
+ try: () => CoreExecutor.decodeRows(rendered, plan, rows, { driverMode, valueMappings }) as never,
149
147
  catch: (error) => error as RowDecodeError
150
148
  })
151
149
  ),
@@ -181,7 +179,7 @@ const sqlClientDriver = (): Driver<any, SqlClient.SqlClient> =>
181
179
  * Creates the standard SQLite executor pipeline.
182
180
  *
183
181
  * By default this uses the built-in SQLite renderer plus the ambient
184
- * `@effect/sql` `SqlClient`. Advanced callers can override the renderer,
182
+ * `effect/unstable/sql` `SqlClient`. Advanced callers can override the renderer,
185
183
  * driver, or both.
186
184
  */
187
185
  export function make(): QueryExecutor<SqlClient.SqlClient>
@@ -35,7 +35,7 @@ const makeTemporal = <
35
35
  >(
36
36
  name: Name,
37
37
  dbType: Db,
38
- runtimeSchema: Schema.Schema<Runtime, any, any>
38
+ runtimeSchema: Schema.Schema<Runtime>
39
39
  ): TemporalExpression<Runtime, Db, Name> =>
40
40
  makeExpression({
41
41
  runtime: undefined as unknown as Runtime,
@@ -1590,11 +1590,14 @@ const profile: QueryDialectProfile<Dialect, TextDb, NumericDb, BoolDb, Timestamp
1590
1590
 
1591
1591
  const literalSchemaOf = <Value extends LiteralValue>(
1592
1592
  value: Value
1593
- ): Schema.Schema.Any | undefined => {
1593
+ ): Schema.Top | undefined => {
1594
1594
  if (value === null || value instanceof Date) {
1595
1595
  return undefined
1596
1596
  }
1597
- return Schema.Literal(value) as Schema.Schema.Any
1597
+ if (typeof value === "number" && !Number.isFinite(value)) {
1598
+ return undefined
1599
+ }
1600
+ return Schema.Literal(value) as unknown as Schema.Top
1598
1601
  }
1599
1602
 
1600
1603
  const literal = <const Value extends LiteralValue>(
@@ -4521,6 +4524,83 @@ type ValidateTargetColumnInput<
4521
4524
  Columns extends DdlColumnInput
4522
4525
  > = ValidateTargetColumns<Target, NormalizeDdlColumns<Columns>> extends never ? never : Columns
4523
4526
 
4527
+ type SameColumnSet<
4528
+ Left extends readonly string[],
4529
+ Right extends readonly string[]
4530
+ > = string extends Left[number] | Right[number]
4531
+ ? false
4532
+ : Exclude<Left[number], Right[number]> extends never
4533
+ ? Exclude<Right[number], Left[number]> extends never
4534
+ ? true
4535
+ : false
4536
+ : false
4537
+
4538
+ type ConflictArbitersOf<Target extends MutationTargetLike> =
4539
+ Target[typeof Table.TypeId]["conflictArbiters"][number]
4540
+
4541
+ type MatchingConflictArbiter<
4542
+ Target extends MutationTargetLike,
4543
+ Columns extends readonly string[],
4544
+ AllowPartial extends boolean
4545
+ > = ConflictArbitersOf<Target> extends infer Arbiter extends Table.ConflictArbiter
4546
+ ? Arbiter extends Table.ConflictArbiter
4547
+ ? SameColumnSet<Arbiter["columns"], Columns> extends true
4548
+ ? Arbiter["scope"] extends "unconditional"
4549
+ ? true
4550
+ : AllowPartial extends true ? true : never
4551
+ : never
4552
+ : never
4553
+ : never
4554
+
4555
+ type HasInlineConflictArbiter<
4556
+ Target extends MutationTargetLike,
4557
+ Columns extends readonly string[]
4558
+ > = Columns extends readonly [infer Column extends Extract<keyof Target[typeof Table.TypeId]["fields"], string>]
4559
+ ? Target[typeof Table.TypeId]["fields"][Column] extends { readonly metadata: { readonly primaryKey: true } | { readonly unique: true } }
4560
+ ? true
4561
+ : false
4562
+ : false
4563
+
4564
+ type HasConflictArbiter<
4565
+ Target extends MutationTargetLike,
4566
+ Columns extends readonly string[],
4567
+ AllowPartial extends boolean
4568
+ > = string extends Extract<keyof Target[typeof Table.TypeId]["fields"], string>
4569
+ ? true
4570
+ : HasInlineConflictArbiter<Target, Columns> extends true
4571
+ ? true
4572
+ : true extends MatchingConflictArbiter<Target, Columns, AllowPartial> ? true : false
4573
+
4574
+ type ConflictTargetArbiterError<
4575
+ Columns,
4576
+ AllowPartial extends boolean
4577
+ > = {
4578
+ readonly __effect_qb_error__: "effect-qb: conflict target columns must match a primary key, unique constraint, or unique index"
4579
+ readonly __effect_qb_conflict_columns__: Columns
4580
+ readonly __effect_qb_partial_target__: AllowPartial
4581
+ readonly __effect_qb_hint__: "Declare the target columns as primaryKey/unique, add a table-level Unique.make(...), or use a simple Pg.Index.uniqueIndex(...)"
4582
+ }
4583
+
4584
+ type ValidateConflictColumnInput<
4585
+ Target extends MutationTargetLike,
4586
+ Columns extends DdlColumnInput,
4587
+ AllowPartial extends boolean
4588
+ > = ValidateTargetColumnInput<Target, Columns> extends never
4589
+ ? never
4590
+ : HasConflictArbiter<Target, NormalizeDdlColumns<Columns>, AllowPartial> extends true
4591
+ ? Columns
4592
+ : ConflictTargetArbiterError<NormalizeDdlColumns<Columns>, AllowPartial>
4593
+
4594
+ type ConflictColumnPlanConstraint<
4595
+ Target extends MutationTargetLike,
4596
+ Columns extends DdlColumnInput,
4597
+ AllowPartial extends boolean
4598
+ > = ValidateTargetColumnInput<Target, Columns> extends never
4599
+ ? never
4600
+ : HasConflictArbiter<Target, NormalizeDdlColumns<Columns>, AllowPartial> extends true
4601
+ ? unknown
4602
+ : ConflictTargetArbiterError<NormalizeDdlColumns<Columns>, AllowPartial>
4603
+
4524
4604
  type CreateIndexOptions<Name extends string = string> = {
4525
4605
  readonly name?: NonEmptyStringInput<Name>
4526
4606
  readonly unique?: boolean
@@ -5022,6 +5102,21 @@ type ConflictConstraintNameConstraint<Target> =
5022
5102
  ? { readonly constraint: NonEmptyStringInput<Constraint> }
5023
5103
  : unknown
5024
5104
 
5105
+ type ConflictTargetHasPredicate<Target> =
5106
+ Target extends { readonly where: PredicateInput } ? true : false
5107
+
5108
+ type ConflictTargetPlanConstraint<
5109
+ Target extends MutationTargetLike,
5110
+ ConflictTarget
5111
+ > =
5112
+ ConflictTarget extends { readonly constraint: string }
5113
+ ? unknown
5114
+ : ConflictTarget extends { readonly columns: infer Columns extends DdlColumnInput }
5115
+ ? ConflictColumnPlanConstraint<Target, Columns, ConflictTargetHasPredicate<ConflictTarget>>
5116
+ : ConflictTarget extends DdlColumnInput
5117
+ ? ConflictColumnPlanConstraint<Target, ConflictTarget, false>
5118
+ : unknown
5119
+
5025
5120
  type ConflictActionInput<
5026
5121
  Target extends MutationTargetLike,
5027
5122
  Dialect extends string,
@@ -6315,9 +6410,9 @@ type AsCurriedResult<
6315
6410
  >(
6316
6411
  target: ConflictTarget & ConflictConstraintNameConstraint<ConflictTarget>,
6317
6412
  options?: Options & ConflictActionUpdateNonEmptyConstraint<Options>
6318
- ) =>
6413
+ ) =>
6319
6414
  <PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
6320
- plan: PlanValue & RequireInsertStatement<PlanValue>
6415
+ plan: PlanValue & RequireInsertStatement<PlanValue> & ConflictTargetPlanConstraint<MutationTargetOfPlan<PlanValue>, ConflictTarget>
6321
6416
  ) => QueryPlan<
6322
6417
  SelectionOfPlan<PlanValue>,
6323
6418
  Exclude<RequiredOfPlan<PlanValue> | ConflictRequired<UpdateValues, Options, ConflictTarget>, AvailableNames<AvailableOfPlan<PlanValue>>>,
@@ -6381,7 +6476,7 @@ type AsCurriedResult<
6381
6476
  >(
6382
6477
  target: Target,
6383
6478
  values: Values & MutationValuesDialectConstraint<Values, Dialect, TextDb, NumericDb, BoolDb, TimestampDb, NullDb>,
6384
- conflictColumns: ValidateTargetColumnInput<Target, Columns>,
6479
+ conflictColumns: ValidateConflictColumnInput<Target, Columns, false>,
6385
6480
  updateValues?: UpdateValues & UpdateValuesNonEmptyConstraint<Exclude<UpdateValues, undefined>> & MutationValuesDialectConstraint<Exclude<UpdateValues, undefined>, Dialect, TextDb, NumericDb, BoolDb, TimestampDb, NullDb>
6386
6481
  ) => QueryPlan<
6387
6482
  {},
@@ -1,39 +1,8 @@
1
- /** SQLite JSON expression helpers. */
2
- export { json } from "./internal/dsl.js"
1
+ /** SQLite-specific JSON expression helpers. Portable JSON helpers are exported from `effect-qb`. */
3
2
  import { json } from "./internal/dsl.js"
4
3
 
5
- export const key = json.key
6
- export const index = json.index
7
- export const wildcard = json.wildcard
8
- export const slice = json.slice
9
- export const descend = json.descend
10
- export const path = json.path
11
- export const get = json.get
12
- export const access = json.access
13
- export const traverse = json.traverse
14
- export const text = json.text
15
- export const accessText = json.accessText
16
- export const traverseText = json.traverseText
17
- export const contains = json.contains
18
- export const containedBy = json.containedBy
19
- export const hasKey = json.hasKey
20
- export const keyExists = json.keyExists
21
- export const hasAnyKeys = json.hasAnyKeys
22
- export const hasAllKeys = json.hasAllKeys
23
- export const delete_ = json.delete
24
- export { delete_ as delete }
25
- export const remove = json.remove
26
- export const set = json.set
27
4
  export const insert = json.insert
28
- export const concat = json.concat
29
- export const merge = json.merge
30
- export const buildObject = json.buildObject
31
- export const buildArray = json.buildArray
32
- export const toJson = json.toJson
33
- export const toJsonb = json.toJsonb
34
5
  export const typeOf = json.typeOf
35
6
  export const length = json.length
36
- export const keys = json.keys
37
7
  export const stripNulls = json.stripNulls
38
- export const pathExists = json.pathExists
39
8
  export const pathMatch = json.pathMatch
@@ -20,6 +20,9 @@ export type ValueMappings = Expression.DriverValueMappingsFor<SqliteDatatypeKind
20
20
 
21
21
  export interface MakeOptions {
22
22
  readonly valueMappings?: ValueMappings
23
+ }
24
+
25
+ interface RendererState extends MakeOptions {
23
26
  readonly casing?: Casing.Options
24
27
  }
25
28
 
@@ -33,19 +36,23 @@ const RendererProto = {
33
36
  }
34
37
 
35
38
  /** Creates the built-in SQLite renderer. */
36
- export const make = (options: MakeOptions = {}): Renderer => {
37
- const renderer = CoreRenderer.makeTrusted("sqlite", (plan) => renderSqlitePlan(plan, options))
39
+ const makeWithState = (state: RendererState = {}): Renderer => {
40
+ const renderer = CoreRenderer.makeTrusted("sqlite", (plan) => renderSqlitePlan(plan, state))
38
41
  return Object.assign(Object.create(RendererProto), renderer, {
39
42
  [Casing.TypeId]: {
40
- casing: options.casing
43
+ casing: state.casing
41
44
  },
42
45
  withCasing: (override: Casing.Options) =>
43
- make({
44
- ...options,
45
- casing: Casing.merge(options.casing, override)
46
+ makeWithState({
47
+ ...state,
48
+ casing: Casing.merge(state.casing, override)
46
49
  })
47
50
  }) as Renderer
48
51
  }
49
52
 
53
+ /** Creates the built-in SQLite renderer. */
54
+ export const make = (options: MakeOptions = {}): Renderer =>
55
+ makeWithState({ valueMappings: options.valueMappings })
56
+
50
57
  /** Shared built-in SQLite renderer instance. */
51
58
  export const sqlite = make()
@@ -0,0 +1,40 @@
1
+ import type * as Expression from "../internal/scalar.js"
2
+ import type { NonEmptyStringInput } from "../internal/table-options.js"
3
+ import {
4
+ pickDatatypeConstructors,
5
+ sqliteSpecificDatatypeKeys,
6
+ type SqliteSpecificDatatypeKey
7
+ } from "../internal/datatypes/matrix.js"
8
+ import { sqliteDatatypes } from "./datatypes/index.js"
9
+
10
+ type SqliteSpecificDatatypes = Pick<typeof sqliteDatatypes, SqliteSpecificDatatypeKey>
11
+
12
+ type SqliteTypeNamespace = SqliteSpecificDatatypes & {
13
+ readonly custom: <Kind extends string>(kind: NonEmptyStringInput<Kind>) => Expression.DbType.Base<"sqlite", Kind>
14
+ readonly driverValueMapping: <Db extends Expression.DbType.Any>(
15
+ dbType: Db,
16
+ mapping: Expression.DriverValueMapping
17
+ ) => Db
18
+ }
19
+
20
+ const custom = <Kind extends string>(
21
+ kind: NonEmptyStringInput<Kind>
22
+ ): Expression.DbType.Base<"sqlite", Kind> => ({
23
+ dialect: "sqlite",
24
+ kind: kind as Kind
25
+ })
26
+
27
+ const driverValueMapping = <Db extends Expression.DbType.Any>(
28
+ dbType: Db,
29
+ mapping: Expression.DriverValueMapping
30
+ ): Db => ({
31
+ ...dbType,
32
+ driverValueMapping: mapping
33
+ })
34
+
35
+ /** SQLite-only database-type constructors for casts and typed column references. */
36
+ export const type: SqliteTypeNamespace = {
37
+ ...pickDatatypeConstructors(sqliteDatatypes, sqliteSpecificDatatypeKeys),
38
+ custom,
39
+ driverValueMapping
40
+ }
package/src/sqlite.ts CHANGED
@@ -4,11 +4,13 @@ export * as Column from "./sqlite/column-extension.js"
4
4
  export * as Datatypes from "./sqlite/datatypes/index.js"
5
5
  /** SQLite error catalog and error normalization helpers. */
6
6
  export * as Errors from "./sqlite/errors/index.js"
7
- /** SQLite-specialized JSON expression helpers. */
7
+ /** SQLite-specific JSON expression helpers. Portable JSON helpers are exported from the root package. */
8
8
  export * as Json from "./sqlite/json.js"
9
9
  /** SQLite-specialized typed query execution contracts. */
10
10
  export * as Executor from "./sqlite/executor.js"
11
11
  /** SQLite-specific query helpers. Portable queries are exported from the root package. */
12
12
  export * as Query from "./sqlite/query-extension.js"
13
+ /** SQLite-only database-type constructors for casts and typed references. */
14
+ export { type as Type } from "./sqlite/type.js"
13
15
  /** SQLite-specialized built-in renderer entrypoint. */
14
16
  export * as Renderer from "./sqlite/renderer.js"
@@ -0,0 +1,113 @@
1
+ import type * as ExpressionAst from "../internal/expression-ast.js"
2
+ import type { CastTargetError } from "../internal/coercion/errors.js"
3
+ import type { RuntimeOfDbType } from "../internal/coercion/analysis.js"
4
+ import type { CanCastDbType } from "../internal/coercion/rules.js"
5
+ import type { FamilyOfDbType } from "../internal/datatypes/lookup.js"
6
+ import type { ExpressionInput } from "../internal/query.js"
7
+ import type * as Expression from "../internal/scalar.js"
8
+ import { cast as standardCast } from "../internal/standard-dsl.js"
9
+ import type { standardDatatypes } from "./datatypes/index.js"
10
+ import type { standardDatatypeFamilies } from "./datatypes/spec.js"
11
+
12
+ type CastInput = ExpressionInput
13
+ type CastTarget = Expression.DbType.Any
14
+ type IsAny<Value> = 0 extends (1 & Value) ? true : false
15
+
16
+ type StandardNullDb = Expression.DbType.Base<"standard", "null"> & {
17
+ readonly family: "null"
18
+ readonly runtime: "unknown"
19
+ readonly compareGroup: "null"
20
+ readonly castTargets: typeof standardDatatypeFamilies.null.castTargets
21
+ readonly traits: {}
22
+ }
23
+
24
+ type LiteralDbType<Value> =
25
+ Value extends string ? ReturnType<typeof standardDatatypes.text> :
26
+ Value extends number ? ReturnType<typeof standardDatatypes.real> :
27
+ Value extends boolean ? ReturnType<typeof standardDatatypes.boolean> :
28
+ Value extends Date ? ReturnType<typeof standardDatatypes.timestamp> :
29
+ StandardNullDb
30
+
31
+ type CastSourceDbType<Value extends CastInput> = Value extends Expression.Any
32
+ ? Expression.DbTypeOf<Value>
33
+ : LiteralDbType<Value>
34
+
35
+ type CastDialect<Value extends CastInput, Target extends CastTarget> =
36
+ CastSourceDbType<Value>["dialect"] | Target["dialect"]
37
+
38
+ type CastNullability<Value extends CastInput> = Value extends Expression.Any
39
+ ? Expression.NullabilityOf<Value>
40
+ : Value extends null ? "always" : "never"
41
+
42
+ type CastKind<Value extends CastInput> = Value extends Expression.Any
43
+ ? Expression.KindOf<Value>
44
+ : "scalar"
45
+
46
+ type CastDependencies<Value extends CastInput> = Value extends Expression.Any
47
+ ? Expression.DependenciesOf<Value>
48
+ : never
49
+
50
+ type JsonbScalarCastTarget<Value extends CastInput, Target extends CastTarget> =
51
+ Value extends Expression.Any
52
+ ? Expression.DbTypeOf<Value> extends Expression.DbType.Json<"postgres", "jsonb">
53
+ ? [Expression.RuntimeOf<Value>] extends [number]
54
+ ? FamilyOfDbType<Target> extends "numeric" ? Target : never
55
+ : [Expression.RuntimeOf<Value>] extends [boolean]
56
+ ? FamilyOfDbType<Target> extends "boolean" ? Target : never
57
+ : never
58
+ : never
59
+ : never
60
+
61
+ type CanCastJsonbScalar<Value extends CastInput, Target extends CastTarget> =
62
+ [JsonbScalarCastTarget<Value, Target>] extends [never]
63
+ ? false
64
+ : JsonbScalarCastTarget<Value, Target> extends Target
65
+ ? true
66
+ : false
67
+
68
+ type CastTargetInput<Value extends CastInput, Target extends CastTarget> =
69
+ IsAny<Value> extends true
70
+ ? Target
71
+ : IsAny<Target> extends true
72
+ ? Target
73
+ : CanCastDbType<CastSourceDbType<Value>, Target, CastDialect<Value, Target>> extends true
74
+ ? Target
75
+ : CanCastJsonbScalar<Value, Target> extends true
76
+ ? Target
77
+ : CastTargetError<CastSourceDbType<Value>, Target, CastDialect<Value, Target>>
78
+
79
+ type CastValueInput<Value extends CastInput, Target extends CastTarget> =
80
+ CastTargetInput<Value, Target> extends Target
81
+ ? Value
82
+ : CastTargetInput<Value, Target>
83
+
84
+ type CastExpression<
85
+ Value extends CastInput,
86
+ Target extends CastTarget
87
+ > = Expression.Scalar<
88
+ RuntimeOfDbType<Target>,
89
+ Target,
90
+ CastNullability<Value>,
91
+ CastDialect<Value, Target>,
92
+ CastKind<Value>,
93
+ CastDependencies<Value>
94
+ > & {
95
+ readonly [ExpressionAst.TypeId]: ExpressionAst.CastNode<Value extends Expression.Any ? Value : Expression.Any, Target>
96
+ }
97
+
98
+ export const to: {
99
+ <Value extends CastInput, Target extends CastTarget>(
100
+ value: Value,
101
+ target: Target & CastTargetInput<Value, Target>
102
+ ): CastExpression<Value, Target>
103
+ // `NoInfer` keeps `Value` out of its own inference constraint: it is inferred
104
+ // from the argument, then validated against the already-fixed `Target`.
105
+ // Without it, the validation forms an inference fixpoint that explodes under
106
+ // higher-order inference (e.g. `.pipe`).
107
+ <Target extends CastTarget>(
108
+ target: Target
109
+ ): <Value extends CastInput>(value: Value & CastValueInput<NoInfer<Value>, Target>) => CastExpression<Value, Target>
110
+ } = ((...args: [CastInput, CastTarget] | [CastTarget]) =>
111
+ args.length === 1
112
+ ? ((value: CastInput) => standardCast(value as never, args[0] as never))
113
+ : standardCast(args[0] as never, args[1] as never)) as unknown as typeof to
@@ -0,0 +1,17 @@
1
+ import * as BaseTable from "../internal/table.js"
2
+ import type { TableOptionSpec } from "../internal/table-options.js"
3
+
4
+ type CheckSpec = Extract<TableOptionSpec, { readonly kind: "check" }>
5
+
6
+ export const make = BaseTable.check
7
+
8
+ export const named = <const Name extends string>(
9
+ name: BaseTable.NonEmptyStringInput<Name>
10
+ ) =>
11
+ <Spec extends CheckSpec, TableContext extends BaseTable.TableDefinition<any, any, any, "schema", any>>(
12
+ option: BaseTable.TableOption<Spec, TableContext>
13
+ ): BaseTable.TableOption<Spec & { readonly name: Name }, TableContext> =>
14
+ BaseTable.mapOption(option, (spec) => ({
15
+ ...spec,
16
+ name
17
+ } as Spec & { readonly name: Name }))