effect-qb 0.17.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 +3053 -2505
- package/dist/postgres/metadata.js +1366 -1250
- package/dist/postgres.js +2020 -2719
- package/dist/sqlite.js +3226 -2732
- package/dist/standard.js +8019 -0
- package/package.json +10 -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 +4 -36
- package/src/{mysql/internal/sql-expression-renderer.ts → internal/dialect-renderers/mysql.ts} +548 -359
- package/src/{postgres/internal/sql-expression-renderer.ts → internal/dialect-renderers/postgres.ts} +654 -399
- package/src/{sqlite/internal/sql-expression-renderer.ts → internal/dialect-renderers/sqlite.ts} +501 -345
- package/src/internal/dialect.ts +35 -0
- package/src/internal/dsl-mutation-runtime.ts +12 -162
- package/src/internal/dsl-plan-runtime.ts +10 -138
- package/src/internal/dsl-query-runtime.ts +5 -79
- package/src/internal/dsl-transaction-ddl-runtime.ts +41 -65
- package/src/internal/executor.ts +10 -6
- package/src/internal/grouping-key.ts +87 -20
- package/src/internal/implication-runtime.ts +1 -1
- package/src/internal/predicate/runtime.ts +3 -0
- package/src/internal/query.d.ts +38 -11
- package/src/internal/query.ts +64 -25
- package/src/internal/renderer.ts +26 -14
- package/src/internal/runtime/normalize.ts +12 -5
- 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 +126 -66
- package/src/internal/table.d.ts +33 -32
- package/src/internal/table.ts +406 -155
- package/src/mysql/column-extension.ts +3 -0
- package/src/mysql/column.ts +10 -11
- package/src/mysql/datatypes/index.ts +3 -2
- package/src/mysql/executor.ts +7 -5
- package/src/mysql/internal/dialect.ts +9 -4
- package/src/mysql/internal/dsl.ts +219 -155
- package/src/mysql/internal/renderer.ts +6 -2
- package/src/mysql/json.ts +37 -0
- package/src/mysql/query-extension.ts +16 -0
- 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 +5 -11
- package/src/postgres/datatypes/index.d.ts +2 -1
- package/src/postgres/datatypes/index.ts +3 -2
- package/src/postgres/executor.ts +7 -5
- package/src/postgres/function/core.ts +1 -3
- package/src/postgres/function/index.ts +1 -17
- package/src/postgres/internal/dialect.ts +9 -4
- package/src/postgres/internal/dsl.ts +208 -160
- package/src/postgres/internal/renderer.ts +6 -2
- package/src/postgres/internal/schema-ddl.ts +22 -10
- package/src/postgres/internal/schema-model.ts +238 -7
- package/src/postgres/json.ts +43 -7
- package/src/postgres/jsonb.ts +38 -0
- package/src/postgres/query-extension.ts +2 -0
- package/src/postgres/renderer.ts +31 -4
- package/src/postgres/schema-management.ts +17 -12
- package/src/postgres/schema.ts +98 -15
- package/src/postgres/table.ts +193 -524
- 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 +10 -11
- package/src/sqlite/datatypes/index.ts +3 -2
- package/src/sqlite/executor.ts +7 -5
- package/src/sqlite/internal/dialect.ts +9 -4
- package/src/sqlite/internal/dsl.ts +208 -155
- package/src/sqlite/internal/renderer.ts +6 -2
- package/src/sqlite/json.ts +37 -0
- package/src/sqlite/query-extension.ts +2 -0
- package/src/sqlite/renderer.ts +31 -4
- package/src/sqlite.ts +4 -12
- 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 -183
- package/src/sqlite/table.ts +0 -183
|
@@ -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,9 +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
39
|
cteNames: new Set<string>(),
|
|
37
|
-
cteSources: new Map<string, unknown>()
|
|
40
|
+
cteSources: new Map<string, unknown>(),
|
|
41
|
+
sourceNames: new Map()
|
|
38
42
|
}
|
|
39
43
|
const rendered = renderQueryAst(
|
|
40
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,21 +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
|
-
cteSources: new Map()
|
|
47
|
-
}, inlineLiteralDialect)
|
|
56
|
+
: renderExpression(expression as Expression.Any, makeExpressionState(state), inlineLiteralDialect)
|
|
48
57
|
|
|
49
58
|
const stripRedundantOuterParens = (value: string): string => {
|
|
50
59
|
let current = value.trim()
|
|
@@ -99,8 +108,11 @@ const canonicalizeDdlExpressionSql = (value: string): string =>
|
|
|
99
108
|
)
|
|
100
109
|
)
|
|
101
110
|
|
|
102
|
-
export const normalizeDdlExpressionSql = (
|
|
103
|
-
|
|
111
|
+
export const normalizeDdlExpressionSql = (
|
|
112
|
+
expression: DdlExpressionLike,
|
|
113
|
+
state?: Partial<RenderState>
|
|
114
|
+
): string => {
|
|
115
|
+
const rendered = renderDdlExpressionSql(expression, state)
|
|
104
116
|
try {
|
|
105
117
|
return canonicalizeDdlExpressionSql(toSql.expr(parse(rendered, "expr")))
|
|
106
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
|
}
|
package/src/postgres/json.ts
CHANGED
|
@@ -9,11 +9,12 @@ import type {
|
|
|
9
9
|
JsonTextResult,
|
|
10
10
|
JsonValueAtPath
|
|
11
11
|
} from "../internal/json/types.js"
|
|
12
|
+
import type { LiteralStringInput } from "../internal/table-options.js"
|
|
12
13
|
import { json as postgresJson, jsonb as postgresJsonb } from "./internal/dsl.js"
|
|
13
14
|
|
|
14
15
|
type PostgresJsonExpression<Runtime = unknown> = Expression.Scalar<
|
|
15
16
|
Runtime,
|
|
16
|
-
Expression.DbType.Json<"postgres", "json" | "jsonb">,
|
|
17
|
+
Expression.DbType.Json<"postgres" | "standard", "json" | "jsonb">,
|
|
17
18
|
Expression.Nullability,
|
|
18
19
|
string,
|
|
19
20
|
Expression.ScalarKind,
|
|
@@ -31,10 +32,24 @@ type PostgresJsonbExpression<Runtime = unknown> = Expression.Scalar<
|
|
|
31
32
|
|
|
32
33
|
type ExactJsonPathInput = JsonPath.ExactSegment | JsonPath.Path<any>
|
|
33
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
|
+
|
|
34
49
|
type ExactJsonPathUsageError<Target> = {
|
|
35
50
|
readonly __effect_qb_error__: "effect-qb: postgres json helpers only accept exact key/index paths"
|
|
36
51
|
readonly __effect_qb_json_path__: Target
|
|
37
|
-
readonly __effect_qb_hint__: "Use Postgres.
|
|
52
|
+
readonly __effect_qb_hint__: "Use Postgres.Jsonb.path(...) when you need wildcard(), slice(), or descend() segments"
|
|
38
53
|
}
|
|
39
54
|
|
|
40
55
|
type ExactJsonPathGuard<Target> = Target extends JsonPath.Path<any>
|
|
@@ -141,7 +156,7 @@ type JsonbOnlyUsageError<
|
|
|
141
156
|
readonly __effect_qb_error__: "effect-qb: postgres jsonb helpers require a jsonb expression"
|
|
142
157
|
readonly __effect_qb_json_operation__: Operation
|
|
143
158
|
readonly __effect_qb_received_kind__: Expression.DbTypeOf<Value>["kind"]
|
|
144
|
-
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(...)"
|
|
145
160
|
}
|
|
146
161
|
|
|
147
162
|
type JsonbBaseGuard<
|
|
@@ -514,20 +529,41 @@ const jsonb = {
|
|
|
514
529
|
base: Base & JsonbBaseGuard<Base, "jsonb.stripNulls">
|
|
515
530
|
) => postgresJsonb.stripNulls(base as Base),
|
|
516
531
|
pathExists: <
|
|
517
|
-
Base extends PostgresJsonExpression<any
|
|
532
|
+
Base extends PostgresJsonExpression<any>,
|
|
533
|
+
Query extends JsonPathPredicateQuery
|
|
518
534
|
>(
|
|
519
535
|
base: Base & JsonbBaseGuard<Base, "jsonb.pathExists">,
|
|
520
|
-
query:
|
|
536
|
+
query: JsonPathPredicateQueryInput<Query>
|
|
521
537
|
) => postgresJsonb.pathExists(base as Base, query),
|
|
522
538
|
pathMatch: <
|
|
523
|
-
Base extends PostgresJsonExpression<any
|
|
539
|
+
Base extends PostgresJsonExpression<any>,
|
|
540
|
+
Query extends JsonPathPredicateQuery
|
|
524
541
|
>(
|
|
525
542
|
base: Base & JsonbBaseGuard<Base, "jsonb.pathMatch">,
|
|
526
|
-
query:
|
|
543
|
+
query: JsonPathPredicateQueryInput<Query>
|
|
527
544
|
) => postgresJsonb.pathMatch(base as Base, query)
|
|
528
545
|
}
|
|
529
546
|
|
|
530
547
|
/** Postgres shared JSON helpers for exact paths and functions that work on both json and jsonb. */
|
|
531
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
|
|
532
568
|
/** Postgres jsonb-only helpers for containment, mutation, wildcard paths, and SQL/JSON path predicates. */
|
|
533
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
|
package/src/postgres/renderer.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { pipeArguments, type Pipeable } from "effect/Pipeable"
|
|
2
|
+
|
|
1
3
|
import * as CoreRenderer from "../internal/renderer.js"
|
|
4
|
+
import * as Casing from "../internal/casing.js"
|
|
2
5
|
import type * as Expression from "../internal/scalar.js"
|
|
6
|
+
import type { PostgresDatatypeFamily, PostgresDatatypeKind } from "./datatypes/spec.js"
|
|
3
7
|
import { renderPostgresPlan } from "./internal/renderer.js"
|
|
4
8
|
|
|
5
9
|
/** Postgres-specialized rendered query shape. */
|
|
@@ -7,18 +11,41 @@ export type RenderedQuery<Row> = CoreRenderer.RenderedQuery<Row, "postgres">
|
|
|
7
11
|
/** Extracts the row type carried by a Postgres rendered query. */
|
|
8
12
|
export type RowOf<Value extends RenderedQuery<any>> = CoreRenderer.RowOf<Value>
|
|
9
13
|
/** Postgres-specialized renderer contract. */
|
|
10
|
-
export type Renderer = CoreRenderer.Renderer<"postgres">
|
|
14
|
+
export type Renderer = CoreRenderer.Renderer<"postgres"> & Pipeable & {
|
|
15
|
+
readonly [Casing.TypeId]: Casing.State
|
|
16
|
+
readonly withCasing: (options: Casing.Options) => Renderer
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type ValueMappings = Expression.DriverValueMappingsFor<PostgresDatatypeKind, PostgresDatatypeFamily>
|
|
11
20
|
|
|
12
21
|
export interface MakeOptions {
|
|
13
|
-
readonly valueMappings?:
|
|
22
|
+
readonly valueMappings?: ValueMappings
|
|
23
|
+
readonly casing?: Casing.Options
|
|
14
24
|
}
|
|
15
25
|
|
|
16
26
|
export { TypeId } from "../internal/renderer.js"
|
|
17
27
|
export type { Projection } from "../internal/renderer.js"
|
|
18
28
|
|
|
29
|
+
const RendererProto = {
|
|
30
|
+
pipe(this: Pipeable) {
|
|
31
|
+
return pipeArguments(this, arguments)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
/** Creates the built-in Postgres renderer. */
|
|
20
|
-
export const make = (options: MakeOptions = {}): Renderer =>
|
|
21
|
-
CoreRenderer.
|
|
36
|
+
export const make = (options: MakeOptions = {}): Renderer => {
|
|
37
|
+
const renderer = CoreRenderer.makeTrusted("postgres", (plan) => renderPostgresPlan(plan, options))
|
|
38
|
+
return Object.assign(Object.create(RendererProto), renderer, {
|
|
39
|
+
[Casing.TypeId]: {
|
|
40
|
+
casing: options.casing
|
|
41
|
+
},
|
|
42
|
+
withCasing: (override: Casing.Options) =>
|
|
43
|
+
make({
|
|
44
|
+
...options,
|
|
45
|
+
casing: Casing.merge(options.casing, override)
|
|
46
|
+
})
|
|
47
|
+
}) as Renderer
|
|
48
|
+
}
|
|
22
49
|
|
|
23
50
|
/** Shared built-in Postgres renderer instance. */
|
|
24
51
|
export const postgres = make()
|
|
@@ -3,6 +3,7 @@ import { pipeArguments, type Pipeable } from "effect/Pipeable"
|
|
|
3
3
|
|
|
4
4
|
import type * as Expression from "../internal/scalar.js"
|
|
5
5
|
import { makeColumnDefinition, type ColumnDefinition } from "../internal/column-state.js"
|
|
6
|
+
import type { NonEmptyStringInput } from "../internal/table-options.js"
|
|
6
7
|
|
|
7
8
|
export const EnumTypeId: unique symbol = Symbol.for("effect-qb/SchemaManagement/Enum")
|
|
8
9
|
export const SequenceTypeId: unique symbol = Symbol.for("effect-qb/SchemaManagement/Sequence")
|
|
@@ -121,7 +122,7 @@ const renderQualifiedTypeName = (
|
|
|
121
122
|
: `${renderIdentifier(schemaName)}.${renderIdentifier(name)}`
|
|
122
123
|
|
|
123
124
|
const EnumProto = {
|
|
124
|
-
pipe(this:
|
|
125
|
+
pipe(this: Pipeable) {
|
|
125
126
|
return pipeArguments(this, arguments)
|
|
126
127
|
},
|
|
127
128
|
qualifiedName(this: EnumDefinition) {
|
|
@@ -137,7 +138,11 @@ const EnumProto = {
|
|
|
137
138
|
}
|
|
138
139
|
},
|
|
139
140
|
column(this: EnumDefinition) {
|
|
140
|
-
const
|
|
141
|
+
const [first, ...rest] = this.values
|
|
142
|
+
const values: readonly [Schema.Schema.Any, ...Schema.Schema.Any[]] = [
|
|
143
|
+
Schema.Literal(first),
|
|
144
|
+
...rest.map((value) => Schema.Literal(value))
|
|
145
|
+
]
|
|
141
146
|
return makeColumnDefinition(
|
|
142
147
|
values.length === 1 ? values[0]! : Schema.Union(...values),
|
|
143
148
|
{
|
|
@@ -161,7 +166,7 @@ const EnumProto = {
|
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
const SequenceProto = {
|
|
164
|
-
pipe(this:
|
|
169
|
+
pipe(this: Pipeable) {
|
|
165
170
|
return pipeArguments(this, arguments)
|
|
166
171
|
},
|
|
167
172
|
qualifiedName(this: SequenceDefinition) {
|
|
@@ -212,7 +217,7 @@ export function enumType<
|
|
|
212
217
|
Name extends string,
|
|
213
218
|
const Values extends readonly [string, ...string[]]
|
|
214
219
|
>(
|
|
215
|
-
name: Name
|
|
220
|
+
name: NonEmptyStringInput<Name>,
|
|
216
221
|
values: Values
|
|
217
222
|
): EnumDefinition<Name, Values, undefined>
|
|
218
223
|
export function enumType<
|
|
@@ -220,9 +225,9 @@ export function enumType<
|
|
|
220
225
|
const Values extends readonly [string, ...string[]],
|
|
221
226
|
SchemaName extends string
|
|
222
227
|
>(
|
|
223
|
-
name: Name
|
|
228
|
+
name: NonEmptyStringInput<Name>,
|
|
224
229
|
values: Values,
|
|
225
|
-
schemaName: SchemaName
|
|
230
|
+
schemaName: NonEmptyStringInput<SchemaName>
|
|
226
231
|
): EnumDefinition<Name, Values, SchemaName>
|
|
227
232
|
export function enumType(
|
|
228
233
|
name: string,
|
|
@@ -243,11 +248,11 @@ export function enumType(
|
|
|
243
248
|
}
|
|
244
249
|
|
|
245
250
|
export function sequence<Name extends string>(
|
|
246
|
-
name: Name
|
|
251
|
+
name: NonEmptyStringInput<Name>
|
|
247
252
|
): SequenceDefinition<Name, undefined>
|
|
248
253
|
export function sequence<Name extends string, SchemaName extends string>(
|
|
249
|
-
name: Name
|
|
250
|
-
schemaName: SchemaName
|
|
254
|
+
name: NonEmptyStringInput<Name>,
|
|
255
|
+
schemaName: NonEmptyStringInput<SchemaName>
|
|
251
256
|
): SequenceDefinition<Name, SchemaName>
|
|
252
257
|
export function sequence(
|
|
253
258
|
name: string,
|
|
@@ -265,21 +270,21 @@ export function sequence(
|
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
export const schema = <SchemaName extends string>(
|
|
268
|
-
schemaName: SchemaName
|
|
273
|
+
schemaName: NonEmptyStringInput<SchemaName>
|
|
269
274
|
) => ({
|
|
270
275
|
schemaName,
|
|
271
276
|
enumType: <
|
|
272
277
|
Name extends string,
|
|
273
278
|
const Values extends readonly [string, ...string[]]
|
|
274
279
|
>(
|
|
275
|
-
name: Name
|
|
280
|
+
name: NonEmptyStringInput<Name>,
|
|
276
281
|
values: Values
|
|
277
282
|
): EnumDefinition<Name, Values, SchemaName> =>
|
|
278
283
|
enumType(name, values, schemaName) as EnumDefinition<Name, Values, SchemaName>,
|
|
279
284
|
sequence: <
|
|
280
285
|
Name extends string
|
|
281
286
|
>(
|
|
282
|
-
name: Name
|
|
287
|
+
name: NonEmptyStringInput<Name>
|
|
283
288
|
): SequenceDefinition<Name, SchemaName> =>
|
|
284
289
|
sequence(name, schemaName) as SequenceDefinition<Name, SchemaName>
|
|
285
290
|
})
|