effect-qb 0.16.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.js +8065 -0
- package/dist/mysql.js +4036 -2418
- package/dist/postgres/metadata.js +2536 -625
- package/dist/postgres.js +8248 -7857
- package/dist/sqlite.js +8854 -0
- package/dist/standard.js +8019 -0
- package/package.json +15 -3
- package/src/casing.ts +71 -0
- package/src/index.ts +2 -0
- package/src/internal/casing.ts +89 -0
- package/src/internal/column-state.ts +11 -6
- package/src/internal/column.ts +44 -7
- package/src/internal/datatypes/define.ts +2 -1
- package/src/internal/datatypes/enrich.ts +23 -0
- package/src/internal/datatypes/lookup.ts +14 -7
- package/src/internal/derived-table.ts +7 -13
- package/src/internal/dialect-renderers/mysql.ts +2046 -0
- package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +867 -283
- package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +834 -358
- package/src/internal/dialect.ts +37 -0
- package/src/internal/dsl-mutation-runtime.ts +29 -10
- package/src/internal/dsl-plan-runtime.ts +41 -24
- package/src/internal/dsl-query-runtime.ts +11 -31
- package/src/internal/dsl-transaction-ddl-runtime.ts +61 -15
- package/src/internal/executor.ts +57 -15
- package/src/internal/expression-ast.ts +3 -2
- package/src/internal/grouping-key.ts +216 -9
- package/src/internal/implication-runtime.ts +3 -2
- package/src/internal/json/types.ts +155 -40
- package/src/internal/predicate/context.ts +14 -1
- package/src/internal/predicate/key.ts +19 -2
- package/src/internal/predicate/runtime.ts +30 -3
- package/src/internal/query.d.ts +38 -11
- package/src/internal/query.ts +315 -54
- package/src/internal/renderer.ts +51 -6
- package/src/internal/runtime/driver-value-mapping.ts +58 -0
- package/src/internal/runtime/normalize.ts +74 -43
- package/src/internal/runtime/schema.ts +5 -3
- package/src/internal/runtime/value.ts +153 -30
- package/src/internal/scalar.ts +6 -1
- package/src/internal/schema-derivation.d.ts +12 -61
- package/src/internal/schema-derivation.ts +90 -38
- package/src/internal/schema-expression.ts +2 -2
- package/src/internal/sql-expression-renderer.ts +19 -0
- package/src/internal/standard-dsl.ts +6885 -0
- package/src/internal/table-options.ts +229 -62
- package/src/internal/table.d.ts +33 -32
- package/src/internal/table.ts +469 -160
- package/src/mysql/column-extension.ts +3 -0
- package/src/mysql/column.ts +27 -12
- package/src/mysql/datatypes/index.ts +24 -2
- package/src/mysql/errors/catalog.ts +5 -5
- package/src/mysql/errors/normalize.ts +2 -2
- package/src/mysql/executor.ts +7 -5
- package/src/mysql/internal/dialect.ts +9 -4
- package/src/mysql/internal/dsl.ts +906 -324
- package/src/mysql/internal/renderer.ts +7 -2
- package/src/mysql/json.ts +37 -0
- package/src/mysql/query-extension.ts +16 -0
- package/src/mysql/query.ts +9 -2
- package/src/mysql/renderer.ts +31 -4
- package/src/mysql.ts +4 -12
- package/src/postgres/column-extension.ts +28 -0
- package/src/postgres/column.ts +9 -13
- package/src/postgres/datatypes/index.d.ts +2 -1
- package/src/postgres/datatypes/index.ts +3 -2
- package/src/postgres/errors/normalize.ts +2 -2
- package/src/postgres/executor.ts +55 -10
- package/src/postgres/function/core.ts +20 -4
- package/src/postgres/function/index.ts +1 -17
- package/src/postgres/internal/dialect.ts +9 -4
- package/src/postgres/internal/dsl.ts +850 -359
- package/src/postgres/internal/renderer.ts +7 -2
- package/src/postgres/internal/schema-ddl.ts +22 -9
- package/src/postgres/internal/schema-model.ts +244 -10
- package/src/postgres/json.ts +100 -24
- package/src/postgres/jsonb.ts +38 -0
- package/src/postgres/query-extension.ts +2 -0
- package/src/postgres/query.ts +9 -2
- package/src/postgres/renderer.ts +31 -4
- package/src/postgres/schema-management.ts +108 -16
- package/src/postgres/schema.ts +98 -15
- package/src/postgres/table.ts +203 -398
- package/src/postgres/type.ts +8 -7
- package/src/postgres.ts +9 -11
- package/src/sqlite/column-extension.ts +3 -0
- package/src/sqlite/column.ts +127 -0
- package/src/sqlite/datatypes/index.ts +80 -0
- package/src/sqlite/datatypes/spec.ts +98 -0
- package/src/sqlite/errors/catalog.ts +103 -0
- package/src/sqlite/errors/fields.ts +19 -0
- package/src/sqlite/errors/index.ts +19 -0
- package/src/sqlite/errors/normalize.ts +229 -0
- package/src/sqlite/errors/requirements.ts +71 -0
- package/src/sqlite/errors/types.ts +29 -0
- package/src/sqlite/executor.ts +229 -0
- package/src/sqlite/function/aggregate.ts +2 -0
- package/src/sqlite/function/core.ts +2 -0
- package/src/sqlite/function/index.ts +19 -0
- package/src/sqlite/function/string.ts +2 -0
- package/src/sqlite/function/temporal.ts +100 -0
- package/src/sqlite/function/window.ts +2 -0
- package/src/sqlite/internal/dialect.ts +42 -0
- package/src/sqlite/internal/dsl.ts +6979 -0
- package/src/sqlite/internal/renderer.ts +51 -0
- package/src/sqlite/json.ts +39 -0
- package/src/sqlite/query-extension.ts +2 -0
- package/src/sqlite/query.ts +196 -0
- package/src/sqlite/renderer.ts +51 -0
- package/src/sqlite.ts +14 -0
- package/src/standard/column.ts +163 -0
- package/src/standard/datatypes/index.ts +83 -0
- package/src/standard/datatypes/spec.ts +98 -0
- package/src/standard/dialect.ts +40 -0
- package/src/standard/function/aggregate.ts +2 -0
- package/src/standard/function/core.ts +2 -0
- package/src/standard/function/index.ts +18 -0
- package/src/standard/function/string.ts +2 -0
- package/src/standard/function/temporal.ts +78 -0
- package/src/standard/function/window.ts +2 -0
- package/src/standard/internal/renderer.ts +45 -0
- package/src/standard/query.ts +152 -0
- package/src/standard/renderer.ts +21 -0
- package/src/standard/table.ts +147 -0
- package/src/standard.ts +18 -0
- package/src/internal/aggregation-validation.ts +0 -57
- package/src/mysql/table.ts +0 -157
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as Query from "../../internal/query.js"
|
|
2
2
|
import type * as Expression from "../../internal/scalar.js"
|
|
3
|
+
import type * as Casing from "../../internal/casing.js"
|
|
3
4
|
import { type RenderState } from "../../internal/dialect.js"
|
|
4
5
|
import { postgresDialect } from "./dialect.js"
|
|
5
6
|
import { type Projection } from "../../internal/projections.js"
|
|
6
|
-
import { renderQueryAst } from "
|
|
7
|
+
import { renderQueryAst } from "../../internal/sql-expression-renderer.js"
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Minimal rendered-query payload produced by the built-in Postgres renderer.
|
|
@@ -20,6 +21,7 @@ export interface PostgresRenderResult {
|
|
|
20
21
|
|
|
21
22
|
export interface PostgresRenderOptions {
|
|
22
23
|
readonly valueMappings?: Expression.DriverValueMappings
|
|
24
|
+
readonly casing?: Casing.Options
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -32,8 +34,11 @@ export const renderPostgresPlan = <PlanValue extends Query.Plan.Any>(
|
|
|
32
34
|
const state: RenderState = {
|
|
33
35
|
params: [],
|
|
34
36
|
valueMappings: options.valueMappings,
|
|
37
|
+
casing: options.casing,
|
|
35
38
|
ctes: [],
|
|
36
|
-
cteNames: new Set<string>()
|
|
39
|
+
cteNames: new Set<string>(),
|
|
40
|
+
cteSources: new Map<string, unknown>(),
|
|
41
|
+
sourceNames: new Map()
|
|
37
42
|
}
|
|
38
43
|
const rendered = renderQueryAst(
|
|
39
44
|
Query.getAst(plan as Query.Plan.Any) as any,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as Expression from "../../internal/scalar.js"
|
|
2
2
|
import type { RenderState, SqlDialect } from "../../internal/dialect.js"
|
|
3
3
|
import * as SchemaExpression from "../../internal/schema-expression.js"
|
|
4
|
-
import { renderExpression } from "
|
|
4
|
+
import { renderExpression } from "../../internal/sql-expression-renderer.js"
|
|
5
5
|
import type { DdlExpressionLike } from "../../internal/table-options.js"
|
|
6
6
|
import { parse, toSql } from "pgsql-ast-parser"
|
|
7
7
|
import { postgresDialect } from "./dialect.js"
|
|
@@ -30,20 +30,30 @@ const inlineLiteralDialect: SqlDialect<"postgres"> = {
|
|
|
30
30
|
return String(value)
|
|
31
31
|
}
|
|
32
32
|
if (value instanceof Date) {
|
|
33
|
+
if (Number.isNaN(value.getTime())) {
|
|
34
|
+
throw new Error("Expected a valid Date value")
|
|
35
|
+
}
|
|
33
36
|
return escapeString(value.toISOString())
|
|
34
37
|
}
|
|
35
38
|
return escapeString(String(value))
|
|
36
39
|
}
|
|
37
40
|
}
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
const makeExpressionState = (state: Partial<RenderState> = {}): RenderState => ({
|
|
43
|
+
...state,
|
|
44
|
+
params: [],
|
|
45
|
+
ctes: [],
|
|
46
|
+
cteNames: new Set(),
|
|
47
|
+
cteSources: new Map()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
export const renderDdlExpressionSql = (
|
|
51
|
+
expression: DdlExpressionLike,
|
|
52
|
+
state?: Partial<RenderState>
|
|
53
|
+
): string =>
|
|
40
54
|
SchemaExpression.isSchemaExpression(expression)
|
|
41
55
|
? SchemaExpression.render(expression)
|
|
42
|
-
: renderExpression(expression as Expression.Any,
|
|
43
|
-
params: [],
|
|
44
|
-
ctes: [],
|
|
45
|
-
cteNames: new Set()
|
|
46
|
-
}, inlineLiteralDialect)
|
|
56
|
+
: renderExpression(expression as Expression.Any, makeExpressionState(state), inlineLiteralDialect)
|
|
47
57
|
|
|
48
58
|
const stripRedundantOuterParens = (value: string): string => {
|
|
49
59
|
let current = value.trim()
|
|
@@ -98,8 +108,11 @@ const canonicalizeDdlExpressionSql = (value: string): string =>
|
|
|
98
108
|
)
|
|
99
109
|
)
|
|
100
110
|
|
|
101
|
-
export const normalizeDdlExpressionSql = (
|
|
102
|
-
|
|
111
|
+
export const normalizeDdlExpressionSql = (
|
|
112
|
+
expression: DdlExpressionLike,
|
|
113
|
+
state?: Partial<RenderState>
|
|
114
|
+
): string => {
|
|
115
|
+
const rendered = renderDdlExpressionSql(expression, state)
|
|
103
116
|
try {
|
|
104
117
|
return canonicalizeDdlExpressionSql(toSql.expr(parse(rendered, "expr")))
|
|
105
118
|
} catch {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as Table from "../../internal/table.js"
|
|
2
2
|
import type { AnyColumnDefinition } from "../../internal/column-state.js"
|
|
3
|
+
import type { RenderState } from "../../internal/dialect.js"
|
|
4
|
+
import * as Casing from "../../internal/casing.js"
|
|
5
|
+
import * as Expression from "../../internal/scalar.js"
|
|
6
|
+
import * as SchemaExpression from "../../internal/schema-expression.js"
|
|
3
7
|
import { normalizeDdlExpressionSql } from "./schema-ddl.js"
|
|
4
|
-
import type
|
|
8
|
+
import { validateOptions, type ColumnList, type DdlExpressionLike, type IndexKeySpec, type TableOptionSpec } from "../../internal/table-options.js"
|
|
5
9
|
import type { EnumDefinition } from "../schema-management.js"
|
|
6
10
|
import { EnumTypeId } from "../schema-management.js"
|
|
7
11
|
|
|
@@ -52,15 +56,238 @@ export const isTableDefinition = (value: unknown): value is Table.AnyTable =>
|
|
|
52
56
|
export const isEnumDefinition = (value: unknown): value is EnumDefinition =>
|
|
53
57
|
typeof value === "object" && value !== null && EnumTypeId in value
|
|
54
58
|
|
|
59
|
+
const applyCasing = (
|
|
60
|
+
casing: Casing.Options | undefined,
|
|
61
|
+
category: Casing.Category,
|
|
62
|
+
name: string
|
|
63
|
+
): string =>
|
|
64
|
+
Casing.applyCategory(casing, category, name)
|
|
65
|
+
|
|
66
|
+
const mapColumnList = (
|
|
67
|
+
columns: ColumnList,
|
|
68
|
+
casing: Casing.Options | undefined
|
|
69
|
+
): ColumnList =>
|
|
70
|
+
!Array.isArray(columns)
|
|
71
|
+
? columns
|
|
72
|
+
: columns.length === 0
|
|
73
|
+
? columns
|
|
74
|
+
: [
|
|
75
|
+
mapCasedValue(columns[0], casing, "columns"),
|
|
76
|
+
...columns.slice(1).map((column) => mapCasedValue(column, casing, "columns"))
|
|
77
|
+
] as ColumnList
|
|
78
|
+
|
|
79
|
+
const expressionStateForTable = (
|
|
80
|
+
state: Table.AnyTable[typeof Table.TypeId],
|
|
81
|
+
tableName: string,
|
|
82
|
+
columns: ReadonlyMap<string, string>,
|
|
83
|
+
casing: Casing.Options | undefined
|
|
84
|
+
): Partial<RenderState> => ({
|
|
85
|
+
casing,
|
|
86
|
+
rowLocalColumns: true,
|
|
87
|
+
sourceNames: new Map([
|
|
88
|
+
[state.name, { tableName, columns }],
|
|
89
|
+
[state.baseName, { tableName, columns }]
|
|
90
|
+
])
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const mapDdlExpression = (
|
|
94
|
+
expression: DdlExpressionLike,
|
|
95
|
+
state: Partial<RenderState>
|
|
96
|
+
): SchemaExpression.SchemaExpression =>
|
|
97
|
+
SchemaExpression.fromSql(normalizeDdlExpressionSql(expression, state))
|
|
98
|
+
|
|
99
|
+
function mapOptionName(
|
|
100
|
+
name: string,
|
|
101
|
+
casing: Casing.Options | undefined,
|
|
102
|
+
category: "indexes" | "constraints"
|
|
103
|
+
): string
|
|
104
|
+
function mapOptionName(
|
|
105
|
+
name: unknown,
|
|
106
|
+
casing: Casing.Options | undefined,
|
|
107
|
+
category: "indexes" | "constraints"
|
|
108
|
+
): unknown
|
|
109
|
+
function mapOptionName(
|
|
110
|
+
name: unknown,
|
|
111
|
+
casing: Casing.Options | undefined,
|
|
112
|
+
category: "indexes" | "constraints"
|
|
113
|
+
): unknown {
|
|
114
|
+
return typeof name === "string"
|
|
115
|
+
? applyCasing(casing, category, name)
|
|
116
|
+
: name
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function mapCasedValue(
|
|
120
|
+
value: string,
|
|
121
|
+
casing: Casing.Options | undefined,
|
|
122
|
+
category: Casing.Category
|
|
123
|
+
): string
|
|
124
|
+
function mapCasedValue(
|
|
125
|
+
value: unknown,
|
|
126
|
+
casing: Casing.Options | undefined,
|
|
127
|
+
category: Casing.Category
|
|
128
|
+
): unknown
|
|
129
|
+
function mapCasedValue(
|
|
130
|
+
value: unknown,
|
|
131
|
+
casing: Casing.Options | undefined,
|
|
132
|
+
category: Casing.Category
|
|
133
|
+
): unknown {
|
|
134
|
+
return typeof value === "string"
|
|
135
|
+
? applyCasing(casing, category, value)
|
|
136
|
+
: value
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const isDdlExpressionLike = (value: unknown): value is DdlExpressionLike =>
|
|
140
|
+
typeof value === "object" &&
|
|
141
|
+
value !== null &&
|
|
142
|
+
(Expression.TypeId in value || SchemaExpression.TypeId in value)
|
|
143
|
+
|
|
144
|
+
function mapIndexKey(
|
|
145
|
+
key: IndexKeySpec,
|
|
146
|
+
casing: Casing.Options | undefined,
|
|
147
|
+
expressionState: Partial<RenderState>
|
|
148
|
+
): IndexKeySpec
|
|
149
|
+
function mapIndexKey(
|
|
150
|
+
key: unknown,
|
|
151
|
+
casing: Casing.Options | undefined,
|
|
152
|
+
expressionState: Partial<RenderState>
|
|
153
|
+
): unknown
|
|
154
|
+
function mapIndexKey(
|
|
155
|
+
key: unknown,
|
|
156
|
+
casing: Casing.Options | undefined,
|
|
157
|
+
expressionState: Partial<RenderState>
|
|
158
|
+
): unknown {
|
|
159
|
+
if (typeof key !== "object" || key === null || !("kind" in key)) {
|
|
160
|
+
return key
|
|
161
|
+
}
|
|
162
|
+
const kind = (key as { readonly kind?: unknown }).kind
|
|
163
|
+
if (kind === "column") {
|
|
164
|
+
const column = (key as { readonly column?: unknown }).column
|
|
165
|
+
return typeof column === "string"
|
|
166
|
+
? {
|
|
167
|
+
...key,
|
|
168
|
+
column: applyCasing(casing, "columns", column)
|
|
169
|
+
}
|
|
170
|
+
: key
|
|
171
|
+
}
|
|
172
|
+
if (kind === "expression") {
|
|
173
|
+
const expression = (key as { readonly expression?: unknown }).expression
|
|
174
|
+
return isDdlExpressionLike(expression)
|
|
175
|
+
? {
|
|
176
|
+
...key,
|
|
177
|
+
expression: mapDdlExpression(expression, expressionState)
|
|
178
|
+
}
|
|
179
|
+
: key
|
|
180
|
+
}
|
|
181
|
+
return key
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const mapOption = (
|
|
185
|
+
option: TableOptionSpec,
|
|
186
|
+
casing: Casing.Options | undefined,
|
|
187
|
+
expressionState: Partial<RenderState>
|
|
188
|
+
): TableOptionSpec => {
|
|
189
|
+
switch (option.kind) {
|
|
190
|
+
case "index":
|
|
191
|
+
return {
|
|
192
|
+
...option,
|
|
193
|
+
columns: option.columns === undefined ? undefined : mapColumnList(option.columns, casing),
|
|
194
|
+
name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "indexes"),
|
|
195
|
+
include: option.include === undefined
|
|
196
|
+
? undefined
|
|
197
|
+
: Array.isArray(option.include)
|
|
198
|
+
? option.include.map((column) => mapCasedValue(column, casing, "columns")) as unknown as readonly string[]
|
|
199
|
+
: option.include,
|
|
200
|
+
predicate: option.predicate === undefined
|
|
201
|
+
? undefined
|
|
202
|
+
: isDdlExpressionLike(option.predicate)
|
|
203
|
+
? mapDdlExpression(option.predicate, expressionState)
|
|
204
|
+
: option.predicate,
|
|
205
|
+
keys: option.keys === undefined
|
|
206
|
+
? undefined
|
|
207
|
+
: Array.isArray(option.keys)
|
|
208
|
+
? option.keys.length === 0
|
|
209
|
+
? option.keys
|
|
210
|
+
: [
|
|
211
|
+
mapIndexKey(option.keys[0], casing, expressionState),
|
|
212
|
+
...option.keys.slice(1).map((key) => mapIndexKey(key, casing, expressionState))
|
|
213
|
+
] as unknown as readonly [IndexKeySpec, ...IndexKeySpec[]]
|
|
214
|
+
: option.keys
|
|
215
|
+
}
|
|
216
|
+
case "primaryKey":
|
|
217
|
+
return {
|
|
218
|
+
...option,
|
|
219
|
+
columns: mapColumnList(option.columns, casing),
|
|
220
|
+
name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints")
|
|
221
|
+
}
|
|
222
|
+
case "unique":
|
|
223
|
+
return {
|
|
224
|
+
...option,
|
|
225
|
+
columns: mapColumnList(option.columns, casing),
|
|
226
|
+
name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints")
|
|
227
|
+
}
|
|
228
|
+
case "foreignKey":
|
|
229
|
+
return {
|
|
230
|
+
...option,
|
|
231
|
+
columns: mapColumnList(option.columns, casing),
|
|
232
|
+
name: option.name === undefined ? undefined : mapOptionName(option.name, casing, "constraints"),
|
|
233
|
+
references: () => {
|
|
234
|
+
const reference = typeof option.references === "function"
|
|
235
|
+
? option.references()
|
|
236
|
+
: option.references
|
|
237
|
+
if (typeof reference !== "object" || reference === null) {
|
|
238
|
+
return reference
|
|
239
|
+
}
|
|
240
|
+
const referenceCasing = reference.casing
|
|
241
|
+
return {
|
|
242
|
+
...reference,
|
|
243
|
+
tableName: mapCasedValue(reference.tableName, referenceCasing, "tables"),
|
|
244
|
+
schemaName: reference.schemaName === undefined
|
|
245
|
+
? undefined
|
|
246
|
+
: mapCasedValue(reference.schemaName, referenceCasing, "schemas"),
|
|
247
|
+
columns: mapColumnList(reference.columns, referenceCasing),
|
|
248
|
+
knownColumns: reference.knownColumns === undefined
|
|
249
|
+
? undefined
|
|
250
|
+
: Array.isArray(reference.knownColumns)
|
|
251
|
+
? reference.knownColumns.map((column) =>
|
|
252
|
+
mapCasedValue(column, referenceCasing, "columns")) as unknown as readonly string[]
|
|
253
|
+
: reference.knownColumns
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
case "check":
|
|
258
|
+
return {
|
|
259
|
+
...option,
|
|
260
|
+
name: mapOptionName(option.name, casing, "constraints"),
|
|
261
|
+
predicate: isDdlExpressionLike(option.predicate)
|
|
262
|
+
? mapDdlExpression(option.predicate, expressionState)
|
|
263
|
+
: option.predicate
|
|
264
|
+
}
|
|
265
|
+
default:
|
|
266
|
+
return option
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
55
270
|
export const toTableModel = (table: Table.AnyTable): TableModel => {
|
|
56
271
|
const state = table[Table.TypeId]
|
|
272
|
+
const casing = state.casing
|
|
273
|
+
const tableName = applyCasing(casing, "tables", state.baseName)
|
|
274
|
+
const schemaName = state.schemaName === undefined
|
|
275
|
+
? undefined
|
|
276
|
+
: applyCasing(casing, "schemas", state.schemaName)
|
|
57
277
|
const fields = state.fields as Record<string, AnyColumnDefinition>
|
|
278
|
+
const options = table[Table.OptionsSymbol] as unknown
|
|
279
|
+
const normalizedOptions = (Array.isArray(options) ? options : [options]) as readonly TableOptionSpec[]
|
|
280
|
+
validateOptions(state.name, fields, normalizedOptions)
|
|
281
|
+
const columnNames = new Map(
|
|
282
|
+
Object.keys(fields).map((name) => [name, applyCasing(casing, "columns", name)] as const)
|
|
283
|
+
)
|
|
284
|
+
const expressionState = expressionStateForTable(state, tableName, columnNames, casing)
|
|
58
285
|
const columns = Object.entries(fields).map(([name, column]) => {
|
|
59
286
|
const metadata = column.metadata
|
|
60
287
|
const enumDefinition = metadata.enum
|
|
61
288
|
const ddlType = metadata.ddlType ?? metadata.dbType.kind
|
|
62
289
|
return {
|
|
63
|
-
name,
|
|
290
|
+
name: columnNames.get(name) ?? name,
|
|
64
291
|
ddlType,
|
|
65
292
|
dbTypeKind: enumDefinition?.name ?? column.metadata.dbType.kind,
|
|
66
293
|
typeKind: enumDefinition === undefined ? undefined : "e",
|
|
@@ -70,20 +297,24 @@ export const toTableModel = (table: Table.AnyTable): TableModel => {
|
|
|
70
297
|
generated: column.metadata.generated,
|
|
71
298
|
defaultSql: column.metadata.defaultValue === undefined
|
|
72
299
|
? undefined
|
|
73
|
-
: normalizeDdlExpressionSql(column.metadata.defaultValue),
|
|
300
|
+
: normalizeDdlExpressionSql(column.metadata.defaultValue, expressionState),
|
|
74
301
|
generatedSql: column.metadata.generatedValue === undefined
|
|
75
302
|
? undefined
|
|
76
|
-
: normalizeDdlExpressionSql(column.metadata.generatedValue),
|
|
303
|
+
: normalizeDdlExpressionSql(column.metadata.generatedValue, expressionState),
|
|
77
304
|
identity: column.metadata.identity,
|
|
78
305
|
column
|
|
79
306
|
}
|
|
80
307
|
}) satisfies ReadonlyArray<ColumnModel>
|
|
81
308
|
return {
|
|
82
309
|
kind: "table",
|
|
83
|
-
schemaName
|
|
84
|
-
name:
|
|
310
|
+
schemaName,
|
|
311
|
+
name: tableName,
|
|
85
312
|
columns,
|
|
86
|
-
options:
|
|
313
|
+
options: normalizedOptions.map((option) =>
|
|
314
|
+
typeof option === "object" && option !== null && "kind" in option
|
|
315
|
+
? mapOption(option, casing, expressionState)
|
|
316
|
+
: option as TableOptionSpec
|
|
317
|
+
),
|
|
87
318
|
table
|
|
88
319
|
}
|
|
89
320
|
}
|
|
@@ -121,17 +352,17 @@ export const fromDiscoveredValues = (values: ReadonlyArray<unknown>): SchemaMode
|
|
|
121
352
|
const enums = new Map<string, EnumModel>()
|
|
122
353
|
for (const value of values) {
|
|
123
354
|
if (isEnumDefinition(value)) {
|
|
124
|
-
enums.set(
|
|
355
|
+
enums.set(modelIdentityKey(value.schemaName, value.name), toEnumModel(value))
|
|
125
356
|
} else if (isTableDefinition(value)) {
|
|
126
357
|
for (const enumModel of enumModelsOfTable(value)) {
|
|
127
|
-
const key =
|
|
358
|
+
const key = modelIdentityKey(enumModel.schemaName, enumModel.name)
|
|
128
359
|
const existing = enums.get(key)
|
|
129
360
|
if (existing === undefined) {
|
|
130
361
|
enums.set(key, enumModel)
|
|
131
362
|
continue
|
|
132
363
|
}
|
|
133
364
|
if (JSON.stringify(existing.values) !== JSON.stringify(enumModel.values)) {
|
|
134
|
-
throw new Error(`Conflicting enum definitions discovered for '${
|
|
365
|
+
throw new Error(`Conflicting enum definitions discovered for '${enumKey(enumModel.schemaName, enumModel.name)}'`)
|
|
135
366
|
}
|
|
136
367
|
}
|
|
137
368
|
}
|
|
@@ -148,3 +379,6 @@ export const tableKey = (schemaName: string | undefined, name: string): string =
|
|
|
148
379
|
|
|
149
380
|
export const enumKey = (schemaName: string | undefined, name: string): string =>
|
|
150
381
|
`${schemaName ?? "public"}.${name}`
|
|
382
|
+
|
|
383
|
+
const modelIdentityKey = (schemaName: string | undefined, name: string): string =>
|
|
384
|
+
JSON.stringify([schemaName ?? "public", name])
|
package/src/postgres/json.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import * as Expression from "../internal/scalar.js"
|
|
2
|
+
import type * as ExpressionAst from "../internal/expression-ast.js"
|
|
2
3
|
import type { JsonPathUsageError } from "../internal/json/errors.js"
|
|
3
4
|
import * as JsonPath from "../internal/json/path.js"
|
|
4
5
|
import type {
|
|
5
6
|
JsonDeleteAtPath,
|
|
6
7
|
JsonInsertAtPath,
|
|
7
8
|
JsonSetAtPath,
|
|
9
|
+
JsonTextResult,
|
|
8
10
|
JsonValueAtPath
|
|
9
11
|
} from "../internal/json/types.js"
|
|
12
|
+
import type { LiteralStringInput } from "../internal/table-options.js"
|
|
10
13
|
import { json as postgresJson, jsonb as postgresJsonb } from "./internal/dsl.js"
|
|
11
14
|
|
|
12
15
|
type PostgresJsonExpression<Runtime = unknown> = Expression.Scalar<
|
|
13
16
|
Runtime,
|
|
14
|
-
Expression.DbType.Json<"postgres", "json" | "jsonb">,
|
|
17
|
+
Expression.DbType.Json<"postgres" | "standard", "json" | "jsonb">,
|
|
15
18
|
Expression.Nullability,
|
|
16
19
|
string,
|
|
17
20
|
Expression.ScalarKind,
|
|
@@ -29,10 +32,24 @@ type PostgresJsonbExpression<Runtime = unknown> = Expression.Scalar<
|
|
|
29
32
|
|
|
30
33
|
type ExactJsonPathInput = JsonPath.ExactSegment | JsonPath.Path<any>
|
|
31
34
|
|
|
35
|
+
type JsonPathPredicateExpression = Expression.Scalar<
|
|
36
|
+
string | null,
|
|
37
|
+
Expression.DbType.Any,
|
|
38
|
+
Expression.Nullability,
|
|
39
|
+
string,
|
|
40
|
+
Expression.ScalarKind,
|
|
41
|
+
Expression.BindingId
|
|
42
|
+
>
|
|
43
|
+
|
|
44
|
+
type JsonPathPredicateQuery = JsonPath.Path<any> | JsonPathPredicateExpression | string
|
|
45
|
+
|
|
46
|
+
type JsonPathPredicateQueryInput<Query extends JsonPathPredicateQuery> =
|
|
47
|
+
Query extends string ? LiteralStringInput<Query> : Query
|
|
48
|
+
|
|
32
49
|
type ExactJsonPathUsageError<Target> = {
|
|
33
50
|
readonly __effect_qb_error__: "effect-qb: postgres json helpers only accept exact key/index paths"
|
|
34
51
|
readonly __effect_qb_json_path__: Target
|
|
35
|
-
readonly __effect_qb_hint__: "Use Postgres.
|
|
52
|
+
readonly __effect_qb_hint__: "Use Postgres.Jsonb.path(...) when you need wildcard(), slice(), or descend() segments"
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
type ExactJsonPathGuard<Target> = Target extends JsonPath.Path<any>
|
|
@@ -75,6 +92,16 @@ type JsonSetOutputOf<
|
|
|
75
92
|
? JsonSetAtPath<Root, JsonPath.Path<[Target]>, Next, Operation>
|
|
76
93
|
: never
|
|
77
94
|
|
|
95
|
+
type JsonSetOutputWithCreateMissing<
|
|
96
|
+
Root,
|
|
97
|
+
Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment,
|
|
98
|
+
Next,
|
|
99
|
+
Operation extends string,
|
|
100
|
+
CreateMissing extends boolean
|
|
101
|
+
> = false extends CreateMissing
|
|
102
|
+
? Root | JsonSetOutputOf<Root, Target, Next, Operation>
|
|
103
|
+
: JsonSetOutputOf<Root, Target, Next, Operation>
|
|
104
|
+
|
|
78
105
|
type JsonInsertOutputOf<
|
|
79
106
|
Root,
|
|
80
107
|
Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment,
|
|
@@ -129,7 +156,7 @@ type JsonbOnlyUsageError<
|
|
|
129
156
|
readonly __effect_qb_error__: "effect-qb: postgres jsonb helpers require a jsonb expression"
|
|
130
157
|
readonly __effect_qb_json_operation__: Operation
|
|
131
158
|
readonly __effect_qb_received_kind__: Expression.DbTypeOf<Value>["kind"]
|
|
132
|
-
readonly __effect_qb_hint__: "Use Column.jsonb(...), Cast.to(..., Type.jsonb()), or Postgres.
|
|
159
|
+
readonly __effect_qb_hint__: "Use Column.jsonb(...), Cast.to(..., Type.jsonb()), or Postgres.Jsonb.toJsonb(...)"
|
|
133
160
|
}
|
|
134
161
|
|
|
135
162
|
type JsonbBaseGuard<
|
|
@@ -144,17 +171,37 @@ type JsonNullabilityOf<Output> =
|
|
|
144
171
|
? Exclude<Output, null> extends never ? "always" : "maybe"
|
|
145
172
|
: "never"
|
|
146
173
|
|
|
174
|
+
type JsonPathSegmentsOf<Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment> =
|
|
175
|
+
Target extends JsonPath.Path<infer Segments extends readonly JsonPath.CanonicalSegment[]> ? Segments :
|
|
176
|
+
Target extends JsonPath.CanonicalSegment ? readonly [Target] :
|
|
177
|
+
readonly []
|
|
178
|
+
|
|
179
|
+
type JsonGetAccessKind<Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment> =
|
|
180
|
+
Target extends JsonPath.Path<any>
|
|
181
|
+
? JsonPath.IsExactPath<Target> extends true ? "jsonPath" : "jsonTraverse"
|
|
182
|
+
: Target extends JsonPath.ExactSegment ? "jsonGet" : "jsonAccess"
|
|
183
|
+
|
|
184
|
+
type JsonTextAccessKind<Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment> =
|
|
185
|
+
Target extends JsonPath.Path<any>
|
|
186
|
+
? JsonPath.IsExactPath<Target> extends true ? "jsonPathText" : "jsonTraverseText"
|
|
187
|
+
: Target extends JsonPath.ExactSegment ? "jsonGetText" : "jsonAccessText"
|
|
188
|
+
|
|
147
189
|
type JsonResultExpression<
|
|
148
190
|
Runtime,
|
|
149
|
-
Db extends Expression.DbType.Json<any, any
|
|
191
|
+
Db extends Expression.DbType.Json<any, any>,
|
|
192
|
+
Kind extends Expression.ScalarKind = Expression.ScalarKind,
|
|
193
|
+
Dependencies extends Expression.BindingId = Expression.BindingId,
|
|
194
|
+
Ast extends ExpressionAst.Any = never
|
|
150
195
|
> = Expression.Scalar<
|
|
151
196
|
Runtime,
|
|
152
197
|
Db,
|
|
153
198
|
JsonNullabilityOf<Runtime>,
|
|
154
199
|
string,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
>
|
|
200
|
+
Kind,
|
|
201
|
+
Dependencies
|
|
202
|
+
> & ([Ast] extends [never] ? unknown : {
|
|
203
|
+
readonly [ExpressionAst.TypeId]: Ast
|
|
204
|
+
})
|
|
158
205
|
|
|
159
206
|
type JsonDbOf<Base extends PostgresJsonExpression<any>> =
|
|
160
207
|
Expression.DbTypeOf<Base> extends Expression.DbType.Json<"postgres", infer Variant>
|
|
@@ -167,14 +214,17 @@ type JsonGetResultExpression<
|
|
|
167
214
|
Operation extends string
|
|
168
215
|
> = JsonResultExpression<
|
|
169
216
|
JsonPathOutputOf<Expression.RuntimeOf<Base>, Target, Operation>,
|
|
170
|
-
JsonDbOf<Base
|
|
217
|
+
JsonDbOf<Base>,
|
|
218
|
+
Expression.KindOf<Base>,
|
|
219
|
+
Expression.DependenciesOf<Base>,
|
|
220
|
+
ExpressionAst.JsonAccessNode<JsonGetAccessKind<Target>, Base, JsonPathSegmentsOf<Target>>
|
|
171
221
|
>
|
|
172
222
|
|
|
173
223
|
type JsonTextRuntime<
|
|
174
224
|
Base extends PostgresJsonExpression<any>,
|
|
175
225
|
Target extends JsonPath.Path<any> | JsonPath.CanonicalSegment
|
|
176
226
|
> =
|
|
177
|
-
|
|
227
|
+
JsonTextResult<Exclude<JsonPathOutputOf<Expression.RuntimeOf<Base>, Target, "json.text">, JsonPathUsageError<any, any, any, any> | null>> |
|
|
178
228
|
(null extends JsonPathOutputOf<Expression.RuntimeOf<Base>, Target, "json.text"> ? null : never)
|
|
179
229
|
|
|
180
230
|
type JsonTextResultExpression<
|
|
@@ -185,9 +235,11 @@ type JsonTextResultExpression<
|
|
|
185
235
|
Expression.DbType.Base<"postgres", "text">,
|
|
186
236
|
JsonNullabilityOf<JsonTextRuntime<Base, Target>>,
|
|
187
237
|
string,
|
|
188
|
-
Expression.
|
|
189
|
-
Expression.
|
|
190
|
-
>
|
|
238
|
+
Expression.KindOf<Base>,
|
|
239
|
+
Expression.DependenciesOf<Base>
|
|
240
|
+
> & {
|
|
241
|
+
readonly [ExpressionAst.TypeId]: ExpressionAst.JsonAccessNode<JsonTextAccessKind<Target>, Base, JsonPathSegmentsOf<Target>>
|
|
242
|
+
}
|
|
191
243
|
|
|
192
244
|
const exactPath = <Segments extends readonly JsonPath.CanonicalSegment[]>(
|
|
193
245
|
...segments: Segments & ExactJsonPathSegmentsGuard<Segments>
|
|
@@ -222,7 +274,7 @@ const json = {
|
|
|
222
274
|
typeof jsonGetDirect & {
|
|
223
275
|
<Target extends ExactJsonPathInput>(
|
|
224
276
|
target: Target & ExactJsonPathGuard<Target>
|
|
225
|
-
): <Base extends PostgresJsonExpression<any>>(base: Base) =>
|
|
277
|
+
): <Base extends PostgresJsonExpression<any>>(base: Base) => JsonGetResultExpression<Base, Target, "json.get">
|
|
226
278
|
},
|
|
227
279
|
access: <
|
|
228
280
|
Base extends PostgresJsonExpression<any>,
|
|
@@ -245,7 +297,7 @@ const json = {
|
|
|
245
297
|
typeof jsonTextDirect & {
|
|
246
298
|
<Target extends ExactJsonPathInput>(
|
|
247
299
|
target: Target & ExactJsonPathGuard<Target>
|
|
248
|
-
): <Base extends PostgresJsonExpression<any>>(base: Base) =>
|
|
300
|
+
): <Base extends PostgresJsonExpression<any>>(base: Base) => JsonTextResultExpression<Base, Target>
|
|
249
301
|
},
|
|
250
302
|
accessText: <
|
|
251
303
|
Base extends PostgresJsonExpression<any>,
|
|
@@ -416,17 +468,20 @@ const jsonb = {
|
|
|
416
468
|
set: <
|
|
417
469
|
Base extends PostgresJsonExpression<any>,
|
|
418
470
|
Target extends JsonPath.CanonicalSegment | JsonPath.Path<any>,
|
|
419
|
-
Next extends Parameters<typeof postgresJsonb.set>[2]
|
|
471
|
+
Next extends Parameters<typeof postgresJsonb.set>[2],
|
|
472
|
+
CreateMissing extends boolean = true
|
|
420
473
|
>(
|
|
421
474
|
base: Base & JsonbBaseGuard<Base, "jsonb.set">,
|
|
422
|
-
target: Target & JsonSetPathGuard<Expression.RuntimeOf<Base>, Target, Next
|
|
475
|
+
target: Target & JsonSetPathGuard<Expression.RuntimeOf<Base>, Target, NoInfer<Next>, "json.set">,
|
|
423
476
|
next: Next,
|
|
424
|
-
options?:
|
|
477
|
+
options?: {
|
|
478
|
+
readonly createMissing?: CreateMissing
|
|
479
|
+
}
|
|
425
480
|
): JsonResultExpression<
|
|
426
|
-
|
|
481
|
+
JsonSetOutputWithCreateMissing<Expression.RuntimeOf<Base>, Target, Next, "json.set", CreateMissing>,
|
|
427
482
|
Expression.DbTypeOf<Base>
|
|
428
483
|
> => postgresJsonb.set(base as any, target as any, next, options) as unknown as JsonResultExpression<
|
|
429
|
-
|
|
484
|
+
JsonSetOutputWithCreateMissing<Expression.RuntimeOf<Base>, Target, Next, "json.set", CreateMissing>,
|
|
430
485
|
Expression.DbTypeOf<Base>
|
|
431
486
|
>,
|
|
432
487
|
insert: <
|
|
@@ -436,7 +491,7 @@ const jsonb = {
|
|
|
436
491
|
InsertAfter extends boolean = false
|
|
437
492
|
>(
|
|
438
493
|
base: Base & JsonbBaseGuard<Base, "jsonb.insert">,
|
|
439
|
-
target: Target & JsonInsertPathGuard<Expression.RuntimeOf<Base>, Target, Next
|
|
494
|
+
target: Target & JsonInsertPathGuard<Expression.RuntimeOf<Base>, Target, NoInfer<Next>, NoInfer<InsertAfter>, "json.insert">,
|
|
440
495
|
next: Next,
|
|
441
496
|
options?: {
|
|
442
497
|
readonly insertAfter?: InsertAfter
|
|
@@ -474,20 +529,41 @@ const jsonb = {
|
|
|
474
529
|
base: Base & JsonbBaseGuard<Base, "jsonb.stripNulls">
|
|
475
530
|
) => postgresJsonb.stripNulls(base as Base),
|
|
476
531
|
pathExists: <
|
|
477
|
-
Base extends PostgresJsonExpression<any
|
|
532
|
+
Base extends PostgresJsonExpression<any>,
|
|
533
|
+
Query extends JsonPathPredicateQuery
|
|
478
534
|
>(
|
|
479
535
|
base: Base & JsonbBaseGuard<Base, "jsonb.pathExists">,
|
|
480
|
-
query:
|
|
536
|
+
query: JsonPathPredicateQueryInput<Query>
|
|
481
537
|
) => postgresJsonb.pathExists(base as Base, query),
|
|
482
538
|
pathMatch: <
|
|
483
|
-
Base extends PostgresJsonExpression<any
|
|
539
|
+
Base extends PostgresJsonExpression<any>,
|
|
540
|
+
Query extends JsonPathPredicateQuery
|
|
484
541
|
>(
|
|
485
542
|
base: Base & JsonbBaseGuard<Base, "jsonb.pathMatch">,
|
|
486
|
-
query:
|
|
543
|
+
query: JsonPathPredicateQueryInput<Query>
|
|
487
544
|
) => postgresJsonb.pathMatch(base as Base, query)
|
|
488
545
|
}
|
|
489
546
|
|
|
490
547
|
/** Postgres shared JSON helpers for exact paths and functions that work on both json and jsonb. */
|
|
491
548
|
export { json }
|
|
549
|
+
export const key = json.key
|
|
550
|
+
export const index = json.index
|
|
551
|
+
export const path = json.path
|
|
552
|
+
export const get = json.get
|
|
553
|
+
export const access = json.access
|
|
554
|
+
export const traverse = json.traverse
|
|
555
|
+
export const text = json.text
|
|
556
|
+
export const accessText = json.accessText
|
|
557
|
+
export const traverseText = json.traverseText
|
|
558
|
+
export const buildObject = json.buildObject
|
|
559
|
+
export const buildArray = json.buildArray
|
|
560
|
+
export const toJson = json.toJson
|
|
561
|
+
export const typeOf = json.typeOf
|
|
562
|
+
export const length = json.length
|
|
563
|
+
export const keys = json.keys
|
|
564
|
+
export const stripNulls = json.stripNulls
|
|
565
|
+
export const delete_ = json.delete
|
|
566
|
+
export { delete_ as delete }
|
|
567
|
+
export const remove = json.remove
|
|
492
568
|
/** Postgres jsonb-only helpers for containment, mutation, wildcard paths, and SQL/JSON path predicates. */
|
|
493
569
|
export { jsonb }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsonb } from "./json.js"
|
|
2
|
+
|
|
3
|
+
/** Postgres jsonb-only helpers for containment, mutation, wildcard paths, and SQL/JSON path predicates. */
|
|
4
|
+
export { jsonb }
|
|
5
|
+
export const key = jsonb.key
|
|
6
|
+
export const index = jsonb.index
|
|
7
|
+
export const wildcard = jsonb.wildcard
|
|
8
|
+
export const slice = jsonb.slice
|
|
9
|
+
export const descend = jsonb.descend
|
|
10
|
+
export const path = jsonb.path
|
|
11
|
+
export const get = jsonb.get
|
|
12
|
+
export const access = jsonb.access
|
|
13
|
+
export const traverse = jsonb.traverse
|
|
14
|
+
export const text = jsonb.text
|
|
15
|
+
export const accessText = jsonb.accessText
|
|
16
|
+
export const traverseText = jsonb.traverseText
|
|
17
|
+
export const contains = jsonb.contains
|
|
18
|
+
export const containedBy = jsonb.containedBy
|
|
19
|
+
export const hasKey = jsonb.hasKey
|
|
20
|
+
export const keyExists = jsonb.keyExists
|
|
21
|
+
export const hasAnyKeys = jsonb.hasAnyKeys
|
|
22
|
+
export const hasAllKeys = jsonb.hasAllKeys
|
|
23
|
+
export const delete_ = jsonb.delete
|
|
24
|
+
export { delete_ as delete }
|
|
25
|
+
export const remove = jsonb.remove
|
|
26
|
+
export const set = jsonb.set
|
|
27
|
+
export const insert = jsonb.insert
|
|
28
|
+
export const concat = jsonb.concat
|
|
29
|
+
export const merge = jsonb.merge
|
|
30
|
+
export const buildObject = jsonb.buildObject
|
|
31
|
+
export const buildArray = jsonb.buildArray
|
|
32
|
+
export const toJsonb = jsonb.toJsonb
|
|
33
|
+
export const typeOf = jsonb.typeOf
|
|
34
|
+
export const length = jsonb.length
|
|
35
|
+
export const keys = jsonb.keys
|
|
36
|
+
export const stripNulls = jsonb.stripNulls
|
|
37
|
+
export const pathExists = jsonb.pathExists
|
|
38
|
+
export const pathMatch = jsonb.pathMatch
|