effect-qb 0.13.0 → 0.15.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 (146) hide show
  1. package/README.md +6 -1431
  2. package/dist/mysql.js +61945 -3611
  3. package/dist/postgres/metadata.js +2818 -0
  4. package/dist/postgres.js +9942 -5591
  5. package/package.json +21 -10
  6. package/src/internal/aggregation-validation.ts +3 -3
  7. package/src/internal/case-analysis.d.ts +18 -0
  8. package/src/internal/case-analysis.ts +4 -4
  9. package/src/internal/coercion/analysis.d.ts +7 -0
  10. package/src/internal/{coercion-analysis.ts → coercion/analysis.ts} +3 -3
  11. package/src/internal/coercion/errors.d.ts +17 -0
  12. package/src/internal/{coercion-errors.ts → coercion/errors.ts} +1 -1
  13. package/src/internal/coercion/kind.d.ts +4 -0
  14. package/src/internal/{coercion-kind.ts → coercion/kind.ts} +2 -2
  15. package/src/internal/{coercion-normalize.ts → coercion/normalize.ts} +1 -1
  16. package/src/internal/coercion/rules.d.ts +6 -0
  17. package/src/internal/{coercion-rules.ts → coercion/rules.ts} +2 -2
  18. package/src/internal/column-state.d.ts +190 -0
  19. package/src/internal/column-state.ts +119 -56
  20. package/src/internal/column.ts +387 -149
  21. package/src/internal/datatypes/define.d.ts +17 -0
  22. package/src/internal/datatypes/define.ts +18 -34
  23. package/src/internal/datatypes/lookup.d.ts +44 -0
  24. package/src/internal/datatypes/lookup.ts +61 -152
  25. package/src/internal/datatypes/shape.d.ts +16 -0
  26. package/src/internal/datatypes/shape.ts +1 -1
  27. package/src/internal/derived-table.d.ts +4 -0
  28. package/src/internal/derived-table.ts +21 -16
  29. package/src/internal/dsl-mutation-runtime.ts +378 -0
  30. package/src/internal/dsl-plan-runtime.ts +387 -0
  31. package/src/internal/dsl-query-runtime.ts +160 -0
  32. package/src/internal/dsl-transaction-ddl-runtime.ts +263 -0
  33. package/src/internal/executor.ts +173 -38
  34. package/src/internal/expression-ast.ts +19 -5
  35. package/src/internal/grouping-key.d.ts +3 -0
  36. package/src/internal/grouping-key.ts +1 -1
  37. package/src/internal/implication-runtime.d.ts +15 -0
  38. package/src/internal/implication-runtime.ts +171 -0
  39. package/src/internal/json/ast.d.ts +30 -0
  40. package/src/internal/json/ast.ts +1 -1
  41. package/src/internal/json/errors.d.ts +8 -0
  42. package/src/internal/json/path.d.ts +75 -0
  43. package/src/internal/json/path.ts +1 -1
  44. package/src/internal/json/types.d.ts +62 -0
  45. package/src/internal/predicate/analysis.d.ts +20 -0
  46. package/src/internal/{predicate-analysis.ts → predicate/analysis.ts} +13 -3
  47. package/src/internal/predicate/atom.d.ts +28 -0
  48. package/src/internal/{predicate-branches.ts → predicate/branches.ts} +2 -2
  49. package/src/internal/predicate/context.d.ts +67 -0
  50. package/src/internal/{predicate-context.ts → predicate/context.ts} +111 -32
  51. package/src/internal/predicate/formula.d.ts +35 -0
  52. package/src/internal/{predicate-formula.ts → predicate/formula.ts} +32 -20
  53. package/src/internal/predicate/key.d.ts +11 -0
  54. package/src/internal/{predicate-key.ts → predicate/key.ts} +2 -2
  55. package/src/internal/{predicate-nnf.ts → predicate/nnf.ts} +2 -2
  56. package/src/internal/predicate/normalize.d.ts +53 -0
  57. package/src/internal/predicate/normalize.ts +273 -0
  58. package/src/internal/predicate/runtime.d.ts +31 -0
  59. package/src/internal/predicate/runtime.ts +679 -0
  60. package/src/internal/projection-alias.d.ts +13 -0
  61. package/src/internal/projections.d.ts +31 -0
  62. package/src/internal/projections.ts +1 -1
  63. package/src/internal/query-ast.d.ts +217 -0
  64. package/src/internal/query-ast.ts +1 -1
  65. package/src/internal/query-requirements.d.ts +20 -0
  66. package/src/internal/query.d.ts +775 -0
  67. package/src/internal/query.ts +767 -275
  68. package/src/internal/renderer.ts +7 -21
  69. package/src/internal/row-set.d.ts +53 -0
  70. package/src/internal/{plan.ts → row-set.ts} +23 -11
  71. package/src/internal/{runtime-normalize.ts → runtime/normalize.ts} +9 -31
  72. package/src/internal/{runtime-schema.ts → runtime/schema.ts} +84 -55
  73. package/src/internal/runtime/value.d.ts +22 -0
  74. package/src/internal/{runtime-value.ts → runtime/value.ts} +2 -2
  75. package/src/internal/scalar.d.ts +107 -0
  76. package/src/internal/scalar.ts +191 -0
  77. package/src/internal/schema-derivation.d.ts +105 -0
  78. package/src/internal/schema-derivation.ts +93 -21
  79. package/src/internal/schema-expression.d.ts +18 -0
  80. package/src/internal/schema-expression.ts +75 -0
  81. package/src/internal/table-options.d.ts +94 -0
  82. package/src/internal/table-options.ts +94 -8
  83. package/src/internal/table.d.ts +173 -0
  84. package/src/internal/table.ts +135 -54
  85. package/src/mysql/column.ts +95 -18
  86. package/src/mysql/datatypes/index.ts +58 -3
  87. package/src/mysql/errors/generated.ts +57336 -0
  88. package/src/mysql/errors/index.ts +1 -0
  89. package/src/mysql/errors/normalize.ts +55 -53
  90. package/src/mysql/errors/types.ts +74 -0
  91. package/src/mysql/executor.ts +69 -7
  92. package/src/mysql/function/aggregate.ts +1 -5
  93. package/src/mysql/function/core.ts +1 -3
  94. package/src/mysql/function/index.ts +1 -1
  95. package/src/mysql/function/string.ts +1 -5
  96. package/src/mysql/function/temporal.ts +12 -15
  97. package/src/mysql/function/window.ts +1 -6
  98. package/src/{internal/mysql-dialect.ts → mysql/internal/dialect.ts} +1 -1
  99. package/src/mysql/internal/dsl.ts +6115 -0
  100. package/src/{internal/mysql-renderer.ts → mysql/internal/renderer.ts} +6 -6
  101. package/src/mysql/internal/sql-expression-renderer.ts +1455 -0
  102. package/src/mysql/json.ts +2 -0
  103. package/src/mysql/query.ts +111 -86
  104. package/src/mysql/renderer.ts +1 -1
  105. package/src/mysql/table.ts +1 -1
  106. package/src/mysql.ts +6 -4
  107. package/src/postgres/cast.ts +30 -0
  108. package/src/postgres/column.ts +178 -20
  109. package/src/postgres/datatypes/index.d.ts +515 -0
  110. package/src/postgres/datatypes/index.ts +49 -5
  111. package/src/postgres/datatypes/spec.d.ts +412 -0
  112. package/src/postgres/errors/generated.ts +2636 -0
  113. package/src/postgres/errors/index.ts +1 -0
  114. package/src/postgres/errors/normalize.ts +47 -62
  115. package/src/postgres/errors/types.ts +92 -34
  116. package/src/postgres/executor.ts +37 -5
  117. package/src/postgres/function/aggregate.ts +1 -5
  118. package/src/postgres/function/core.ts +20 -2
  119. package/src/postgres/function/index.ts +1 -1
  120. package/src/postgres/function/string.ts +1 -5
  121. package/src/postgres/function/temporal.ts +12 -15
  122. package/src/postgres/function/window.ts +1 -6
  123. package/src/{internal/postgres-dialect.ts → postgres/internal/dialect.ts} +1 -1
  124. package/src/{internal/query-factory.ts → postgres/internal/dsl.ts} +1568 -2120
  125. package/src/{internal/postgres-renderer.ts → postgres/internal/renderer.ts} +6 -6
  126. package/src/postgres/internal/schema-ddl.ts +108 -0
  127. package/src/postgres/internal/schema-model.ts +150 -0
  128. package/src/{internal → postgres/internal}/sql-expression-renderer.ts +112 -46
  129. package/src/postgres/json.ts +493 -0
  130. package/src/postgres/metadata.ts +31 -0
  131. package/src/postgres/query.ts +113 -86
  132. package/src/postgres/renderer.ts +3 -13
  133. package/src/postgres/schema-expression.ts +17 -0
  134. package/src/postgres/schema-management.ts +204 -0
  135. package/src/postgres/schema.ts +35 -0
  136. package/src/postgres/table.ts +316 -42
  137. package/src/postgres/type.ts +31 -0
  138. package/src/postgres.ts +20 -4
  139. package/CHANGELOG.md +0 -134
  140. package/src/internal/expression.ts +0 -327
  141. package/src/internal/predicate-normalize.ts +0 -202
  142. package/src/mysql/function/json.ts +0 -4
  143. package/src/mysql/private/query.ts +0 -13
  144. package/src/postgres/function/json.ts +0 -4
  145. package/src/postgres/private/query.ts +0 -13
  146. /package/src/internal/{predicate-atom.ts → predicate/atom.ts} +0 -0
@@ -0,0 +1,191 @@
1
+ import type { Pipeable } from "effect/Pipeable"
2
+ import type * as Schema from "effect/Schema"
3
+ import type { RuntimeOfDbType as RuntimeOfDbTypeLookup } from "./datatypes/lookup.js"
4
+ import type { DatatypeTraits, RuntimeTag } from "./datatypes/shape.js"
5
+
6
+ export type {
7
+ BigIntString,
8
+ DecimalString,
9
+ InstantString,
10
+ JsonPrimitive,
11
+ JsonValue,
12
+ LocalDateString,
13
+ LocalDateTimeString,
14
+ LocalTimeString,
15
+ OffsetTimeString,
16
+ YearString
17
+ } from "./runtime/value.js"
18
+
19
+ /** Symbol used to attach expression metadata to runtime values. */
20
+ export const TypeId: unique symbol = Symbol.for("effect-qb/Expression")
21
+
22
+ export type TypeId = typeof TypeId
23
+
24
+ /** Scope-local binding identifier used for dependency tracking. */
25
+ export type BindingId = string
26
+ /**
27
+ * Three-state nullability lattice.
28
+ *
29
+ * `"never"` means non-null, `"maybe"` means nullable, and `"always"` means the
30
+ * expression is known to be `null`.
31
+ */
32
+ export type Nullability = "never" | "maybe" | "always"
33
+
34
+ /**
35
+ * High-level classification of an expression.
36
+ *
37
+ * - `scalar`: regular per-row expression
38
+ * - `aggregate`: grouped expression such as `count(*)`
39
+ * - `window`: windowed expression such as `row_number() over (...)`
40
+ */
41
+ export type ScalarKind = "scalar" | "aggregate" | "window"
42
+
43
+ /** Database-type descriptors carried alongside decoded runtime types. */
44
+ export declare namespace DbType {
45
+ /** Base SQL type descriptor. */
46
+ export interface Base<Dialect extends string, Kind extends string> {
47
+ readonly dialect: Dialect
48
+ readonly kind: Kind
49
+ readonly family?: string
50
+ readonly runtime?: RuntimeTag
51
+ readonly compareGroup?: string
52
+ readonly castTargets?: readonly string[]
53
+ readonly traits?: DatatypeTraits
54
+ }
55
+
56
+ /** JSON-like database type. */
57
+ export interface Json<
58
+ Dialect extends string = string,
59
+ SchemaName extends string = "json"
60
+ > extends Base<Dialect, SchemaName>
61
+ {
62
+ readonly variant: SchemaName extends "jsonb" ? "jsonb" : "json"
63
+ }
64
+
65
+ /** Array database type. */
66
+ export interface Array<
67
+ Dialect extends string = string,
68
+ Element extends Any = any,
69
+ Kind extends string = string
70
+ > extends Base<Dialect, Kind> {
71
+ readonly element: Element
72
+ }
73
+
74
+ /** Range database type. */
75
+ export interface Range<
76
+ Dialect extends string = string,
77
+ Subtype extends Any = any,
78
+ Kind extends string = string
79
+ > extends Base<Dialect, Kind> {
80
+ readonly subtype: Subtype
81
+ }
82
+
83
+ /** Multirange database type. */
84
+ export interface Multirange<
85
+ Dialect extends string = string,
86
+ Subtype extends Any = any,
87
+ Kind extends string = string
88
+ > extends Base<Dialect, Kind> {
89
+ readonly subtype: Subtype
90
+ }
91
+
92
+ /** Composite/record database type. */
93
+ export interface Composite<
94
+ Dialect extends string = string,
95
+ Fields extends Record<string, Any> = Record<string, any>,
96
+ Kind extends string = string
97
+ > extends Base<Dialect, Kind> {
98
+ readonly fields: Fields
99
+ }
100
+
101
+ /** Named domain database type. */
102
+ export interface Domain<
103
+ Dialect extends string = string,
104
+ BaseType extends Any = any,
105
+ Kind extends string = string
106
+ > extends Base<Dialect, Kind> {
107
+ readonly base: BaseType
108
+ }
109
+
110
+ /** Enumeration database type. */
111
+ export interface Enum<
112
+ Dialect extends string = string,
113
+ Kind extends string = string
114
+ > extends Base<Dialect, Kind> {
115
+ readonly variant: "enum"
116
+ }
117
+
118
+ /** Set database type. */
119
+ export interface Set<
120
+ Dialect extends string = string,
121
+ Kind extends string = string
122
+ > extends Base<Dialect, Kind> {
123
+ readonly variant: "set"
124
+ }
125
+
126
+ export type Any =
127
+ | Json
128
+ | Base<string, string>
129
+ | Array<string, any, string>
130
+ | Range<string, any, string>
131
+ | Multirange<string, any, string>
132
+ | Composite<string, Record<string, any>, string>
133
+ | Domain<string, any, string>
134
+ | Enum<string, string>
135
+ | Set<string, string>
136
+ }
137
+
138
+ /** Canonical static metadata stored on an expression. */
139
+ export interface State<
140
+ Runtime,
141
+ Db extends DbType.Any,
142
+ Nullable extends Nullability,
143
+ Dialect extends string,
144
+ Kind extends ScalarKind,
145
+ Deps extends BindingId = never
146
+ > {
147
+ readonly runtime: Runtime
148
+ readonly dbType: Db
149
+ readonly runtimeSchema?: Schema.Schema.Any
150
+ readonly nullability: Nullable
151
+ readonly dialect: Dialect
152
+ readonly kind: Kind
153
+ readonly dependencies: Record<string, true>
154
+ }
155
+
156
+ /**
157
+ * A typed scalar SQL expression.
158
+ *
159
+ * `Runtime` is the decoded TypeScript type while `Db` captures the SQL-level
160
+ * type identity. Both are needed: multiple SQL types may decode to the same
161
+ * runtime type but still have different comparison/cast semantics.
162
+ */
163
+ export interface Scalar<
164
+ Runtime,
165
+ Db extends DbType.Any,
166
+ Nullable extends Nullability = "never",
167
+ Dialect extends string = Db["dialect"],
168
+ Kind extends ScalarKind = "scalar",
169
+ Deps extends BindingId = never,
170
+ GroupKey extends string = string
171
+ > extends Pipeable {
172
+ readonly [TypeId]: State<Runtime, Db, Nullable, Dialect, Kind, Deps>
173
+ }
174
+
175
+ /** Convenience alias for any expression-like value. */
176
+ export type Any = Scalar<any, DbType.Any, Nullability, string, ScalarKind, BindingId, string>
177
+ /** Extracts an expression's decoded runtime type. */
178
+ export type RuntimeOf<Value extends Any> = Value[typeof TypeId]["runtime"]
179
+ /** Extracts an expression's database-type descriptor. */
180
+ export type DbTypeOf<Value extends Any> = Value[typeof TypeId]["dbType"]
181
+ /** Extracts an expression's nullability state. */
182
+ export type NullabilityOf<Value extends Any> = Value[typeof TypeId]["nullability"]
183
+ /** Extracts an expression's kind. */
184
+ export type KindOf<Value extends Any> = Value[typeof TypeId]["kind"]
185
+ /** Extracts an expression's source dependency union. */
186
+ export type DependenciesOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, infer Deps> ? Deps : never
187
+ /** Extracts an expression's grouping identity. */
188
+ export type GroupKeyOf<Value extends Any> = Value extends Scalar<any, any, any, any, any, any, infer GroupKey> ? GroupKey : never
189
+
190
+ /** Maps a database type descriptor back to its decoded runtime type. */
191
+ export type RuntimeOfDbType<Db extends DbType.Any> = RuntimeOfDbTypeLookup<Db>
@@ -0,0 +1,105 @@
1
+ import * as VariantSchema from "@effect/experimental/VariantSchema";
2
+ import type * as Brand from "effect/Brand";
3
+ import * as Schema from "effect/Schema";
4
+ import { type AnyColumnDefinition, type HasDefault, type InsertType, type IsGenerated, type IsNullable, type SelectType, type UpdateType } from "./column-state.js";
5
+ /** Variant-schema helper used to derive select / insert / update schemas. */
6
+ export declare const TableSchema: {
7
+ readonly Struct: <const A extends VariantSchema.Struct.Fields>(fields: A & VariantSchema.Struct.Validate<A, "insert" | "select" | "update">) => VariantSchema.Struct<A>;
8
+ readonly Field: <const A extends VariantSchema.Field.ConfigWithKeys<"insert" | "select" | "update">>(config: A & { readonly [K in Exclude<keyof A, "insert" | "select" | "update">]: never; }) => VariantSchema.Field<A>;
9
+ readonly FieldOnly: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Keys[number]]: S; }>;
10
+ readonly FieldExcept: <const Keys extends readonly ("insert" | "select" | "update")[]>(...keys: Keys) => <S extends Schema.Schema.All | Schema.PropertySignature.All<PropertyKey>>(schema: S) => VariantSchema.Field<{ readonly [K in Exclude<"insert", Keys[number]> | Exclude<"select", Keys[number]> | Exclude<"update", Keys[number]>]: S; }>;
11
+ readonly fieldEvolve: {
12
+ <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
13
+ readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
14
+ readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
15
+ readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
16
+ }>(f: Mapping): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping ? Mapping[K] extends (arg: any) => any ? ReturnType<Mapping[K]> : S_1[K] : S_1[K]; } : {
17
+ readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping ? Mapping[T] extends (arg: any) => any ? ReturnType<Mapping[T]> : Self : Self : never : never;
18
+ readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping ? Mapping[T_1] extends (arg: any) => any ? ReturnType<Mapping[T_1]> : Self : Self : never : never;
19
+ readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping ? Mapping[T_2] extends (arg: any) => any ? ReturnType<Mapping[T_2]> : Self : Self : never : never;
20
+ }>;
21
+ <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_1 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: ((variant: S[K]) => VariantSchema.Field.ValueAny) | undefined; } : {
22
+ readonly insert?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
23
+ readonly select?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
24
+ readonly update?: ((variant: Self) => VariantSchema.Field.ValueAny) | undefined;
25
+ }>(self: Self, f: Mapping_1): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_1 ? Mapping_1[K] extends (arg: any) => any ? ReturnType<Mapping_1[K]> : S_1[K] : S_1[K]; } : {
26
+ readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_1 ? Mapping_1[T] extends (arg: any) => any ? ReturnType<Mapping_1[T]> : Self : Self : never : never;
27
+ readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_1 ? Mapping_1[T_1] extends (arg: any) => any ? ReturnType<Mapping_1[T_1]> : Self : Self : never : never;
28
+ readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_1 ? Mapping_1[T_2] extends (arg: any) => any ? ReturnType<Mapping_1[T_2]> : Self : Self : never : never;
29
+ }>;
30
+ };
31
+ readonly fieldFromKey: {
32
+ <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_2 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
33
+ readonly insert?: string | undefined;
34
+ readonly select?: string | undefined;
35
+ readonly update?: string | undefined;
36
+ }>(mapping: Mapping_2): (self: Self) => VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_2 ? Mapping_2[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_2[K]> : S_1[K] : S_1[K]; } : {
37
+ readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_2 ? Mapping_2[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T]> : Self : Self : never : never;
38
+ readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_2 ? Mapping_2[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_1]> : Self : Self : never : never;
39
+ readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_2 ? Mapping_2[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_2[T_2]> : Self : Self : never : never;
40
+ }>;
41
+ <Self extends VariantSchema.Field<any> | VariantSchema.Field.ValueAny, const Mapping_3 extends Self extends VariantSchema.Field<infer S extends VariantSchema.Field.Config> ? { readonly [K in keyof S]?: string | undefined; } : {
42
+ readonly insert?: string | undefined;
43
+ readonly select?: string | undefined;
44
+ readonly update?: string | undefined;
45
+ }>(self: Self, mapping: Mapping_3): VariantSchema.Field<Self extends VariantSchema.Field<infer S_1 extends VariantSchema.Field.Config> ? { readonly [K in keyof S_1]: K extends keyof Mapping_3 ? Mapping_3[K] extends string ? VariantSchema.fromKey.Rename<S_1[K], Mapping_3[K]> : S_1[K] : S_1[K]; } : {
46
+ readonly insert: "insert" extends infer T ? T extends "insert" ? T extends keyof Mapping_3 ? Mapping_3[T] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T]> : Self : Self : never : never;
47
+ readonly select: "select" extends infer T_1 ? T_1 extends "select" ? T_1 extends keyof Mapping_3 ? Mapping_3[T_1] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_1]> : Self : Self : never : never;
48
+ readonly update: "update" extends infer T_2 ? T_2 extends "update" ? T_2 extends keyof Mapping_3 ? Mapping_3[T_2] extends string ? VariantSchema.fromKey.Rename<Self, Mapping_3[T_2]> : Self : Self : never : never;
49
+ }>;
50
+ };
51
+ readonly Class: <Self = never>(identifier: string) => <const Fields extends VariantSchema.Struct.Fields>(fields: Fields & VariantSchema.Struct.Validate<Fields, "insert" | "select" | "update">, annotations?: Schema.Annotations.Schema<Self, readonly []> | undefined) => [Self] extends [never] ? "Missing `Self` generic - use `class Self extends Class<Self>()({ ... })`" : VariantSchema.Class<Self, Fields, VariantSchema.ExtractFields<"select", Fields, true>, Schema.Struct.Type<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Struct.Encoded<VariantSchema.ExtractFields<"select", Fields, true>>, Schema.Schema.Context<VariantSchema.ExtractFields<"select", Fields, true>[keyof VariantSchema.ExtractFields<"select", Fields, true>]>, Schema.Struct.Constructor<VariantSchema.ExtractFields<"select", Fields, true>>> & {
52
+ readonly insert: Schema.Struct<VariantSchema.ExtractFields<"insert", Fields, false> extends infer T ? { [K in keyof T]: T[K]; } : never>;
53
+ readonly select: Schema.Struct<VariantSchema.ExtractFields<"select", Fields, false> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never>;
54
+ readonly update: Schema.Struct<VariantSchema.ExtractFields<"update", Fields, false> extends infer T_2 ? { [K in keyof T_2]: T_2[K]; } : never>;
55
+ };
56
+ readonly Union: <const Members extends readonly VariantSchema.Struct<any>[]>(...members: Members) => VariantSchema.Union<Members> & VariantSchema.Union.Variants<Members, "insert" | "select" | "update">;
57
+ readonly extract: {
58
+ <V extends "insert" | "select" | "update">(variant: V): <A extends VariantSchema.Struct<any>>(self: A) => VariantSchema.Extract<V, A, V extends "select" ? true : false>;
59
+ <V extends "insert" | "select" | "update", A extends VariantSchema.Struct<any>>(self: A, variant: V): VariantSchema.Extract<V, A, V extends "select" ? true : false>;
60
+ };
61
+ };
62
+ /** Normalized field map used by table definitions. */
63
+ export type TableFieldMap = Record<string, AnyColumnDefinition>;
64
+ type GeneratedKeys<Fields extends TableFieldMap> = {
65
+ [K in keyof Fields]: IsGenerated<Fields[K]> extends true ? K : never;
66
+ }[keyof Fields];
67
+ type OptionalInsertKeys<Fields extends TableFieldMap> = {
68
+ [K in keyof Fields]: IsGenerated<Fields[K]> extends true ? never : IsNullable<Fields[K]> extends true ? K : HasDefault<Fields[K]> extends true ? K : never;
69
+ }[keyof Fields];
70
+ type RequiredInsertKeys<Fields extends TableFieldMap> = Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>;
71
+ type UpdateKeys<Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Exclude<keyof Fields, GeneratedKeys<Fields> | PrimaryKey>;
72
+ type Simplify<T> = {
73
+ [K in keyof T]: T[K];
74
+ } & {};
75
+ type BrandedValue<Value, BrandName extends string> = [Extract<Value, null | undefined>] extends [never] ? Value & Brand.Brand<BrandName> : (Exclude<Value, null | undefined> & Brand.Brand<BrandName>) | Extract<Value, null | undefined>;
76
+ type BrandNameOf<TableName extends string, ColumnName extends string> = `${TableName}.${ColumnName}`;
77
+ type BrandedSelectType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<SelectType<Column>, BrandNameOf<TableName, ColumnName>> : SelectType<Column>;
78
+ type BrandedInsertType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<InsertType<Column>, BrandNameOf<TableName, ColumnName>> : InsertType<Column>;
79
+ type BrandedUpdateType<Column extends AnyColumnDefinition, TableName extends string, ColumnName extends string> = Column["metadata"]["brand"] extends true ? BrandedValue<UpdateType<Column>, BrandNameOf<TableName, ColumnName>> : UpdateType<Column>;
80
+ /** Row shape returned by selecting from a table. */
81
+ export type SelectRow<TableName extends string, Fields extends TableFieldMap> = Simplify<{
82
+ [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>;
83
+ }>;
84
+ /** Insert payload derived from a table field map. */
85
+ export type InsertRow<TableName extends string, Fields extends TableFieldMap> = Simplify<{
86
+ [K in RequiredInsertKeys<Fields>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>;
87
+ } & {
88
+ [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>>;
89
+ }>;
90
+ /** Update payload derived from a table field map and primary key. */
91
+ export type UpdateRow<TableName extends string, Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Simplify<Partial<{
92
+ [K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>;
93
+ }>>;
94
+ /**
95
+ * Derives the `select`, `insert`, and `update` schemas for a table.
96
+ *
97
+ * This is the central place where the column capability flags are turned into
98
+ * real runtime schemas.
99
+ */
100
+ export declare const deriveSchemas: <TableName extends string, Fields extends TableFieldMap, PrimaryKeyColumns extends keyof Fields & string>(tableName: TableName, fields: Fields, primaryKeyColumns: readonly PrimaryKeyColumns[]) => {
101
+ readonly select: Schema.Schema<{ [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, { [K in keyof { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }]: { [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>; }[K]; }, never>;
102
+ readonly insert: Schema.Schema<{ [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, { [K in Exclude<keyof Fields, GeneratedKeys<Fields> | OptionalInsertKeys<Fields>>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>>; } & { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never, never>;
103
+ readonly update: Schema.Schema<Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, Partial<{ [K in Exclude<keyof Fields, PrimaryKeyColumns | GeneratedKeys<Fields>>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>; }> extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never, never>;
104
+ };
105
+ export {};
@@ -1,4 +1,5 @@
1
1
  import * as VariantSchema from "@effect/experimental/VariantSchema"
2
+ import type * as Brand from "effect/Brand"
2
3
  import * as Schema from "effect/Schema"
3
4
 
4
5
  import {
@@ -43,43 +44,112 @@ type UpdateKeys<Fields extends TableFieldMap, PrimaryKey extends keyof Fields> =
43
44
 
44
45
  type Simplify<T> = { [K in keyof T]: T[K] } & {}
45
46
 
47
+ type BrandedValue<
48
+ Value,
49
+ BrandName extends string
50
+ > = [Extract<Value, null | undefined>] extends [never]
51
+ ? Value & Brand.Brand<BrandName>
52
+ : Exclude<Value, null | undefined> & Brand.Brand<BrandName> | Extract<Value, null | undefined>
53
+
54
+ type BrandNameOf<
55
+ TableName extends string,
56
+ ColumnName extends string
57
+ > = `${TableName}.${ColumnName}`
58
+
59
+ type BrandedSelectType<
60
+ Column extends AnyColumnDefinition,
61
+ TableName extends string,
62
+ ColumnName extends string
63
+ > = Column["metadata"]["brand"] extends true
64
+ ? BrandedValue<SelectType<Column>, BrandNameOf<TableName, ColumnName>>
65
+ : SelectType<Column>
66
+
67
+ type BrandedInsertType<
68
+ Column extends AnyColumnDefinition,
69
+ TableName extends string,
70
+ ColumnName extends string
71
+ > = Column["metadata"]["brand"] extends true
72
+ ? BrandedValue<InsertType<Column>, BrandNameOf<TableName, ColumnName>>
73
+ : InsertType<Column>
74
+
75
+ type BrandedUpdateType<
76
+ Column extends AnyColumnDefinition,
77
+ TableName extends string,
78
+ ColumnName extends string
79
+ > = Column["metadata"]["brand"] extends true
80
+ ? BrandedValue<UpdateType<Column>, BrandNameOf<TableName, ColumnName>>
81
+ : UpdateType<Column>
82
+
46
83
  /** Row shape returned by selecting from a table. */
47
- export type SelectRow<Fields extends TableFieldMap> = Simplify<{
48
- [K in keyof Fields]: SelectType<Fields[K]>
84
+ export type SelectRow<
85
+ TableName extends string,
86
+ Fields extends TableFieldMap
87
+ > = Simplify<{
88
+ [K in keyof Fields]: BrandedSelectType<Fields[K], TableName, Extract<K, string>>
49
89
  }>
50
90
 
51
91
  /** Insert payload derived from a table field map. */
52
- export type InsertRow<Fields extends TableFieldMap> = Simplify<
53
- { [K in RequiredInsertKeys<Fields>]: InsertType<Fields[K]> } &
54
- { [K in OptionalInsertKeys<Fields>]?: InsertType<Fields[K]> }
92
+ export type InsertRow<
93
+ TableName extends string,
94
+ Fields extends TableFieldMap
95
+ > = Simplify<
96
+ { [K in RequiredInsertKeys<Fields>]: BrandedInsertType<Fields[K], TableName, Extract<K, string>> } &
97
+ { [K in OptionalInsertKeys<Fields>]?: BrandedInsertType<Fields[K], TableName, Extract<K, string>> }
55
98
  >
56
99
 
57
100
  /** Update payload derived from a table field map and primary key. */
58
- export type UpdateRow<Fields extends TableFieldMap, PrimaryKey extends keyof Fields> = Simplify<
101
+ export type UpdateRow<
102
+ TableName extends string,
103
+ Fields extends TableFieldMap,
104
+ PrimaryKey extends keyof Fields
105
+ > = Simplify<
59
106
  Partial<{
60
- [K in UpdateKeys<Fields, PrimaryKey>]: UpdateType<Fields[K]>
107
+ [K in UpdateKeys<Fields, PrimaryKey>]: BrandedUpdateType<Fields[K], TableName, Extract<K, string>>
61
108
  }>
62
109
  >
63
110
 
64
- const selectSchema = (column: AnyColumnDefinition): Schema.Schema.Any =>
65
- column.metadata.nullable ? Schema.NullOr(column.schema) : column.schema
111
+ const maybeBrandSchema = (
112
+ column: AnyColumnDefinition,
113
+ tableName: string,
114
+ columnName: string
115
+ ): Schema.Schema.Any =>
116
+ column.metadata.brand === true
117
+ ? Schema.brand(`${tableName}.${columnName}`)(column.schema)
118
+ : column.schema
119
+
120
+ const selectSchema = (
121
+ column: AnyColumnDefinition,
122
+ tableName: string,
123
+ columnName: string
124
+ ): Schema.Schema.Any =>
125
+ column.metadata.nullable ? Schema.NullOr(maybeBrandSchema(column, tableName, columnName)) : maybeBrandSchema(column, tableName, columnName)
66
126
 
67
- const insertSchema = (column: AnyColumnDefinition): any | undefined => {
127
+ const insertSchema = (
128
+ column: AnyColumnDefinition,
129
+ tableName: string,
130
+ columnName: string
131
+ ): any | undefined => {
68
132
  if (column.metadata.generated) {
69
133
  return undefined
70
134
  }
71
- const base = column.metadata.nullable ? Schema.NullOr(column.schema) : column.schema
135
+ const base = column.metadata.nullable
136
+ ? Schema.NullOr(maybeBrandSchema(column, tableName, columnName))
137
+ : maybeBrandSchema(column, tableName, columnName)
72
138
  return column.metadata.nullable || column.metadata.hasDefault ? Schema.optional(base) : base
73
139
  }
74
140
 
75
141
  const updateSchema = (
76
142
  column: AnyColumnDefinition,
143
+ tableName: string,
144
+ columnName: string,
77
145
  isPrimaryKey: boolean
78
146
  ): any | undefined => {
79
147
  if (column.metadata.generated || isPrimaryKey) {
80
148
  return undefined
81
149
  }
82
- const base = column.metadata.nullable ? Schema.NullOr(column.schema) : column.schema
150
+ const base = column.metadata.nullable
151
+ ? Schema.NullOr(maybeBrandSchema(column, tableName, columnName))
152
+ : maybeBrandSchema(column, tableName, columnName)
83
153
  return Schema.optional(base)
84
154
  }
85
155
 
@@ -90,26 +160,28 @@ const updateSchema = (
90
160
  * real runtime schemas.
91
161
  */
92
162
  export const deriveSchemas = <
163
+ TableName extends string,
93
164
  Fields extends TableFieldMap,
94
165
  PrimaryKeyColumns extends keyof Fields & string
95
166
  >(
167
+ tableName: TableName,
96
168
  fields: Fields,
97
169
  primaryKeyColumns: readonly PrimaryKeyColumns[]
98
170
  ): {
99
- readonly select: Schema.Schema<SelectRow<Fields>>
100
- readonly insert: Schema.Schema<InsertRow<Fields>>
101
- readonly update: Schema.Schema<UpdateRow<Fields, PrimaryKeyColumns>>
171
+ readonly select: Schema.Schema<SelectRow<TableName, Fields>>
172
+ readonly insert: Schema.Schema<InsertRow<TableName, Fields>>
173
+ readonly update: Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
102
174
  } => {
103
175
  const primaryKeySet = new Set<string>(primaryKeyColumns)
104
176
  const variants: Record<string, VariantSchema.Field<any>> = {}
105
177
  for (const [key, column] of Object.entries(fields)) {
106
178
  const config: Record<Variants, any> = {
107
- select: selectSchema(column),
179
+ select: selectSchema(column, tableName, key),
108
180
  insert: undefined,
109
181
  update: undefined
110
182
  }
111
- const insert = insertSchema(column)
112
- const update = updateSchema(column, primaryKeySet.has(key))
183
+ const insert = insertSchema(column, tableName, key)
184
+ const update = updateSchema(column, tableName, key, primaryKeySet.has(key))
113
185
  if (insert !== undefined) {
114
186
  config.insert = insert
115
187
  } else {
@@ -124,8 +196,8 @@ export const deriveSchemas = <
124
196
  }
125
197
  const struct = TableSchema.Struct(variants as any)
126
198
  return {
127
- select: TableSchema.extract(struct, "select") as unknown as Schema.Schema<SelectRow<Fields>>,
128
- insert: TableSchema.extract(struct, "insert") as unknown as Schema.Schema<InsertRow<Fields>>,
129
- update: TableSchema.extract(struct, "update") as unknown as Schema.Schema<UpdateRow<Fields, PrimaryKeyColumns>>
199
+ select: TableSchema.extract(struct, "select") as unknown as Schema.Schema<SelectRow<TableName, Fields>>,
200
+ insert: TableSchema.extract(struct, "insert") as unknown as Schema.Schema<InsertRow<TableName, Fields>>,
201
+ update: TableSchema.extract(struct, "update") as unknown as Schema.Schema<UpdateRow<TableName, Fields, PrimaryKeyColumns>>
130
202
  }
131
203
  }
@@ -0,0 +1,18 @@
1
+ import { type Expr } from "pgsql-ast-parser";
2
+ import { type Pipeable } from "effect/Pipeable";
3
+ export declare const TypeId: unique symbol;
4
+ export type TypeId = typeof TypeId;
5
+ export interface SchemaExpression extends Pipeable {
6
+ readonly [TypeId]: {
7
+ readonly ast?: Expr;
8
+ readonly sql?: string;
9
+ };
10
+ }
11
+ export type Any = SchemaExpression;
12
+ export declare const isSchemaExpression: (value: unknown) => value is SchemaExpression;
13
+ export declare const fromAst: (ast: Expr) => SchemaExpression;
14
+ export declare const fromSql: (sql: string) => SchemaExpression;
15
+ export declare const parseExpression: (sql: string) => SchemaExpression;
16
+ export declare const toAst: (expression: SchemaExpression) => Expr;
17
+ export declare const render: (expression: SchemaExpression) => string;
18
+ export declare const normalize: (expression: SchemaExpression) => SchemaExpression;
@@ -0,0 +1,75 @@
1
+ import { parse, toSql, type Expr } from "pgsql-ast-parser"
2
+ import { pipeArguments, type Pipeable } from "effect/Pipeable"
3
+
4
+ export const TypeId: unique symbol = Symbol.for("effect-qb/SchemaExpression")
5
+
6
+ export type TypeId = typeof TypeId
7
+
8
+ const SchemaExpressionProto = {
9
+ pipe(this: unknown) {
10
+ return pipeArguments(this, arguments)
11
+ }
12
+ }
13
+
14
+ const attachPipe = <Value extends object>(value: Value): Value => {
15
+ Object.defineProperty(value, "pipe", {
16
+ configurable: true,
17
+ writable: true,
18
+ value: function(this: unknown) {
19
+ return pipeArguments(value, arguments)
20
+ }
21
+ })
22
+ return value
23
+ }
24
+
25
+ export interface SchemaExpression extends Pipeable {
26
+ readonly [TypeId]: {
27
+ readonly ast?: Expr
28
+ readonly sql?: string
29
+ }
30
+ }
31
+
32
+ export type Any = SchemaExpression
33
+
34
+ export const isSchemaExpression = (value: unknown): value is SchemaExpression =>
35
+ typeof value === "object" && value !== null && TypeId in value
36
+
37
+ export const fromAst = (ast: Expr): SchemaExpression => {
38
+ const expression = attachPipe(Object.create(SchemaExpressionProto))
39
+ expression[TypeId] = {
40
+ ast
41
+ }
42
+ return expression
43
+ }
44
+
45
+ export const fromSql = (sql: string): SchemaExpression => {
46
+ const expression = attachPipe(Object.create(SchemaExpressionProto))
47
+ expression[TypeId] = {
48
+ sql: sql.trim()
49
+ }
50
+ return expression
51
+ }
52
+
53
+ export const parseExpression = (sql: string): SchemaExpression =>
54
+ fromAst(parse(sql, "expr"))
55
+
56
+ export const toAst = (expression: SchemaExpression): Expr => {
57
+ const ast = expression[TypeId].ast
58
+ if (ast !== undefined) {
59
+ return ast
60
+ }
61
+ return parse(render(expression), "expr")
62
+ }
63
+
64
+ export const render = (expression: SchemaExpression): string =>
65
+ expression[TypeId].sql ?? toSql.expr(toAst(expression))
66
+
67
+ export const normalize = (expression: SchemaExpression): SchemaExpression =>
68
+ (() => {
69
+ const sql = render(expression)
70
+ try {
71
+ return parseExpression(sql)
72
+ } catch {
73
+ return fromSql(sql)
74
+ }
75
+ })()