effect-qb 0.15.0 → 0.16.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/dist/mysql.js +362 -70
- package/dist/postgres/metadata.js +557 -27
- package/dist/postgres.js +5028 -4732
- package/package.json +2 -2
- package/src/internal/column-state.ts +7 -0
- package/src/internal/column.ts +22 -0
- package/src/internal/dialect.ts +12 -1
- package/src/internal/executor.ts +15 -4
- package/src/internal/predicate/analysis.ts +103 -1
- package/src/internal/predicate/atom.ts +7 -0
- package/src/internal/predicate/context.ts +156 -16
- package/src/internal/predicate/key.ts +46 -1
- package/src/internal/predicate/normalize.ts +115 -34
- package/src/internal/predicate/runtime.ts +118 -11
- package/src/internal/query.ts +328 -90
- package/src/internal/renderer.ts +4 -0
- package/src/internal/runtime/driver-value-mapping.ts +186 -0
- package/src/internal/scalar.ts +11 -0
- package/src/mysql/column.ts +1 -0
- package/src/mysql/executor.ts +20 -5
- package/src/mysql/internal/dialect.ts +12 -6
- package/src/mysql/internal/dsl.ts +268 -54
- package/src/mysql/internal/renderer.ts +11 -2
- package/src/mysql/internal/sql-expression-renderer.ts +54 -8
- package/src/mysql/renderer.ts +7 -2
- package/src/postgres/cast.ts +22 -7
- package/src/postgres/column.ts +1 -0
- package/src/postgres/executor.ts +20 -5
- package/src/postgres/internal/dialect.ts +12 -6
- package/src/postgres/internal/dsl.ts +285 -58
- package/src/postgres/internal/renderer.ts +11 -2
- package/src/postgres/internal/sql-expression-renderer.ts +60 -8
- package/src/postgres/renderer.ts +7 -2
- package/src/postgres/type.ts +4 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Query from "../../internal/query.js"
|
|
2
|
+
import type * as Expression from "../../internal/scalar.js"
|
|
2
3
|
import { type RenderState } from "../../internal/dialect.js"
|
|
3
4
|
import { postgresDialect } from "./dialect.js"
|
|
4
5
|
import { type Projection } from "../../internal/projections.js"
|
|
@@ -14,16 +15,23 @@ export interface PostgresRenderResult {
|
|
|
14
15
|
readonly sql: string
|
|
15
16
|
readonly params: readonly unknown[]
|
|
16
17
|
readonly projections: readonly Projection[]
|
|
18
|
+
readonly valueMappings?: Expression.DriverValueMappings
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface PostgresRenderOptions {
|
|
22
|
+
readonly valueMappings?: Expression.DriverValueMappings
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
/**
|
|
20
26
|
* Renders the current query AST into Postgres SQL plus bind parameters.
|
|
21
27
|
*/
|
|
22
28
|
export const renderPostgresPlan = <PlanValue extends Query.Plan.Any>(
|
|
23
|
-
plan: Query.DialectCompatiblePlan<PlanValue, "postgres"
|
|
29
|
+
plan: Query.DialectCompatiblePlan<PlanValue, "postgres">,
|
|
30
|
+
options: PostgresRenderOptions = {}
|
|
24
31
|
): PostgresRenderResult => {
|
|
25
32
|
const state: RenderState = {
|
|
26
33
|
params: [],
|
|
34
|
+
valueMappings: options.valueMappings,
|
|
27
35
|
ctes: [],
|
|
28
36
|
cteNames: new Set<string>()
|
|
29
37
|
}
|
|
@@ -35,6 +43,7 @@ export const renderPostgresPlan = <PlanValue extends Query.Plan.Any>(
|
|
|
35
43
|
return {
|
|
36
44
|
sql: rendered.sql,
|
|
37
45
|
params: state.params,
|
|
38
|
-
projections: rendered.projections
|
|
46
|
+
projections: rendered.projections,
|
|
47
|
+
valueMappings: state.valueMappings
|
|
39
48
|
}
|
|
40
49
|
}
|
|
@@ -5,6 +5,11 @@ import * as QueryAst from "../../internal/query-ast.js"
|
|
|
5
5
|
import type { RenderState, SqlDialect } from "../../internal/dialect.js"
|
|
6
6
|
import * as ExpressionAst from "../../internal/expression-ast.js"
|
|
7
7
|
import * as JsonPath from "../../internal/json/path.js"
|
|
8
|
+
import {
|
|
9
|
+
renderJsonSelectSql,
|
|
10
|
+
renderSelectSql,
|
|
11
|
+
toDriverValue
|
|
12
|
+
} from "../../internal/runtime/driver-value-mapping.js"
|
|
8
13
|
import { flattenSelection, type Projection } from "../../internal/projections.js"
|
|
9
14
|
import { type SelectionValue, validateAggregationSelection } from "../../internal/aggregation-validation.js"
|
|
10
15
|
import * as SchemaExpression from "../../internal/schema-expression.js"
|
|
@@ -294,11 +299,54 @@ const renderPostgresJsonValue = (
|
|
|
294
299
|
throw new Error("Expected a JSON expression")
|
|
295
300
|
}
|
|
296
301
|
const rendered = renderExpression(value, state, dialect)
|
|
302
|
+
const ast = (value as Expression.Any & {
|
|
303
|
+
readonly [ExpressionAst.TypeId]: ExpressionAst.Any
|
|
304
|
+
})[ExpressionAst.TypeId]
|
|
305
|
+
if (ast.kind === "literal") {
|
|
306
|
+
return `cast(${rendered} as jsonb)`
|
|
307
|
+
}
|
|
297
308
|
return value[Expression.TypeId].dbType.kind === "jsonb"
|
|
298
309
|
? rendered
|
|
299
310
|
: `cast(${rendered} as jsonb)`
|
|
300
311
|
}
|
|
301
312
|
|
|
313
|
+
const expressionDriverContext = (
|
|
314
|
+
expression: Expression.Any,
|
|
315
|
+
state: RenderState,
|
|
316
|
+
dialect: SqlDialect
|
|
317
|
+
) => ({
|
|
318
|
+
dialect: dialect.name,
|
|
319
|
+
valueMappings: state.valueMappings,
|
|
320
|
+
dbType: expression[Expression.TypeId].dbType,
|
|
321
|
+
runtimeSchema: expression[Expression.TypeId].runtimeSchema,
|
|
322
|
+
driverValueMapping: expression[Expression.TypeId].driverValueMapping
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
const renderJsonInputExpression = (
|
|
326
|
+
expression: Expression.Any,
|
|
327
|
+
state: RenderState,
|
|
328
|
+
dialect: SqlDialect
|
|
329
|
+
): string =>
|
|
330
|
+
renderJsonSelectSql(
|
|
331
|
+
renderExpression(expression, state, dialect),
|
|
332
|
+
expressionDriverContext(expression, state, dialect)
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
const encodeArrayValues = (
|
|
336
|
+
values: readonly unknown[],
|
|
337
|
+
column: Table.AnyTable[typeof Table.TypeId]["fields"][string],
|
|
338
|
+
state: RenderState,
|
|
339
|
+
dialect: SqlDialect
|
|
340
|
+
): readonly unknown[] =>
|
|
341
|
+
values.map((value) =>
|
|
342
|
+
toDriverValue(value, {
|
|
343
|
+
dialect: dialect.name,
|
|
344
|
+
valueMappings: state.valueMappings,
|
|
345
|
+
dbType: column.metadata.dbType,
|
|
346
|
+
runtimeSchema: column.schema,
|
|
347
|
+
driverValueMapping: column.metadata.driverValueMapping
|
|
348
|
+
}))
|
|
349
|
+
|
|
302
350
|
const renderPostgresJsonKind = (
|
|
303
351
|
value: Expression.Any
|
|
304
352
|
): "json" | "jsonb" => value[Expression.TypeId].dbType.kind === "jsonb" ? "jsonb" : "json"
|
|
@@ -460,7 +508,7 @@ const renderJsonExpression = (
|
|
|
460
508
|
: []
|
|
461
509
|
const renderedEntries = entries.flatMap((entry) => [
|
|
462
510
|
dialect.renderLiteral(entry.key, state),
|
|
463
|
-
|
|
511
|
+
renderJsonInputExpression(entry.value, state, dialect)
|
|
464
512
|
])
|
|
465
513
|
if (dialect.name === "postgres") {
|
|
466
514
|
return `${postgresExpressionKind === "jsonb" ? "jsonb" : "json"}_build_object(${renderedEntries.join(", ")})`
|
|
@@ -474,7 +522,7 @@ const renderJsonExpression = (
|
|
|
474
522
|
const values = Array.isArray((ast as { readonly values?: readonly Expression.Any[] }).values)
|
|
475
523
|
? (ast as { readonly values: readonly Expression.Any[] }).values
|
|
476
524
|
: []
|
|
477
|
-
const renderedValues = values.map((value) =>
|
|
525
|
+
const renderedValues = values.map((value) => renderJsonInputExpression(value, state, dialect)).join(", ")
|
|
478
526
|
if (dialect.name === "postgres") {
|
|
479
527
|
return `${postgresExpressionKind === "jsonb" ? "jsonb" : "json"}_build_array(${renderedValues})`
|
|
480
528
|
}
|
|
@@ -488,7 +536,7 @@ const renderJsonExpression = (
|
|
|
488
536
|
return undefined
|
|
489
537
|
}
|
|
490
538
|
if (dialect.name === "postgres") {
|
|
491
|
-
return `to_json(${
|
|
539
|
+
return `to_json(${renderJsonInputExpression(base, state, dialect)})`
|
|
492
540
|
}
|
|
493
541
|
if (dialect.name === "mysql") {
|
|
494
542
|
return `cast(${renderExpression(base, state, dialect)} as json)`
|
|
@@ -499,7 +547,7 @@ const renderJsonExpression = (
|
|
|
499
547
|
return undefined
|
|
500
548
|
}
|
|
501
549
|
if (dialect.name === "postgres") {
|
|
502
|
-
return `to_jsonb(${
|
|
550
|
+
return `to_jsonb(${renderJsonInputExpression(base, state, dialect)})`
|
|
503
551
|
}
|
|
504
552
|
if (dialect.name === "mysql") {
|
|
505
553
|
return `cast(${renderExpression(base, state, dialect)} as json)`
|
|
@@ -753,7 +801,7 @@ const renderSelectionList = (
|
|
|
753
801
|
const flattened = flattenSelection(selection)
|
|
754
802
|
const projections = selectionProjections(selection)
|
|
755
803
|
const sql = flattened.map(({ expression, alias }) =>
|
|
756
|
-
`${renderExpression(expression, state, dialect)} as ${dialect.quoteIdentifier(alias)}`).join(", ")
|
|
804
|
+
`${renderSelectSql(renderExpression(expression, state, dialect), expressionDriverContext(expression, state, dialect))} as ${dialect.quoteIdentifier(alias)}`).join(", ")
|
|
757
805
|
return {
|
|
758
806
|
sql,
|
|
759
807
|
projections
|
|
@@ -874,14 +922,18 @@ export const renderQueryAst = (
|
|
|
874
922
|
const table = targetSource.source as Table.AnyTable
|
|
875
923
|
const fields = table[Table.TypeId].fields
|
|
876
924
|
const rendered = unnestSource.values.map((entry) =>
|
|
877
|
-
`cast(${dialect.renderLiteral(entry.values, state)} as ${renderCastType(dialect, fields[entry.columnName]!.metadata.dbType)}[])`
|
|
925
|
+
`cast(${dialect.renderLiteral(encodeArrayValues(entry.values, fields[entry.columnName]!, state, dialect), state)} as ${renderCastType(dialect, fields[entry.columnName]!.metadata.dbType)}[])`
|
|
878
926
|
).join(", ")
|
|
879
927
|
sql += ` (${columns}) select * from unnest(${rendered})`
|
|
880
928
|
} else {
|
|
881
929
|
const rowCount = unnestSource.values[0]?.values.length ?? 0
|
|
882
930
|
const rows = Array.from({ length: rowCount }, (_, index) =>
|
|
883
931
|
`(${unnestSource.values.map((entry) =>
|
|
884
|
-
dialect.renderLiteral(
|
|
932
|
+
dialect.renderLiteral(
|
|
933
|
+
entry.values[index],
|
|
934
|
+
state,
|
|
935
|
+
(targetSource.source as Table.AnyTable)[Table.TypeId].fields[entry.columnName]![Expression.TypeId]
|
|
936
|
+
)
|
|
885
937
|
).join(", ")})`
|
|
886
938
|
).join(", ")
|
|
887
939
|
sql += ` (${columns}) values ${rows}`
|
|
@@ -1253,7 +1305,7 @@ export const renderExpression = (
|
|
|
1253
1305
|
? dialect.quoteIdentifier(ast.columnName)
|
|
1254
1306
|
: `${dialect.quoteIdentifier(ast.tableName)}.${dialect.quoteIdentifier(ast.columnName)}`
|
|
1255
1307
|
case "literal":
|
|
1256
|
-
return dialect.renderLiteral(ast.value, state)
|
|
1308
|
+
return dialect.renderLiteral(ast.value, state, expression[Expression.TypeId])
|
|
1257
1309
|
case "excluded":
|
|
1258
1310
|
return dialect.name === "mysql"
|
|
1259
1311
|
? `values(${dialect.quoteIdentifier(ast.columnName)})`
|
package/src/postgres/renderer.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as CoreRenderer from "../internal/renderer.js"
|
|
2
|
+
import type * as Expression from "../internal/scalar.js"
|
|
2
3
|
import { renderPostgresPlan } from "./internal/renderer.js"
|
|
3
4
|
|
|
4
5
|
/** Postgres-specialized rendered query shape. */
|
|
@@ -8,12 +9,16 @@ export type RowOf<Value extends RenderedQuery<any>> = CoreRenderer.RowOf<Value>
|
|
|
8
9
|
/** Postgres-specialized renderer contract. */
|
|
9
10
|
export type Renderer = CoreRenderer.Renderer<"postgres">
|
|
10
11
|
|
|
12
|
+
export interface MakeOptions {
|
|
13
|
+
readonly valueMappings?: Expression.DriverValueMappings
|
|
14
|
+
}
|
|
15
|
+
|
|
11
16
|
export { TypeId } from "../internal/renderer.js"
|
|
12
17
|
export type { Projection } from "../internal/renderer.js"
|
|
13
18
|
|
|
14
19
|
/** Creates the built-in Postgres renderer. */
|
|
15
|
-
export const make = (): Renderer =>
|
|
16
|
-
CoreRenderer.make("postgres", renderPostgresPlan)
|
|
20
|
+
export const make = (options: MakeOptions = {}): Renderer =>
|
|
21
|
+
CoreRenderer.make("postgres", (plan) => renderPostgresPlan(plan, options))
|
|
17
22
|
|
|
18
23
|
/** Shared built-in Postgres renderer instance. */
|
|
19
24
|
export const postgres = make()
|
package/src/postgres/type.ts
CHANGED
|
@@ -25,6 +25,10 @@ type PostgresTypeNamespace = typeof postgresDatatypes & {
|
|
|
25
25
|
readonly enum: <Kind extends string>(kind: Kind) => Expression.DbType.Enum<"postgres", Kind>
|
|
26
26
|
readonly set: <Kind extends string>(kind: Kind) => Expression.DbType.Set<"postgres", Kind>
|
|
27
27
|
readonly custom: <Kind extends string>(kind: Kind) => Expression.DbType.Base<"postgres", Kind>
|
|
28
|
+
readonly driverValueMapping: <Db extends Expression.DbType.Any>(
|
|
29
|
+
dbType: Db,
|
|
30
|
+
mapping: Expression.DriverValueMapping
|
|
31
|
+
) => Db
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
/** Postgres database-type constructors for casts and typed column references. */
|