effect-qb 0.19.0 → 4.0.0-beta.92

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 (89) hide show
  1. package/README.md +7 -1
  2. package/dist/index.js +1987 -679
  3. package/dist/mysql.js +1486 -616
  4. package/dist/postgres/metadata.js +1334 -263
  5. package/dist/postgres.js +3374 -2308
  6. package/dist/sqlite.js +1569 -627
  7. package/dist/standard.js +1982 -674
  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 +118 -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/executor.ts +4 -6
  38. package/src/mysql/function/temporal.ts +1 -1
  39. package/src/mysql/internal/dsl.ts +113 -16
  40. package/src/mysql/json.ts +1 -33
  41. package/src/mysql/renderer.ts +13 -6
  42. package/src/mysql/type.ts +60 -0
  43. package/src/mysql.ts +3 -1
  44. package/src/postgres/check.ts +1 -0
  45. package/src/postgres/column.ts +11 -11
  46. package/src/postgres/datatypes/index.ts +1 -0
  47. package/src/postgres/datatypes/spec.ts +6 -260
  48. package/src/postgres/executor.ts +4 -6
  49. package/src/postgres/foreign-key.ts +24 -0
  50. package/src/postgres/function/temporal.ts +1 -1
  51. package/src/postgres/index.ts +1 -0
  52. package/src/postgres/internal/dsl.ts +119 -21
  53. package/src/postgres/json-extension.ts +7 -0
  54. package/src/postgres/json.ts +726 -173
  55. package/src/postgres/jsonb.ts +0 -1
  56. package/src/postgres/primary-key.ts +24 -0
  57. package/src/postgres/renderer.ts +13 -6
  58. package/src/postgres/schema-management.ts +1 -6
  59. package/src/postgres/schema.ts +16 -8
  60. package/src/postgres/table.ts +111 -113
  61. package/src/postgres/type.ts +86 -4
  62. package/src/postgres/unique.ts +32 -0
  63. package/src/postgres.ts +12 -6
  64. package/src/sqlite/column.ts +6 -6
  65. package/src/sqlite/datatypes/index.ts +1 -0
  66. package/src/sqlite/datatypes/spec.ts +6 -94
  67. package/src/sqlite/executor.ts +4 -6
  68. package/src/sqlite/function/temporal.ts +1 -1
  69. package/src/sqlite/internal/dsl.ts +97 -5
  70. package/src/sqlite/json.ts +1 -32
  71. package/src/sqlite/renderer.ts +13 -6
  72. package/src/sqlite/type.ts +40 -0
  73. package/src/sqlite.ts +3 -1
  74. package/src/standard/cast.ts +113 -0
  75. package/src/standard/check.ts +17 -0
  76. package/src/standard/column.ts +10 -10
  77. package/src/standard/datatypes/index.ts +2 -2
  78. package/src/standard/datatypes/spec.ts +10 -96
  79. package/src/standard/foreign-key.ts +37 -0
  80. package/src/standard/function/temporal.ts +1 -1
  81. package/src/standard/index.ts +17 -0
  82. package/src/standard/json.ts +883 -0
  83. package/src/standard/primary-key.ts +17 -0
  84. package/src/standard/renderer.ts +31 -3
  85. package/src/standard/table.ts +25 -21
  86. package/src/standard/unique.ts +17 -0
  87. package/src/standard.ts +14 -0
  88. package/src/internal/table.d.ts +0 -174
  89. 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
@@ -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,11 @@ 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
+ return Schema.Literal(value) as unknown as Schema.Top
1598
1598
  }
1599
1599
 
1600
1600
  const literal = <const Value extends LiteralValue>(
@@ -4521,6 +4521,83 @@ type ValidateTargetColumnInput<
4521
4521
  Columns extends DdlColumnInput
4522
4522
  > = ValidateTargetColumns<Target, NormalizeDdlColumns<Columns>> extends never ? never : Columns
4523
4523
 
4524
+ type SameColumnSet<
4525
+ Left extends readonly string[],
4526
+ Right extends readonly string[]
4527
+ > = string extends Left[number] | Right[number]
4528
+ ? false
4529
+ : Exclude<Left[number], Right[number]> extends never
4530
+ ? Exclude<Right[number], Left[number]> extends never
4531
+ ? true
4532
+ : false
4533
+ : false
4534
+
4535
+ type ConflictArbitersOf<Target extends MutationTargetLike> =
4536
+ Target[typeof Table.TypeId]["conflictArbiters"][number]
4537
+
4538
+ type MatchingConflictArbiter<
4539
+ Target extends MutationTargetLike,
4540
+ Columns extends readonly string[],
4541
+ AllowPartial extends boolean
4542
+ > = ConflictArbitersOf<Target> extends infer Arbiter extends Table.ConflictArbiter
4543
+ ? Arbiter extends Table.ConflictArbiter
4544
+ ? SameColumnSet<Arbiter["columns"], Columns> extends true
4545
+ ? Arbiter["scope"] extends "unconditional"
4546
+ ? true
4547
+ : AllowPartial extends true ? true : never
4548
+ : never
4549
+ : never
4550
+ : never
4551
+
4552
+ type HasInlineConflictArbiter<
4553
+ Target extends MutationTargetLike,
4554
+ Columns extends readonly string[]
4555
+ > = Columns extends readonly [infer Column extends Extract<keyof Target[typeof Table.TypeId]["fields"], string>]
4556
+ ? Target[typeof Table.TypeId]["fields"][Column] extends { readonly metadata: { readonly primaryKey: true } | { readonly unique: true } }
4557
+ ? true
4558
+ : false
4559
+ : false
4560
+
4561
+ type HasConflictArbiter<
4562
+ Target extends MutationTargetLike,
4563
+ Columns extends readonly string[],
4564
+ AllowPartial extends boolean
4565
+ > = string extends Extract<keyof Target[typeof Table.TypeId]["fields"], string>
4566
+ ? true
4567
+ : HasInlineConflictArbiter<Target, Columns> extends true
4568
+ ? true
4569
+ : true extends MatchingConflictArbiter<Target, Columns, AllowPartial> ? true : false
4570
+
4571
+ type ConflictTargetArbiterError<
4572
+ Columns,
4573
+ AllowPartial extends boolean
4574
+ > = {
4575
+ readonly __effect_qb_error__: "effect-qb: conflict target columns must match a primary key, unique constraint, or unique index"
4576
+ readonly __effect_qb_conflict_columns__: Columns
4577
+ readonly __effect_qb_partial_target__: AllowPartial
4578
+ readonly __effect_qb_hint__: "Declare the target columns as primaryKey/unique, add a table-level Unique.make(...), or use a simple Pg.Index.uniqueIndex(...)"
4579
+ }
4580
+
4581
+ type ValidateConflictColumnInput<
4582
+ Target extends MutationTargetLike,
4583
+ Columns extends DdlColumnInput,
4584
+ AllowPartial extends boolean
4585
+ > = ValidateTargetColumnInput<Target, Columns> extends never
4586
+ ? never
4587
+ : HasConflictArbiter<Target, NormalizeDdlColumns<Columns>, AllowPartial> extends true
4588
+ ? Columns
4589
+ : ConflictTargetArbiterError<NormalizeDdlColumns<Columns>, AllowPartial>
4590
+
4591
+ type ConflictColumnPlanConstraint<
4592
+ Target extends MutationTargetLike,
4593
+ Columns extends DdlColumnInput,
4594
+ AllowPartial extends boolean
4595
+ > = ValidateTargetColumnInput<Target, Columns> extends never
4596
+ ? never
4597
+ : HasConflictArbiter<Target, NormalizeDdlColumns<Columns>, AllowPartial> extends true
4598
+ ? unknown
4599
+ : ConflictTargetArbiterError<NormalizeDdlColumns<Columns>, AllowPartial>
4600
+
4524
4601
  type CreateIndexOptions<Name extends string = string> = {
4525
4602
  readonly name?: NonEmptyStringInput<Name>
4526
4603
  readonly unique?: boolean
@@ -5022,6 +5099,21 @@ type ConflictConstraintNameConstraint<Target> =
5022
5099
  ? { readonly constraint: NonEmptyStringInput<Constraint> }
5023
5100
  : unknown
5024
5101
 
5102
+ type ConflictTargetHasPredicate<Target> =
5103
+ Target extends { readonly where: PredicateInput } ? true : false
5104
+
5105
+ type ConflictTargetPlanConstraint<
5106
+ Target extends MutationTargetLike,
5107
+ ConflictTarget
5108
+ > =
5109
+ ConflictTarget extends { readonly constraint: string }
5110
+ ? unknown
5111
+ : ConflictTarget extends { readonly columns: infer Columns extends DdlColumnInput }
5112
+ ? ConflictColumnPlanConstraint<Target, Columns, ConflictTargetHasPredicate<ConflictTarget>>
5113
+ : ConflictTarget extends DdlColumnInput
5114
+ ? ConflictColumnPlanConstraint<Target, ConflictTarget, false>
5115
+ : unknown
5116
+
5025
5117
  type ConflictActionInput<
5026
5118
  Target extends MutationTargetLike,
5027
5119
  Dialect extends string,
@@ -6315,9 +6407,9 @@ type AsCurriedResult<
6315
6407
  >(
6316
6408
  target: ConflictTarget & ConflictConstraintNameConstraint<ConflictTarget>,
6317
6409
  options?: Options & ConflictActionUpdateNonEmptyConstraint<Options>
6318
- ) =>
6410
+ ) =>
6319
6411
  <PlanValue extends QueryPlan<any, any, any, any, any, any, any, any, any, any>>(
6320
- plan: PlanValue & RequireInsertStatement<PlanValue>
6412
+ plan: PlanValue & RequireInsertStatement<PlanValue> & ConflictTargetPlanConstraint<MutationTargetOfPlan<PlanValue>, ConflictTarget>
6321
6413
  ) => QueryPlan<
6322
6414
  SelectionOfPlan<PlanValue>,
6323
6415
  Exclude<RequiredOfPlan<PlanValue> | ConflictRequired<UpdateValues, Options, ConflictTarget>, AvailableNames<AvailableOfPlan<PlanValue>>>,
@@ -6381,7 +6473,7 @@ type AsCurriedResult<
6381
6473
  >(
6382
6474
  target: Target,
6383
6475
  values: Values & MutationValuesDialectConstraint<Values, Dialect, TextDb, NumericDb, BoolDb, TimestampDb, NullDb>,
6384
- conflictColumns: ValidateTargetColumnInput<Target, Columns>,
6476
+ conflictColumns: ValidateConflictColumnInput<Target, Columns, false>,
6385
6477
  updateValues?: UpdateValues & UpdateValuesNonEmptyConstraint<Exclude<UpdateValues, undefined>> & MutationValuesDialectConstraint<Exclude<UpdateValues, undefined>, Dialect, TextDb, NumericDb, BoolDb, TimestampDb, NullDb>
6386
6478
  ) => QueryPlan<
6387
6479
  {},
@@ -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 }))