joist-core 2.3.0-next.78 → 2.3.0-next.79
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/build/execute.cjs +23 -5
- package/build/execute.cjs.map +1 -1
- package/build/execute.d.cts +10 -3
- package/build/execute.d.cts.map +1 -1
- package/build/execute.d.mts +10 -3
- package/build/execute.d.mts.map +1 -1
- package/build/execute.js +24 -6
- package/build/execute.js.map +1 -1
- package/build/query.cjs +30 -8
- package/build/query.cjs.map +1 -1
- package/build/query.d.cts +40 -1
- package/build/query.d.cts.map +1 -1
- package/build/query.d.mts +40 -1
- package/build/query.d.mts.map +1 -1
- package/build/query.js +27 -9
- package/build/query.js.map +1 -1
- package/package.json +2 -2
package/build/execute.cjs
CHANGED
|
@@ -40,13 +40,15 @@ function parseStatement(arg) {
|
|
|
40
40
|
"insert",
|
|
41
41
|
"values",
|
|
42
42
|
"from",
|
|
43
|
-
"returning"
|
|
43
|
+
"returning",
|
|
44
|
+
"with"
|
|
44
45
|
] : [
|
|
45
46
|
operation,
|
|
46
47
|
"where",
|
|
47
48
|
"allowAll",
|
|
48
49
|
"softDeletes",
|
|
49
50
|
"returning",
|
|
51
|
+
"with",
|
|
50
52
|
...operation === "update" ? ["set"] : []
|
|
51
53
|
], `SQL ${operation}`);
|
|
52
54
|
const target = statement[operation];
|
|
@@ -58,10 +60,14 @@ function parseStatement(arg) {
|
|
|
58
60
|
const fields = Object.values(meta.columns);
|
|
59
61
|
for (const field of fields) requireColumnMetadata(meta, field);
|
|
60
62
|
const assigner = new require_AliasAssigner.AliasAssigner();
|
|
61
|
-
const
|
|
63
|
+
const withCtx = new require_query.Ctx(assigner, void 0);
|
|
64
|
+
const ctes = require_query.registerCtes(statement, withCtx, assigner);
|
|
65
|
+
const refs = [];
|
|
66
|
+
const ctx = new require_query.Ctx(assigner, withCtx);
|
|
62
67
|
const alias = assigner.getAlias(meta.tableName);
|
|
63
68
|
ctx.register(mgmt, alias);
|
|
64
69
|
const returning = statement.returning === void 0 ? void 0 : require_query.projectionToSql(statement.returning, ctx);
|
|
70
|
+
if (returning) for (const select of returning.selects) refs.push(...select.refs);
|
|
65
71
|
let sql = `${operation === "delete" ? "DELETE FROM" : operation.toUpperCase() + (operation === "insert" ? " INTO" : "")} ${require_keywords.kq(meta.tableName)} AS ${require_keywords.kq(alias)}`;
|
|
66
72
|
const bindings = [];
|
|
67
73
|
if (operation === "insert") {
|
|
@@ -69,7 +75,7 @@ function parseStatement(arg) {
|
|
|
69
75
|
const required = fields.filter((column) => column.insert === "required");
|
|
70
76
|
if ("values" in statement) {
|
|
71
77
|
const rows = Array.isArray(statement.values) ? statement.values : [statement.values];
|
|
72
|
-
const valuesCtx = new require_query.Ctx(assigner,
|
|
78
|
+
const valuesCtx = new require_query.Ctx(assigner, withCtx);
|
|
73
79
|
const entries = rows.map((row) => assignments(meta, row, "insert"));
|
|
74
80
|
for (const row of entries) for (const field of required) if (!row.some((entry) => entry[0] === field.columnName)) require_utils.fail(`INSERT requires ${meta.type}.${field.columnName}`);
|
|
75
81
|
if (rows.length === 0) return void 0;
|
|
@@ -81,11 +87,12 @@ function parseStatement(arg) {
|
|
|
81
87
|
if (!entry) return "DEFAULT";
|
|
82
88
|
const cell = assignmentToSql(meta, field, entry[1], valuesCtx);
|
|
83
89
|
bindings.push(...cell.bindings);
|
|
90
|
+
refs.push(...cell.refs);
|
|
84
91
|
return cell.sql;
|
|
85
92
|
}).join(", ")})`;
|
|
86
93
|
}).join(", ");
|
|
87
94
|
} else {
|
|
88
|
-
const source = require_query.
|
|
95
|
+
const source = require_query.parseNestedQuery(statement.from, withCtx, assigner);
|
|
89
96
|
if (source.output.kind !== "pojo") require_utils.fail("INSERT SELECT requires named POJO output columns");
|
|
90
97
|
const columns = source.output.columns;
|
|
91
98
|
for (const field of required) if (!columns.some((column) => column[0] === field.columnName)) require_utils.fail(`INSERT requires ${meta.type}.${field.columnName}`);
|
|
@@ -100,6 +107,7 @@ function parseStatement(arg) {
|
|
|
100
107
|
const sourceAlias = require_keywords.safeKq(assigner.getLiteralAlias("sq"));
|
|
101
108
|
sql += ` (${keys.map((field) => require_keywords.kq(field.columnName)).join(", ")}) SELECT ${keys.map((field) => `${sourceAlias}.${require_keywords.safeKq(field.columnName)}`).join(", ")} FROM (${source.sql}) AS ${sourceAlias}`;
|
|
102
109
|
bindings.push(...source.bindings);
|
|
110
|
+
refs.push(...source.outerRefs);
|
|
103
111
|
}
|
|
104
112
|
} else {
|
|
105
113
|
if (statement.allowAll !== void 0 && typeof statement.allowAll !== "boolean") require_utils.fail("allowAll must be a boolean");
|
|
@@ -113,6 +121,7 @@ function parseStatement(arg) {
|
|
|
113
121
|
const field = writableField(meta, key, "update");
|
|
114
122
|
const cell = assignmentToSql(meta, field, value, ctx);
|
|
115
123
|
bindings.push(...cell.bindings);
|
|
124
|
+
refs.push(...cell.refs);
|
|
116
125
|
return `${require_keywords.kq(field.columnName)} = ${cell.sql}`;
|
|
117
126
|
}).join(", ");
|
|
118
127
|
}
|
|
@@ -122,13 +131,22 @@ function parseStatement(arg) {
|
|
|
122
131
|
}, statement.softDeletes ?? "exclude") }, ctx, true)].filter((condition) => condition !== void 0);
|
|
123
132
|
if (conditions.length) {
|
|
124
133
|
sql += ` WHERE ${conditions.map((condition) => `(${condition.sql})`).join(" AND ")}`;
|
|
125
|
-
for (const condition of conditions)
|
|
134
|
+
for (const condition of conditions) {
|
|
135
|
+
bindings.push(...condition.bindings);
|
|
136
|
+
refs.push(...condition.refs);
|
|
137
|
+
}
|
|
126
138
|
}
|
|
127
139
|
}
|
|
128
140
|
if (returning) {
|
|
129
141
|
sql += ` RETURNING ${returning.selects.map((select) => select.sql).join(", ")}`;
|
|
130
142
|
for (const select of returning.selects) bindings.push(...select.bindings);
|
|
131
143
|
}
|
|
144
|
+
const keptCtes = require_query.pruneCtes(ctes, new Set(refs));
|
|
145
|
+
if (keptCtes.length > 0) {
|
|
146
|
+
const clause = require_query.withFragment(keptCtes);
|
|
147
|
+
sql = clause.sql + sql;
|
|
148
|
+
bindings.unshift(...clause.bindings);
|
|
149
|
+
}
|
|
132
150
|
return {
|
|
133
151
|
sql,
|
|
134
152
|
bindings,
|
package/build/execute.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.cjs","names":["isReadQueryValue","parseUserQuery","isTable","getTableMgmt","AliasAssigner","Ctx","projectionToSql","kq","safeKq","conditionToSql","injectedConditions","isExpr","isEntity","asNode","keyToTaggedId","toTaggedId"],"sources":["../src/execute.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport { type Column } from \"./columns.ts\";\nimport { type SqlCondition } from \"./conditions.ts\";\nimport { type DriverQueryResult } from \"./drivers/Driver.ts\";\nimport { type Entity, isEntity } from \"./Entity.ts\";\nimport { type IdOf } from \"./EntityManager.ts\";\nimport { type EntityMetadata } from \"./EntityMetadata.ts\";\nimport { type ExprBrand, type ExprLike, type SqlFragment, asNode, exprBrand, isExpr } from \"./Expr.ts\";\nimport { keyToTaggedId, toTaggedId } from \"./keys.ts\";\nimport { kq, safeKq } from \"./keywords.ts\";\nimport {\n type CheckReadQuery,\n type CheckScope,\n type CheckSetQuery,\n Ctx,\n type EntityHydrator,\n type NameOf,\n type Plan,\n type Query,\n type QueryJoins,\n type QueryRow,\n type ReadQueryRow,\n type SetOperand,\n type SetOperation,\n type SetQuery,\n type Subquery,\n conditionToSql,\n entityQueryBrand,\n injectedConditions,\n isReadQueryValue,\n parseUserQuery,\n projectionToSql,\n subqueryBrand,\n} from \"./query.ts\";\nimport { type TableFor, getTableMgmt, isTable, tableMgmt } from \"./Tables.ts\";\nimport { type ColumnsOf, type TypeMapEntry } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** The native command count and decoded rows from one immediate SQL statement. */\nexport interface ExecuteResult<R> {\n rowCount: number;\n rows: R[];\n}\n\n/** A mutation's RETURNING projection: one SQL expression or a named object of expressions. */\nexport type MutationReturning = (ExprLike<unknown> | Readonly<Record<string, ExprLike<unknown>>>) & {\n readonly [tableMgmt]?: never;\n readonly [subqueryBrand]?: never;\n readonly [entityQueryBrand]?: never;\n};\n\n/** SQL INSERT inputs, based on physical storage rather than entity creation options. */\nexport type InsertValues<T extends Entity> = {\n [K in RequiredInsertKey<T>]: Assignment<T, K>;\n} & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: Assignment<T, K> | undefined;\n};\n\n/** SQL UPDATE inputs include persisted derived columns, but never primary keys. */\nexport type UpdateValues<T extends Entity> = {\n [K in UpdateKey<T>]?: Assignment<T, K> | undefined;\n};\n\n/** A reusable INSERT POJO; use a concrete Q for annotated INSERT SELECT source checking. */\nexport type InsertStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n Q extends SetOperand = Query<InsertProjection<T>, []> | Subquery<InsertSourceRow<T>, string>,\n> = {\n readonly insert: MutationTarget<T>;\n readonly returning?: R;\n readonly update?: never;\n readonly delete?: never;\n readonly set?: never;\n readonly where?: never;\n readonly allowAll?: never;\n readonly softDeletes?: never;\n} & NoMutationReadClauses &\n (\n | { readonly values: InsertValues<T> | readonly InsertValues<T>[]; readonly from?: never }\n | { readonly from: Q & CheckInsertSource<T, Q>; readonly values?: never }\n );\n\n/** A reusable guarded UPDATE POJO. Undefined assignments leave existing columns unchanged. */\nexport type UpdateStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = {\n readonly update: MutationTarget<T>;\n readonly set: UpdateValues<T>;\n readonly returning?: R;\n readonly insert?: never;\n readonly delete?: never;\n readonly values?: never;\n readonly from?: never;\n} & MutationFilter &\n NoMutationReadClauses;\n\n/** A reusable guarded physical DELETE POJO, not an ORM soft delete. */\nexport type DeleteStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = {\n readonly delete: MutationTarget<T>;\n readonly returning?: R;\n readonly insert?: never;\n readonly update?: never;\n readonly values?: never;\n readonly from?: never;\n readonly set?: never;\n} & MutationFilter &\n NoMutationReadClauses;\n\n/** Public statement annotations retain the target's physical field policy. */\nexport type MutationStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = InsertStatement<T, R> | UpdateStatement<T, R> | DeleteStatement<T, R>;\n\n/** Inference starts with the literal POJO; CheckMutation checks its target and every supplied key. */\nexport type MutationInput = (\n | { readonly insert: TableFor<Entity>; readonly values: object | readonly object[]; readonly from?: never }\n | { readonly insert: TableFor<Entity>; readonly from: SetOperand; readonly values?: never }\n | { readonly update: TableFor<Entity>; readonly set: object }\n | { readonly delete: TableFor<Entity> }\n) & { readonly returning?: MutationReturning } & MutationFilter;\n\n/** Without RETURNING the row type is never; scalar expressions produce scalar rows. */\nexport type MutationRow<M> = M extends { readonly returning?: infer R }\n ? R extends MutationReturning\n ? R extends ExprLike<unknown>\n ? QueryRow<R>\n : { -readonly [K in keyof QueryRow<R>]: QueryRow<R>[K] }\n : never\n : never;\n\n/** Checks nonliteral statements as well as fresh literals without widening their inferred result. */\nexport type CheckMutation<M> = M extends unknown\n ? TargetEntity<M> extends infer T extends Entity\n ? TypeMapEntry<T, \"supportsEmExecute\"> extends true\n ? { readonly [K in keyof M]: K extends MutationClause<M> ? unknown : never } & {\n readonly returning?: M extends { readonly returning?: infer R }\n ? CheckReturning<R, NameOf<TargetTable<M>>>\n : never;\n } & (\n | (M extends { readonly values: infer V } ? { readonly values: CheckValues<T, V> } : never)\n | (M extends { readonly from: infer Q extends SetOperand }\n ? { readonly from: CheckInsertSource<T, Q> }\n : never)\n | (M extends { readonly set: infer V }\n ? { readonly set: CheckAssignments<V, UpdateValues<T>, NameOf<TargetTable<M>>> }\n : never)\n | (M extends { readonly delete: unknown } ? unknown : never)\n )\n : \"SQL mutations require a supported non-inherited target and regenerated metadata\"\n : never\n : never;\n\n/** Classifies mutation roots before EntityManager applies write permissions, including malformed roots. */\nexport function isMutation(arg: unknown): boolean {\n return (\n typeof arg === \"object\" &&\n arg !== null &&\n !isReadQueryValue(arg) &&\n [\"insert\", \"update\", \"delete\"].some((key) => key in arg)\n );\n}\n\n/**\n * Compiles one immediate statement using the read compiler's scopes, projections, and codecs.\n * INSERT SELECT keeps source rows in PostgreSQL; only RETURNING rows pass through JS decoders.\n * An undefined plan represents a validated standalone empty VALUES array, not DEFAULT VALUES.\n */\nexport function parseStatement(arg: unknown): Plan | undefined {\n if (!isMutation(arg)) return parseUserQuery(arg);\n const statement = arg as Record<string, unknown>;\n const roots = [\"insert\", \"update\", \"delete\"].filter((key) => key in statement);\n if (roots.length !== 1) fail(\"A mutation requires exactly one insert, update, or delete root\");\n const operation = roots[0];\n const allowed =\n operation === \"insert\"\n ? [\"insert\", \"values\", \"from\", \"returning\"]\n : [operation, \"where\", \"allowAll\", \"softDeletes\", \"returning\", ...(operation === \"update\" ? [\"set\"] : [])];\n checkPojo(statement, allowed, `SQL ${operation}`);\n const target = statement[operation];\n if (!isTable(target)) fail(\"A mutation target must be an entity table\");\n const mgmt = getTableMgmt(target);\n const meta = mgmt.meta;\n if (meta.inheritanceType || meta.baseType || meta.baseTypes.length || meta.subTypes.length) {\n fail(\"SQL mutations do not support CTI/STI targets or inherited table families\");\n }\n if (meta.supportsEmExecute !== true)\n fail(`SQL mutations require supported physical metadata for ${meta.type}; run codegen`);\n const fields = Object.values(meta.columns);\n for (const field of fields) {\n requireColumnMetadata(meta, field);\n }\n const assigner = new AliasAssigner();\n const ctx = new Ctx(assigner, undefined);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(mgmt, alias);\n const returning = statement.returning === undefined ? undefined : projectionToSql(statement.returning, ctx);\n let sql = `${operation === \"delete\" ? \"DELETE FROM\" : operation.toUpperCase() + (operation === \"insert\" ? \" INTO\" : \"\")} ${kq(meta.tableName)} AS ${kq(alias)}`;\n const bindings: unknown[] = [];\n if (operation === \"insert\") {\n if (\"values\" in statement === \"from\" in statement) fail(\"INSERT requires exactly one of values or from\");\n const required = fields.filter((column) => column.insert === \"required\");\n if (\"values\" in statement) {\n const rows = Array.isArray(statement.values) ? statement.values : [statement.values];\n // No target is registered here: value subqueries own their sources, but no existing INSERT row exists.\n const valuesCtx = new Ctx(assigner, undefined);\n const entries = rows.map((row) => assignments(meta, row, \"insert\"));\n for (const row of entries) {\n for (const field of required) {\n if (!row.some((entry) => entry[0] === field.columnName))\n fail(`INSERT requires ${meta.type}.${field.columnName}`);\n }\n }\n if (rows.length === 0) return undefined;\n const keys = fields.filter((field) => entries.some((row) => row.some((entry) => entry[0] === field.columnName)));\n sql += ` (${keys.map((field) => kq(field.columnName)).join(\", \")}) VALUES `;\n sql += entries\n .map((row) => {\n const cells = keys.map((field) => {\n const entry = row.find((entry) => entry[0] === field.columnName);\n if (!entry) return \"DEFAULT\";\n const cell = assignmentToSql(meta, field, entry[1], valuesCtx);\n bindings.push(...cell.bindings);\n return cell.sql;\n });\n return `(${cells.join(\", \")})`;\n })\n .join(\", \");\n } else {\n const source = parseUserQuery(statement.from);\n if (source.output.kind !== \"pojo\") fail(\"INSERT SELECT requires named POJO output columns\");\n const columns = source.output.columns;\n for (const field of required) {\n if (!columns.some((column) => column[0] === field.columnName))\n fail(`INSERT requires ${meta.type}.${field.columnName}`);\n }\n for (const [key, expr] of columns) {\n const field = writableField(meta, key, \"insert\");\n const left = field.outputType;\n const right = expr.outputType;\n if (\n !left ||\n !right ||\n left.dbType !== right.dbType ||\n left.domain !== right.domain ||\n left.idMeta !== right.idMeta\n ) {\n fail(`INSERT SELECT ${meta.type}.${key} has incompatible or unknown storage codecs`);\n }\n if (!field.sqlNullable && expr.sqlNullable === true)\n fail(`INSERT SELECT ${meta.type}.${key} cannot accept a nullable output`);\n }\n const keys = fields.filter((field) => columns.some((column) => column[0] === field.columnName));\n const sourceAlias = safeKq(assigner.getLiteralAlias(\"sq\"));\n sql += ` (${keys.map((field) => kq(field.columnName)).join(\", \")}) SELECT ${keys.map((field) => `${sourceAlias}.${safeKq(field.columnName)}`).join(\", \")} FROM (${source.sql}) AS ${sourceAlias}`;\n bindings.push(...source.bindings);\n }\n } else {\n if (statement.allowAll !== undefined && typeof statement.allowAll !== \"boolean\") fail(\"allowAll must be a boolean\");\n if (\n statement.softDeletes !== undefined &&\n statement.softDeletes !== \"include\" &&\n statement.softDeletes !== \"exclude\"\n )\n fail(\"softDeletes must be 'include' or 'exclude'\");\n const user = mutationCondition(statement.where, ctx);\n if (!user && statement.allowAll !== true) fail(\"UPDATE and DELETE require a nonempty user where or allowAll: true\");\n if (operation === \"update\") {\n const entries = assignments(meta, statement.set, \"update\");\n sql +=\n \" SET \" +\n entries\n .map((entry) => {\n const [key, value] = entry;\n const field = writableField(meta, key, \"update\");\n const cell = assignmentToSql(meta, field, value, ctx);\n bindings.push(...cell.bindings);\n return `${kq(field.columnName)} = ${cell.sql}`;\n })\n .join(\", \");\n }\n const injected = conditionToSql(\n { and: injectedConditions({ meta, alias }, statement.softDeletes ?? \"exclude\") },\n ctx,\n true,\n );\n const conditions = [user, injected].filter((condition) => condition !== undefined);\n if (conditions.length) {\n sql += ` WHERE ${conditions.map((condition) => `(${condition.sql})`).join(\" AND \")}`;\n for (const condition of conditions) bindings.push(...condition.bindings);\n }\n }\n if (returning) {\n sql += ` RETURNING ${returning.selects.map((select) => select.sql).join(\", \")}`;\n for (const select of returning.selects) bindings.push(...select.bindings);\n }\n return {\n sql,\n bindings,\n outerRefs: [],\n output: returning?.output ?? { kind: \"pojo\", columns: [] },\n decodeRows: returning?.decodeRows ?? (() => []),\n };\n}\n\n/** Retains native counts even when no rows return, and propagates decoding failures after execution. */\nexport function decodeStatementResult(\n em: EntityHydrator,\n plan: Plan,\n result: DriverQueryResult,\n): ExecuteResult<unknown> {\n if (typeof result.rowCount !== \"number\" || !Number.isInteger(result.rowCount) || result.rowCount < 0)\n fail(\"The driver did not return a numeric command rowCount\");\n return { rowCount: result.rowCount, rows: plan.decodeRows(em, result.rows) };\n}\n\ntype MutationTarget<T extends Entity> = TableFor<T> &\n (TypeMapEntry<T, \"supportsEmExecute\"> extends true ? unknown : never);\ntype MutationFilter = {\n readonly where?: SqlCondition | ExprLike<boolean>;\n readonly allowAll?: boolean;\n readonly softDeletes?: \"include\" | \"exclude\";\n};\ntype NoMutationReadClauses = Partial<\n Record<\n | \"select\"\n | \"join\"\n | \"groupBy\"\n | \"having\"\n | \"orderBy\"\n | \"limit\"\n | \"offset\"\n | \"distinct\"\n | \"pruneJoins\"\n | \"as\"\n | \"union\"\n | \"unionAll\"\n | \"intersect\"\n | \"intersectAll\"\n | \"except\"\n | \"exceptAll\"\n | \"with\"\n | \"ctes\"\n | \"using\"\n | \"onConflict\",\n never\n >\n>;\n/** Column keys allowed in INSERT, i.e. Book's optional `id` and required `author_id`. */\ntype InsertKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { insert: \"required\" | \"optional\" } ? K : never;\n}[keyof ColumnsOf<T>];\n/** Column keys that each INSERT row must supply, i.e. Book's `author_id` despite its ORM default. */\ntype RequiredInsertKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { insert: \"required\" } ? K : never;\n}[keyof ColumnsOf<T>];\n/** Column keys allowed in UPDATE SET, i.e. Book's `title` and `author_id`, but not `id`. */\ntype UpdateKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { update: true } ? K : never;\n}[keyof ColumnsOf<T>];\n/** A column's domain value before SQL nullability is added, i.e. Book's `id` is BookId and `author_id` is AuthorId. */\ntype DomainValue<T, K extends keyof ColumnsOf<T>> = K extends \"id\"\n ? IdOf<T>\n : ColumnsOf<T>[K] extends { entity: infer U }\n ? IdOf<U>\n : ColumnsOf<T>[K] extends { type: infer V }\n ? V\n : never;\ntype SqlValue<T, K extends keyof ColumnsOf<T>> =\n | DomainValue<T, K>\n | (ColumnsOf<T>[K] extends { nullable: true } ? null : never);\ntype Assignment<T, K extends keyof ColumnsOf<T>> =\n | SqlValue<T, K>\n | ExprLike<SqlValue<T, K>>\n | (K extends \"id\" ? never : ColumnsOf<T>[K] extends { entity: infer U } ? U : never);\ntype InsertSourceRow<T> = { [K in RequiredInsertKey<T>]: SqlValue<T, K> } & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: SqlValue<T, K>;\n};\ntype InsertProjection<T> = { [K in RequiredInsertKey<T>]: ExprLike<SqlValue<T, K>> } & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: ExprLike<SqlValue<T, K>>;\n};\ntype UnionKeys<V> = V extends unknown ? keyof V : never;\n/** Collects every alternative before scope checking; a valid branch cannot hide an unrelated alias. */\ntype UnionValue<V, K extends PropertyKey> = V extends unknown ? (K extends keyof V ? V[K] : never) : never;\ntype ExprSource<V> = V extends { readonly [exprBrand]: ExprBrand<unknown, infer Src> } ? Src : never;\ntype CheckExprScope<V, Scope> =\n string extends ExprSource<V>\n ? unknown\n : [Exclude<ExprSource<V>, Scope>] extends [never]\n ? unknown\n : \"Expression source is not in the statement scope\";\ntype ReturningExpr<R> = R extends ExprLike<unknown> ? R : R extends undefined ? never : R[keyof R];\ntype EmptyReturning<R> = R extends object ? (keyof R extends never ? true : false) : false;\ntype CheckReturning<R, Scope> = true extends EmptyReturning<R> ? never : CheckExprScope<ReturningExpr<R>, Scope>;\ntype CheckAssignments<V, Allowed, Scope> = [Exclude<UnionKeys<V>, keyof Allowed>] extends [never]\n ? Allowed & {\n [K in UnionKeys<V>]?: CheckExprScope<UnionValue<V, K>, Scope>;\n }\n : \"SQL assignments have unknown target fields\";\ntype CheckValues<T extends Entity, V> =\n | ([Extract<V, readonly unknown[]>] extends [never]\n ? never\n : readonly CheckAssignments<Extract<V, readonly unknown[]>[number], InsertValues<T>, never>[])\n | ([Exclude<V, readonly unknown[]>] extends [never]\n ? never\n : CheckAssignments<Exclude<V, readonly unknown[]>, InsertValues<T>, never>);\ntype CheckSourceScope<Q> = Q extends { readonly select: infer S; readonly from: infer F }\n ? CheckScope<S, F, \"join\" extends keyof Q ? Extract<Q[keyof Q & \"join\"], QueryJoins> : []>\n : {\n [K in keyof Q]: K extends SetOperation\n ? Q[K] extends readonly unknown[]\n ? { [I in keyof Q[K]]: CheckSourceScope<Q[K][I]> }\n : unknown\n : unknown;\n };\ntype CheckInsertSource<T, Q extends SetOperand> = SetOperand extends Q\n ? \"INSERT source was typed too generically; retain its named output fields\"\n : ReadQueryRow<Q> extends InsertSourceRow<T>\n ? Exclude<UnionKeys<ReadQueryRow<Q>>, InsertKey<T>> extends never\n ? CheckReadQuery<Q> &\n CheckSourceScope<Q> &\n (Q extends SetQuery<readonly SetOperand[]> ? CheckSetQuery<Q> : unknown)\n : \"INSERT SELECT has unknown target fields\"\n : \"INSERT SELECT requires compatible values for all SQL-required fields\";\ntype TargetEntity<M> = M extends\n | { readonly insert: TableFor<infer T> }\n | { readonly update: TableFor<infer T> }\n | { readonly delete: TableFor<infer T> }\n ? T\n : never;\ntype TargetTable<M> = M extends\n | { readonly insert: infer A }\n | { readonly update: infer A }\n | { readonly delete: infer A }\n ? A\n : never;\ntype MutationClause<M> =\n | \"returning\"\n | (M extends { readonly insert: unknown }\n ? \"insert\" | (M extends { readonly values: unknown } ? \"values\" : \"from\")\n : \"where\" | \"allowAll\" | \"softDeletes\" | (M extends { readonly update: unknown } ? \"update\" | \"set\" : \"delete\"));\n/** SQL mutations require complete physical metadata. */\nfunction requireColumnMetadata(meta: EntityMetadata, column: Column): void {\n if (\n typeof column.sqlNullable !== \"boolean\" ||\n typeof column.hasDefault !== \"boolean\" ||\n typeof column.isGenerated !== \"boolean\"\n )\n fail(`Missing physical metadata for ${meta.type}.${column.columnName}; run codegen`);\n}\n\n/** Validates every supplied key, including undefined fields, before pruning omitted values. */\nfunction assignments(meta: EntityMetadata, value: unknown, operation: \"insert\" | \"update\"): [string, unknown][] {\n if (!value || typeof value !== \"object\" || Array.isArray(value) || isExpr(value) || isEntity(value))\n fail(`${operation} assignments must be a field POJO`);\n const entries = Object.entries(value);\n for (const [key] of entries) writableField(meta, key, operation);\n checkPojo(value, Object.keys(meta.columns), `${operation} assignments`);\n const defined = entries.filter((entry) => entry[1] !== undefined);\n if (!defined.length) fail(`${operation} requires at least one defined field; empty rows/sets are not DEFAULT VALUES`);\n return defined;\n}\n\n/** Applies physical write restrictions, not ORM-derived, protected, or business-immutable flags. */\nfunction writableField(meta: EntityMetadata, key: string, operation: \"insert\" | \"update\"): Column {\n const column = Object.hasOwn(meta.columns, key) ? meta.columns[key] : undefined;\n if (!column) fail(`Unsupported SQL mutation field ${meta.type}.${key}`);\n requireColumnMetadata(meta, column);\n if (operation === \"update\" && key === \"id\") fail(\"UPDATE primary-key assignments are not supported\");\n if (column.isGenerated) fail(`Generated field ${meta.type}.${key} is omit-only`);\n if (operation === \"update\" ? !column.update : column.insert === \"never\")\n fail(`Unsupported SQL mutation field ${meta.type}.${key}`);\n return column;\n}\n\n/**\n * Classifies SQL expressions and SQL NULL before invoking the column's entity-independent write codec.\n * Normalizes public PK/FK ids to internal tagged ids using the target entity's idType.\n */\nfunction assignmentToSql(meta: EntityMetadata, column: Column, value: unknown, ctx: Ctx): SqlFragment {\n if (isExpr(value)) return asNode(value).toSql(ctx);\n if (value === null) {\n if (!column.sqlNullable) fail(`${meta.type}.${column.columnName} is physically NOT NULL`);\n return { sql: \"NULL\", bindings: [], refs: [] };\n }\n if (column.idMetadata) {\n const other = column.idMetadata();\n if (isEntity(value)) {\n if (column.columnName === \"id\" || !(value instanceof other.cstr)) fail(`Expected a ${other.type} reference`);\n if (value.isNewEntity || value.idTaggedMaybe === undefined)\n fail(`Cannot reference an unflushed ${other.type}, even with an assigned ID`);\n value = value.idTaggedMaybe;\n } else if (typeof value !== (other.idType === \"number\" ? \"number\" : \"string\")) {\n fail(`Expected a persisted ${other.type} or its ID; nested creation is not supported`);\n } else {\n // Public untagged TEXT ids may contain delimiters or start with the entity tag.\n value =\n other.idType === \"untagged-string\"\n ? keyToTaggedId(other, value as string)\n : toTaggedId(other, value as string | number);\n }\n }\n if (!column.codec.mapToDbValue)\n fail(`The codec for ${meta.type}.${column.columnName} does not support SQL value writes`);\n return { sql: \"?\", bindings: [column.mapToDbValue(value)], refs: [] };\n}\n\n/** Checks the user predicate independently so metadata filters cannot turn a pruned guard into consent. */\nfunction mutationCondition(value: unknown, ctx: Ctx): SqlFragment | undefined {\n if (isExpr(value)) return asNode(value).toSql(ctx);\n return conditionToSql(value as SqlCondition | undefined, ctx, true);\n}\n\n/** Only own enumerable POJO clauses count as input or explicit full-table consent. */\nfunction checkPojo(value: object, allowed: readonly PropertyKey[], description: string): void {\n if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)\n fail(`${description} must be a plain POJO`);\n for (const key of Reflect.ownKeys(value)) {\n if (!allowed.includes(key)) fail(`${description} does not support '${String(key)}'`);\n if (typeof key === \"string\" && !Object.prototype.propertyIsEnumerable.call(value, key))\n fail(`${description} requires enumerable fields`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"execute.cjs","names":["isReadQueryValue","parseUserQuery","isTable","getTableMgmt","AliasAssigner","Ctx","registerCtes","projectionToSql","kq","parseNestedQuery","safeKq","conditionToSql","injectedConditions","pruneCtes","withFragment","isExpr","isEntity","asNode","keyToTaggedId","toTaggedId"],"sources":["../src/execute.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport { type Column } from \"./columns.ts\";\nimport { type SqlCondition } from \"./conditions.ts\";\nimport { type DriverQueryResult } from \"./drivers/Driver.ts\";\nimport { type Entity, isEntity } from \"./Entity.ts\";\nimport { type IdOf } from \"./EntityManager.ts\";\nimport { type EntityMetadata } from \"./EntityMetadata.ts\";\nimport { type ExprBrand, type ExprLike, type SqlFragment, asNode, exprBrand, isExpr } from \"./Expr.ts\";\nimport { keyToTaggedId, toTaggedId } from \"./keys.ts\";\nimport { kq, safeKq } from \"./keywords.ts\";\nimport {\n type CheckReadQuery,\n type CheckScope,\n type CheckSetQuery,\n Ctx,\n type EntityHydrator,\n type NameOf,\n type Plan,\n type Query,\n type QueryJoins,\n type QueryRow,\n type ReadQueryRow,\n type SetOperand,\n type SetOperation,\n type SetQuery,\n type Subquery,\n type WithInput,\n conditionToSql,\n entityQueryBrand,\n injectedConditions,\n isReadQueryValue,\n parseNestedQuery,\n parseUserQuery,\n projectionToSql,\n pruneCtes,\n registerCtes,\n subqueryBrand,\n withFragment,\n} from \"./query.ts\";\nimport { type TableFor, getTableMgmt, isTable, tableMgmt } from \"./Tables.ts\";\nimport { type ColumnsOf, type TypeMapEntry } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** The native command count and decoded rows from one immediate SQL statement. */\nexport interface ExecuteResult<R> {\n rowCount: number;\n rows: R[];\n}\n\n/** A mutation's RETURNING projection: one SQL expression or a named object of expressions. */\nexport type MutationReturning = (ExprLike<unknown> | Readonly<Record<string, ExprLike<unknown>>>) & {\n readonly [tableMgmt]?: never;\n readonly [subqueryBrand]?: never;\n readonly [entityQueryBrand]?: never;\n};\n\n/** SQL INSERT inputs, based on physical storage rather than entity creation options. */\nexport type InsertValues<T extends Entity> = {\n [K in RequiredInsertKey<T>]: Assignment<T, K>;\n} & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: Assignment<T, K> | undefined;\n};\n\n/** SQL UPDATE inputs include persisted derived columns, but never primary keys. */\nexport type UpdateValues<T extends Entity> = {\n [K in UpdateKey<T>]?: Assignment<T, K> | undefined;\n};\n\n/** A reusable INSERT POJO; use a concrete Q for annotated INSERT SELECT source checking. */\nexport type InsertStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n Q extends SetOperand = Query<InsertProjection<T>, []> | Subquery<InsertSourceRow<T>, string>,\n> = {\n readonly insert: MutationTarget<T>;\n readonly returning?: R;\n readonly update?: never;\n readonly delete?: never;\n readonly set?: never;\n readonly where?: never;\n readonly allowAll?: never;\n readonly softDeletes?: never;\n /** CTEs to add to a `WITH` before the INSERT; see `Clauses.with`. */\n readonly with?: WithInput;\n} & NoMutationReadClauses &\n (\n | { readonly values: InsertValues<T> | readonly InsertValues<T>[]; readonly from?: never }\n | { readonly from: Q & CheckInsertSource<T, Q>; readonly values?: never }\n );\n\n/** A reusable guarded UPDATE POJO. Undefined assignments leave existing columns unchanged. */\nexport type UpdateStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = {\n readonly update: MutationTarget<T>;\n readonly set: UpdateValues<T>;\n readonly returning?: R;\n readonly insert?: never;\n readonly delete?: never;\n readonly values?: never;\n readonly from?: never;\n /** CTEs to add to a `WITH` before the UPDATE; see `Clauses.with`. */\n readonly with?: WithInput;\n} & MutationFilter &\n NoMutationReadClauses;\n\n/** A reusable guarded physical DELETE POJO, not an ORM soft delete. */\nexport type DeleteStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = {\n readonly delete: MutationTarget<T>;\n readonly returning?: R;\n readonly insert?: never;\n readonly update?: never;\n readonly values?: never;\n readonly from?: never;\n readonly set?: never;\n /** CTEs to add to a `WITH` before the DELETE; see `Clauses.with`. */\n readonly with?: WithInput;\n} & MutationFilter &\n NoMutationReadClauses;\n\n/** Public statement annotations retain the target's physical field policy. */\nexport type MutationStatement<\n T extends Entity,\n R extends MutationReturning | undefined = MutationReturning | undefined,\n> = InsertStatement<T, R> | UpdateStatement<T, R> | DeleteStatement<T, R>;\n\n/** Inference starts with the literal POJO; CheckMutation checks its target and every supplied key. */\nexport type MutationInput = (\n | { readonly insert: TableFor<Entity>; readonly values: object | readonly object[]; readonly from?: never }\n | { readonly insert: TableFor<Entity>; readonly from: SetOperand; readonly values?: never }\n | { readonly update: TableFor<Entity>; readonly set: object }\n | { readonly delete: TableFor<Entity> }\n) & { readonly returning?: MutationReturning; readonly with?: WithInput } & MutationFilter;\n\n/** Without RETURNING the row type is never; scalar expressions produce scalar rows. */\nexport type MutationRow<M> = M extends { readonly returning?: infer R }\n ? R extends MutationReturning\n ? R extends ExprLike<unknown>\n ? QueryRow<R>\n : { -readonly [K in keyof QueryRow<R>]: QueryRow<R>[K] }\n : never\n : never;\n\n/** Checks nonliteral statements as well as fresh literals without widening their inferred result. */\nexport type CheckMutation<M> = M extends unknown\n ? TargetEntity<M> extends infer T extends Entity\n ? TypeMapEntry<T, \"supportsEmExecute\"> extends true\n ? { readonly [K in keyof M]: K extends MutationClause<M> ? unknown : never } & {\n readonly returning?: M extends { readonly returning?: infer R }\n ? CheckReturning<R, NameOf<TargetTable<M>>>\n : never;\n } & (\n | (M extends { readonly values: infer V } ? { readonly values: CheckValues<T, V> } : never)\n | (M extends { readonly from: infer Q extends SetOperand }\n ? { readonly from: CheckInsertSource<T, Q> }\n : never)\n | (M extends { readonly set: infer V }\n ? { readonly set: CheckAssignments<V, UpdateValues<T>, NameOf<TargetTable<M>>> }\n : never)\n | (M extends { readonly delete: unknown } ? unknown : never)\n )\n : \"SQL mutations require a supported non-inherited target and regenerated metadata\"\n : never\n : never;\n\n/** Classifies mutation roots before EntityManager applies write permissions, including malformed roots. */\nexport function isMutation(arg: unknown): boolean {\n return (\n typeof arg === \"object\" &&\n arg !== null &&\n !isReadQueryValue(arg) &&\n [\"insert\", \"update\", \"delete\"].some((key) => key in arg)\n );\n}\n\n/**\n * Compiles one immediate statement using the read compiler's scopes, projections, and codecs.\n * INSERT SELECT keeps source rows in PostgreSQL; only RETURNING rows pass through JS decoders.\n * An undefined plan represents a validated standalone empty VALUES array, not DEFAULT VALUES.\n */\nexport function parseStatement(arg: unknown): Plan | undefined {\n if (!isMutation(arg)) return parseUserQuery(arg);\n const statement = arg as Record<string, unknown>;\n const roots = [\"insert\", \"update\", \"delete\"].filter((key) => key in statement);\n if (roots.length !== 1) fail(\"A mutation requires exactly one insert, update, or delete root\");\n const operation = roots[0];\n const allowed =\n operation === \"insert\"\n ? [\"insert\", \"values\", \"from\", \"returning\", \"with\"]\n : [\n operation,\n \"where\",\n \"allowAll\",\n \"softDeletes\",\n \"returning\",\n \"with\",\n ...(operation === \"update\" ? [\"set\"] : []),\n ];\n checkPojo(statement, allowed, `SQL ${operation}`);\n const target = statement[operation];\n if (!isTable(target)) fail(\"A mutation target must be an entity table\");\n const mgmt = getTableMgmt(target);\n const meta = mgmt.meta;\n if (meta.inheritanceType || meta.baseType || meta.baseTypes.length || meta.subTypes.length) {\n fail(\"SQL mutations do not support CTI/STI targets or inherited table families\");\n }\n if (meta.supportsEmExecute !== true)\n fail(`SQL mutations require supported physical metadata for ${meta.type}; run codegen`);\n const fields = Object.values(meta.columns);\n for (const field of fields) {\n requireColumnMetadata(meta, field);\n }\n const assigner = new AliasAssigner();\n // A CTE is in scope for the whole statement, so its scope is the parent of every other one here. It\n // deliberately holds no target alias, which is what lets INSERT VALUES cells and the INSERT SELECT\n // source read the CTEs without also seeing the row being written.\n const withCtx = new Ctx(assigner, undefined);\n const ctes = registerCtes(statement, withCtx, assigner);\n // Aliases the rest of the statement reads, so an unread CTE prunes like it does on a read query.\n const refs: string[] = [];\n const ctx = new Ctx(assigner, withCtx);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(mgmt, alias);\n const returning = statement.returning === undefined ? undefined : projectionToSql(statement.returning, ctx);\n if (returning) for (const select of returning.selects) refs.push(...select.refs);\n let sql = `${operation === \"delete\" ? \"DELETE FROM\" : operation.toUpperCase() + (operation === \"insert\" ? \" INTO\" : \"\")} ${kq(meta.tableName)} AS ${kq(alias)}`;\n const bindings: unknown[] = [];\n if (operation === \"insert\") {\n if (\"values\" in statement === \"from\" in statement) fail(\"INSERT requires exactly one of values or from\");\n const required = fields.filter((column) => column.insert === \"required\");\n if (\"values\" in statement) {\n const rows = Array.isArray(statement.values) ? statement.values : [statement.values];\n // A VALUES cell *is* the new row, so there is no existing row for it to read: this scope skips\n // the `ctx.register(mgmt, alias)` above, so a cell naming the target fails instead of emitting a\n // `b` with no FROM clause. I.e. an UPDATE can say `set: { title: b.title }`; an INSERT cannot.\n // A value subquery still works, because it brings its own sources, and the parent here is the CTE\n // scope rather than `ctx`, so a cell can read a `with` entry but not the row being written.\n const valuesCtx = new Ctx(assigner, withCtx);\n const entries = rows.map((row) => assignments(meta, row, \"insert\"));\n for (const row of entries) {\n for (const field of required) {\n if (!row.some((entry) => entry[0] === field.columnName))\n fail(`INSERT requires ${meta.type}.${field.columnName}`);\n }\n }\n if (rows.length === 0) return undefined;\n const keys = fields.filter((field) => entries.some((row) => row.some((entry) => entry[0] === field.columnName)));\n sql += ` (${keys.map((field) => kq(field.columnName)).join(\", \")}) VALUES `;\n sql += entries\n .map((row) => {\n const cells = keys.map((field) => {\n const entry = row.find((entry) => entry[0] === field.columnName);\n if (!entry) return \"DEFAULT\";\n const cell = assignmentToSql(meta, field, entry[1], valuesCtx);\n bindings.push(...cell.bindings);\n refs.push(...cell.refs);\n return cell.sql;\n });\n return `(${cells.join(\", \")})`;\n })\n .join(\", \");\n } else {\n const source = parseNestedQuery(statement.from, withCtx, assigner);\n if (source.output.kind !== \"pojo\") fail(\"INSERT SELECT requires named POJO output columns\");\n const columns = source.output.columns;\n for (const field of required) {\n if (!columns.some((column) => column[0] === field.columnName))\n fail(`INSERT requires ${meta.type}.${field.columnName}`);\n }\n for (const [key, expr] of columns) {\n const field = writableField(meta, key, \"insert\");\n const left = field.outputType;\n const right = expr.outputType;\n if (\n !left ||\n !right ||\n left.dbType !== right.dbType ||\n left.domain !== right.domain ||\n left.idMeta !== right.idMeta\n ) {\n fail(`INSERT SELECT ${meta.type}.${key} has incompatible or unknown storage codecs`);\n }\n if (!field.sqlNullable && expr.sqlNullable === true)\n fail(`INSERT SELECT ${meta.type}.${key} cannot accept a nullable output`);\n }\n const keys = fields.filter((field) => columns.some((column) => column[0] === field.columnName));\n const sourceAlias = safeKq(assigner.getLiteralAlias(\"sq\"));\n sql += ` (${keys.map((field) => kq(field.columnName)).join(\", \")}) SELECT ${keys.map((field) => `${sourceAlias}.${safeKq(field.columnName)}`).join(\", \")} FROM (${source.sql}) AS ${sourceAlias}`;\n bindings.push(...source.bindings);\n refs.push(...source.outerRefs);\n }\n } else {\n if (statement.allowAll !== undefined && typeof statement.allowAll !== \"boolean\") fail(\"allowAll must be a boolean\");\n if (\n statement.softDeletes !== undefined &&\n statement.softDeletes !== \"include\" &&\n statement.softDeletes !== \"exclude\"\n )\n fail(\"softDeletes must be 'include' or 'exclude'\");\n const user = mutationCondition(statement.where, ctx);\n if (!user && statement.allowAll !== true) fail(\"UPDATE and DELETE require a nonempty user where or allowAll: true\");\n if (operation === \"update\") {\n const entries = assignments(meta, statement.set, \"update\");\n sql +=\n \" SET \" +\n entries\n .map((entry) => {\n const [key, value] = entry;\n const field = writableField(meta, key, \"update\");\n const cell = assignmentToSql(meta, field, value, ctx);\n bindings.push(...cell.bindings);\n refs.push(...cell.refs);\n return `${kq(field.columnName)} = ${cell.sql}`;\n })\n .join(\", \");\n }\n const injected = conditionToSql(\n { and: injectedConditions({ meta, alias }, statement.softDeletes ?? \"exclude\") },\n ctx,\n true,\n );\n const conditions = [user, injected].filter((condition) => condition !== undefined);\n if (conditions.length) {\n sql += ` WHERE ${conditions.map((condition) => `(${condition.sql})`).join(\" AND \")}`;\n for (const condition of conditions) {\n bindings.push(...condition.bindings);\n refs.push(...condition.refs);\n }\n }\n }\n if (returning) {\n sql += ` RETURNING ${returning.selects.map((select) => select.sql).join(\", \")}`;\n for (const select of returning.selects) bindings.push(...select.bindings);\n }\n const keptCtes = pruneCtes(ctes, new Set(refs));\n if (keptCtes.length > 0) {\n const clause = withFragment(keptCtes);\n sql = clause.sql + sql;\n bindings.unshift(...clause.bindings);\n }\n return {\n sql,\n bindings,\n outerRefs: [],\n output: returning?.output ?? { kind: \"pojo\", columns: [] },\n decodeRows: returning?.decodeRows ?? (() => []),\n };\n}\n\n/** Retains native counts even when no rows return, and propagates decoding failures after execution. */\nexport function decodeStatementResult(\n em: EntityHydrator,\n plan: Plan,\n result: DriverQueryResult,\n): ExecuteResult<unknown> {\n if (typeof result.rowCount !== \"number\" || !Number.isInteger(result.rowCount) || result.rowCount < 0)\n fail(\"The driver did not return a numeric command rowCount\");\n return { rowCount: result.rowCount, rows: plan.decodeRows(em, result.rows) };\n}\n\ntype MutationTarget<T extends Entity> = TableFor<T> &\n (TypeMapEntry<T, \"supportsEmExecute\"> extends true ? unknown : never);\ntype MutationFilter = {\n readonly where?: SqlCondition | ExprLike<boolean>;\n readonly allowAll?: boolean;\n readonly softDeletes?: \"include\" | \"exclude\";\n};\ntype NoMutationReadClauses = Partial<\n Record<\n | \"select\"\n | \"join\"\n | \"groupBy\"\n | \"having\"\n | \"orderBy\"\n | \"limit\"\n | \"offset\"\n | \"distinct\"\n | \"pruneJoins\"\n | \"as\"\n | \"union\"\n | \"unionAll\"\n | \"intersect\"\n | \"intersectAll\"\n | \"except\"\n | \"exceptAll\"\n | \"ctes\"\n | \"using\"\n | \"onConflict\",\n never\n >\n>;\n/** Column keys allowed in INSERT, i.e. Book's optional `id` and required `author_id`. */\ntype InsertKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { insert: \"required\" | \"optional\" } ? K : never;\n}[keyof ColumnsOf<T>];\n/** Column keys that each INSERT row must supply, i.e. Book's `author_id` despite its ORM default. */\ntype RequiredInsertKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { insert: \"required\" } ? K : never;\n}[keyof ColumnsOf<T>];\n/** Column keys allowed in UPDATE SET, i.e. Book's `title` and `author_id`, but not `id`. */\ntype UpdateKey<T> = {\n [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends { update: true } ? K : never;\n}[keyof ColumnsOf<T>];\n/** A column's domain value before SQL nullability is added, i.e. Book's `id` is BookId and `author_id` is AuthorId. */\ntype DomainValue<T, K extends keyof ColumnsOf<T>> = K extends \"id\"\n ? IdOf<T>\n : ColumnsOf<T>[K] extends { entity: infer U }\n ? IdOf<U>\n : ColumnsOf<T>[K] extends { type: infer V }\n ? V\n : never;\ntype SqlValue<T, K extends keyof ColumnsOf<T>> =\n | DomainValue<T, K>\n | (ColumnsOf<T>[K] extends { nullable: true } ? null : never);\ntype Assignment<T, K extends keyof ColumnsOf<T>> =\n | SqlValue<T, K>\n | ExprLike<SqlValue<T, K>>\n | (K extends \"id\" ? never : ColumnsOf<T>[K] extends { entity: infer U } ? U : never);\ntype InsertSourceRow<T> = { [K in RequiredInsertKey<T>]: SqlValue<T, K> } & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: SqlValue<T, K>;\n};\ntype InsertProjection<T> = { [K in RequiredInsertKey<T>]: ExprLike<SqlValue<T, K>> } & {\n [K in Exclude<InsertKey<T>, RequiredInsertKey<T>>]?: ExprLike<SqlValue<T, K>>;\n};\ntype UnionKeys<V> = V extends unknown ? keyof V : never;\n/** Collects every alternative before scope checking; a valid branch cannot hide an unrelated alias. */\ntype UnionValue<V, K extends PropertyKey> = V extends unknown ? (K extends keyof V ? V[K] : never) : never;\ntype ExprSource<V> = V extends { readonly [exprBrand]: ExprBrand<unknown, infer Src> } ? Src : never;\ntype CheckExprScope<V, Scope> =\n string extends ExprSource<V>\n ? unknown\n : [Exclude<ExprSource<V>, Scope>] extends [never]\n ? unknown\n : \"Expression source is not in the statement scope\";\ntype ReturningExpr<R> = R extends ExprLike<unknown> ? R : R extends undefined ? never : R[keyof R];\ntype EmptyReturning<R> = R extends object ? (keyof R extends never ? true : false) : false;\ntype CheckReturning<R, Scope> = true extends EmptyReturning<R> ? never : CheckExprScope<ReturningExpr<R>, Scope>;\ntype CheckAssignments<V, Allowed, Scope> = [Exclude<UnionKeys<V>, keyof Allowed>] extends [never]\n ? Allowed & {\n [K in UnionKeys<V>]?: CheckExprScope<UnionValue<V, K>, Scope>;\n }\n : \"SQL assignments have unknown target fields\";\ntype CheckValues<T extends Entity, V> =\n | ([Extract<V, readonly unknown[]>] extends [never]\n ? never\n : readonly CheckAssignments<Extract<V, readonly unknown[]>[number], InsertValues<T>, never>[])\n | ([Exclude<V, readonly unknown[]>] extends [never]\n ? never\n : CheckAssignments<Exclude<V, readonly unknown[]>, InsertValues<T>, never>);\ntype CheckSourceScope<Q> = Q extends { readonly select: infer S; readonly from: infer F }\n ? CheckScope<S, F, \"join\" extends keyof Q ? Extract<Q[keyof Q & \"join\"], QueryJoins> : []>\n : {\n [K in keyof Q]: K extends SetOperation\n ? Q[K] extends readonly unknown[]\n ? { [I in keyof Q[K]]: CheckSourceScope<Q[K][I]> }\n : unknown\n : unknown;\n };\ntype CheckInsertSource<T, Q extends SetOperand> = SetOperand extends Q\n ? \"INSERT source was typed too generically; retain its named output fields\"\n : ReadQueryRow<Q> extends InsertSourceRow<T>\n ? Exclude<UnionKeys<ReadQueryRow<Q>>, InsertKey<T>> extends never\n ? CheckReadQuery<Q> &\n CheckSourceScope<Q> &\n (Q extends SetQuery<readonly SetOperand[]> ? CheckSetQuery<Q> : unknown)\n : \"INSERT SELECT has unknown target fields\"\n : \"INSERT SELECT requires compatible values for all SQL-required fields\";\ntype TargetEntity<M> = M extends\n | { readonly insert: TableFor<infer T> }\n | { readonly update: TableFor<infer T> }\n | { readonly delete: TableFor<infer T> }\n ? T\n : never;\ntype TargetTable<M> = M extends\n | { readonly insert: infer A }\n | { readonly update: infer A }\n | { readonly delete: infer A }\n ? A\n : never;\ntype MutationClause<M> =\n | \"returning\"\n | \"with\"\n | (M extends { readonly insert: unknown }\n ? \"insert\" | (M extends { readonly values: unknown } ? \"values\" : \"from\")\n : \"where\" | \"allowAll\" | \"softDeletes\" | (M extends { readonly update: unknown } ? \"update\" | \"set\" : \"delete\"));\n/** SQL mutations require complete physical metadata. */\nfunction requireColumnMetadata(meta: EntityMetadata, column: Column): void {\n if (\n typeof column.sqlNullable !== \"boolean\" ||\n typeof column.hasDefault !== \"boolean\" ||\n typeof column.isGenerated !== \"boolean\"\n )\n fail(`Missing physical metadata for ${meta.type}.${column.columnName}; run codegen`);\n}\n\n/** Validates every supplied key, including undefined fields, before pruning omitted values. */\nfunction assignments(meta: EntityMetadata, value: unknown, operation: \"insert\" | \"update\"): [string, unknown][] {\n if (!value || typeof value !== \"object\" || Array.isArray(value) || isExpr(value) || isEntity(value))\n fail(`${operation} assignments must be a field POJO`);\n const entries = Object.entries(value);\n for (const [key] of entries) writableField(meta, key, operation);\n checkPojo(value, Object.keys(meta.columns), `${operation} assignments`);\n const defined = entries.filter((entry) => entry[1] !== undefined);\n if (!defined.length) fail(`${operation} requires at least one defined field; empty rows/sets are not DEFAULT VALUES`);\n return defined;\n}\n\n/** Applies physical write restrictions, not ORM-derived, protected, or business-immutable flags. */\nfunction writableField(meta: EntityMetadata, key: string, operation: \"insert\" | \"update\"): Column {\n const column = Object.hasOwn(meta.columns, key) ? meta.columns[key] : undefined;\n if (!column) fail(`Unsupported SQL mutation field ${meta.type}.${key}`);\n requireColumnMetadata(meta, column);\n if (operation === \"update\" && key === \"id\") fail(\"UPDATE primary-key assignments are not supported\");\n if (column.isGenerated) fail(`Generated field ${meta.type}.${key} is omit-only`);\n if (operation === \"update\" ? !column.update : column.insert === \"never\")\n fail(`Unsupported SQL mutation field ${meta.type}.${key}`);\n return column;\n}\n\n/**\n * Classifies SQL expressions and SQL NULL before invoking the column's entity-independent write codec.\n * Normalizes public PK/FK ids to internal tagged ids using the target entity's idType.\n */\nfunction assignmentToSql(meta: EntityMetadata, column: Column, value: unknown, ctx: Ctx): SqlFragment {\n if (isExpr(value)) return asNode(value).toSql(ctx);\n if (value === null) {\n if (!column.sqlNullable) fail(`${meta.type}.${column.columnName} is physically NOT NULL`);\n return { sql: \"NULL\", bindings: [], refs: [] };\n }\n if (column.idMetadata) {\n const other = column.idMetadata();\n if (isEntity(value)) {\n if (column.columnName === \"id\" || !(value instanceof other.cstr)) fail(`Expected a ${other.type} reference`);\n if (value.isNewEntity || value.idTaggedMaybe === undefined)\n fail(`Cannot reference an unflushed ${other.type}, even with an assigned ID`);\n value = value.idTaggedMaybe;\n } else if (typeof value !== (other.idType === \"number\" ? \"number\" : \"string\")) {\n fail(`Expected a persisted ${other.type} or its ID; nested creation is not supported`);\n } else {\n // Public untagged TEXT ids may contain delimiters or start with the entity tag.\n value =\n other.idType === \"untagged-string\"\n ? keyToTaggedId(other, value as string)\n : toTaggedId(other, value as string | number);\n }\n }\n if (!column.codec.mapToDbValue)\n fail(`The codec for ${meta.type}.${column.columnName} does not support SQL value writes`);\n return { sql: \"?\", bindings: [column.mapToDbValue(value)], refs: [] };\n}\n\n/** Checks the user predicate independently so metadata filters cannot turn a pruned guard into consent. */\nfunction mutationCondition(value: unknown, ctx: Ctx): SqlFragment | undefined {\n if (isExpr(value)) return asNode(value).toSql(ctx);\n return conditionToSql(value as SqlCondition | undefined, ctx, true);\n}\n\n/** Only own enumerable POJO clauses count as input or explicit full-table consent. */\nfunction checkPojo(value: object, allowed: readonly PropertyKey[], description: string): void {\n if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null)\n fail(`${description} must be a plain POJO`);\n for (const key of Reflect.ownKeys(value)) {\n if (!allowed.includes(key)) fail(`${description} does not support '${String(key)}'`);\n if (typeof key === \"string\" && !Object.prototype.propertyIsEnumerable.call(value, key))\n fail(`${description} requires enumerable fields`);\n }\n}\n"],"mappings":"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"}
|
package/build/execute.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ import { ColumnsOf, TypeMapEntry } from "./typeMap.cjs";
|
|
|
3
3
|
import { ExprBrand, ExprLike, exprBrand } from "./Expr.cjs";
|
|
4
4
|
import { TableFor, tableMgmt } from "./Tables.cjs";
|
|
5
5
|
import { DriverQueryResult } from "./drivers/Driver.cjs";
|
|
6
|
-
import { CheckReadQuery, CheckScope, CheckSetQuery, EntityHydrator, NameOf, Plan, Query, QueryJoins, QueryRow, ReadQueryRow, SetOperand, SetOperation, SetQuery, Subquery, entityQueryBrand, subqueryBrand } from "./query.cjs";
|
|
6
|
+
import { CheckReadQuery, CheckScope, CheckSetQuery, EntityHydrator, NameOf, Plan, Query, QueryJoins, QueryRow, ReadQueryRow, SetOperand, SetOperation, SetQuery, Subquery, WithInput, entityQueryBrand, subqueryBrand } from "./query.cjs";
|
|
7
7
|
import { IdOf } from "./EntityManager.cjs";
|
|
8
8
|
import { Entity } from "./Entity.cjs";
|
|
9
9
|
//#region src/execute.d.ts
|
|
@@ -32,6 +32,8 @@ type InsertStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
32
32
|
readonly where?: never;
|
|
33
33
|
readonly allowAll?: never;
|
|
34
34
|
readonly softDeletes?: never;
|
|
35
|
+
/** CTEs to add to a `WITH` before the INSERT; see `Clauses.with`. */
|
|
36
|
+
readonly with?: WithInput;
|
|
35
37
|
} & NoMutationReadClauses & ({
|
|
36
38
|
readonly values: InsertValues<T> | readonly InsertValues<T>[];
|
|
37
39
|
readonly from?: never;
|
|
@@ -48,6 +50,8 @@ type UpdateStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
48
50
|
readonly delete?: never;
|
|
49
51
|
readonly values?: never;
|
|
50
52
|
readonly from?: never;
|
|
53
|
+
/** CTEs to add to a `WITH` before the UPDATE; see `Clauses.with`. */
|
|
54
|
+
readonly with?: WithInput;
|
|
51
55
|
} & MutationFilter & NoMutationReadClauses;
|
|
52
56
|
/** A reusable guarded physical DELETE POJO, not an ORM soft delete. */
|
|
53
57
|
type DeleteStatement<T extends Entity, R extends MutationReturning | undefined = MutationReturning | undefined> = {
|
|
@@ -58,6 +62,8 @@ type DeleteStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
58
62
|
readonly values?: never;
|
|
59
63
|
readonly from?: never;
|
|
60
64
|
readonly set?: never;
|
|
65
|
+
/** CTEs to add to a `WITH` before the DELETE; see `Clauses.with`. */
|
|
66
|
+
readonly with?: WithInput;
|
|
61
67
|
} & MutationFilter & NoMutationReadClauses;
|
|
62
68
|
/** Public statement annotations retain the target's physical field policy. */
|
|
63
69
|
type MutationStatement<T extends Entity, R extends MutationReturning | undefined = MutationReturning | undefined> = InsertStatement<T, R> | UpdateStatement<T, R> | DeleteStatement<T, R>;
|
|
@@ -77,6 +83,7 @@ type MutationInput = ({
|
|
|
77
83
|
readonly delete: TableFor<Entity>;
|
|
78
84
|
}) & {
|
|
79
85
|
readonly returning?: MutationReturning;
|
|
86
|
+
readonly with?: WithInput;
|
|
80
87
|
} & MutationFilter;
|
|
81
88
|
/** Without RETURNING the row type is never; scalar expressions produce scalar rows. */
|
|
82
89
|
type MutationRow<M> = M extends {
|
|
@@ -118,7 +125,7 @@ type MutationFilter = {
|
|
|
118
125
|
readonly allowAll?: boolean;
|
|
119
126
|
readonly softDeletes?: "include" | "exclude";
|
|
120
127
|
};
|
|
121
|
-
type NoMutationReadClauses = Partial<Record<"select" | "join" | "groupBy" | "having" | "orderBy" | "limit" | "offset" | "distinct" | "pruneJoins" | "as" | "union" | "unionAll" | "intersect" | "intersectAll" | "except" | "exceptAll" | "
|
|
128
|
+
type NoMutationReadClauses = Partial<Record<"select" | "join" | "groupBy" | "having" | "orderBy" | "limit" | "offset" | "distinct" | "pruneJoins" | "as" | "union" | "unionAll" | "intersect" | "intersectAll" | "except" | "exceptAll" | "ctes" | "using" | "onConflict", never>>;
|
|
122
129
|
/** Column keys allowed in INSERT, i.e. Book's optional `id` and required `author_id`. */
|
|
123
130
|
type InsertKey<T> = { [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends {
|
|
124
131
|
insert: "required" | "optional";
|
|
@@ -176,7 +183,7 @@ type TargetTable<M> = M extends {
|
|
|
176
183
|
} | {
|
|
177
184
|
readonly delete: infer A;
|
|
178
185
|
} ? A : never;
|
|
179
|
-
type MutationClause<M> = "returning" | (M extends {
|
|
186
|
+
type MutationClause<M> = "returning" | "with" | (M extends {
|
|
180
187
|
readonly insert: unknown;
|
|
181
188
|
} ? "insert" | (M extends {
|
|
182
189
|
readonly values: unknown;
|
package/build/execute.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.cts","names":[],"sources":["../src/execute.ts"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"execute.d.cts","names":[],"sources":["../src/execute.ts"],"mappings":";;;;;;;;;;UA4CiB,cAAc;EAC7B;EACA,MAAM;;;KAII,qBAAqB,oBAAoB,SAAS,eAAe;YACjE;YACA;YACA;;;KAIA,aAAa,UAAU,aAChC,KAAK,kBAAkB,KAAK,WAAW,GAAG,WAE1C,KAAK,QAAQ,UAAU,IAAI,kBAAkB,OAAO,WAAW,GAAG;;KAIzD,aAAa,UAAU,aAChC,KAAK,UAAU,MAAM,WAAW,GAAG;;KAI1B,gBACV,UAAU,QACV,UAAU,gCAAgC,+BAC1C,UAAU,aAAa,MAAM,iBAAiB,UAAU,SAAS,gBAAgB;WAExE,QAAQ,eAAe;WACvB,YAAY;WACZ;WACA;WACA;WACA;WACA;WACA;;WAEA,OAAO;IACd;WAEa,QAAQ,aAAa,cAAc,aAAa;WAAe;;WAC/D,MAAM,IAAI,kBAAkB,GAAG;WAAa;;;KAIjD,gBACV,UAAU,QACV,UAAU,gCAAgC;WAEjC,QAAQ,eAAe;WACvB,KAAK,aAAa;WAClB,YAAY;WACZ;WACA;WACA;WACA;;WAEA,OAAO;IACd,iBACF;;KAGU,gBACV,UAAU,QACV,UAAU,gCAAgC;WAEjC,QAAQ,eAAe;WACvB,YAAY;WACZ;WACA;WACA;WACA;WACA;;WAEA,OAAO;IACd,iBACF;;KAGU,kBACV,UAAU,QACV,UAAU,gCAAgC,iCACxC,gBAAgB,GAAG,KAAK,gBAAgB,GAAG,KAAK,gBAAgB,GAAG;;KAG3D;WACG,QAAQ,SAAS;WAAkB;WAA6C;;WAChF,QAAQ,SAAS;WAAkB,MAAM;WAAqB;;WAC9D,QAAQ,SAAS;WAAkB;;WACnC,QAAQ,SAAS;;WACjB,YAAY;WAA4B,OAAO;IAAc;;KAGhE,YAAY,KAAK;WAAqB,kBAAkB;IAChE,UAAU,oBACR,UAAU,oBACR,SAAS,kBACI,WAAW,SAAS,KAAK,SAAS,GAAG;;KAK9C,cAAc,KAAK,oBAC3B,aAAa,kBAAiB,UAAU,UACtC,aAAa,mDACC,WAAW,IAAI,UAAU,eAAe;WACzC,YAAY;aAAqB,kBAAkB;MACxD,eAAe,GAAG,OAAO,YAAY;MAGpC;WAAqB,cAAc;;WAAiB,QAAQ,YAAY,GAAG;cAC3E;WAAqB,YAAY,UAAU;;WAC7B,MAAM,kBAAkB,GAAG;cAEzC;WAAqB,WAAW;;WAClB,KAAK,iBAAiB,GAAG,aAAa,IAAI,OAAO,YAAY;cAE3E;WAAqB;;;iBAOpB,WAAW;;;;;;iBAcX,eAAe,eAAe;;iBA0K9B,sBACd,IAAI,gBACJ,MAAM,MACN,QAAQ,oBACP;KAME,eAAe,UAAU,UAAU,SAAS,MAC9C,aAAa;KACX;WACM,QAAQ,eAAe;WACvB;WACA;;KAEN,wBAAwB,QAC3B;;KAwBG,UAAU,QACZ,WAAW,UAAU,KAAK,UAAU,GAAG;EAAa;IAAoC,mBACnF,UAAU;;KAEb,kBAAkB,QACpB,WAAW,UAAU,KAAK,UAAU,GAAG;EAAa;IAAuB,mBACtE,UAAU;;KAEb,UAAU,QACZ,WAAW,UAAU,KAAK,UAAU,GAAG;EAAa;IAAiB,mBAChE,UAAU;;KAEb,YAAY,GAAG,gBAAgB,UAAU,MAAM,iBAChD,KAAK,KACL,UAAU,GAAG;EAAa,cAAc;IACtC,KAAK,KACL,UAAU,GAAG;EAAa,YAAY;IACpC;KAEH,SAAS,GAAG,gBAAgB,UAAU,MACvC,YAAY,GAAG,MACd,UAAU,GAAG;EAAa;;KAC1B,WAAW,GAAG,gBAAgB,UAAU,MACzC,SAAS,GAAG,KACZ,SAAS,SAAS,GAAG,OACpB,yBAAyB,UAAU,GAAG;EAAa,cAAc;IAAM;KACvE,gBAAgB,QAAQ,KAAK,kBAAkB,KAAK,SAAS,GAAG,WAClE,KAAK,QAAQ,UAAU,IAAI,kBAAkB,OAAO,SAAS,GAAG;KAE9D,iBAAiB,QAAQ,KAAK,kBAAkB,KAAK,SAAS,SAAS,GAAG,YAC5E,KAAK,QAAQ,UAAU,IAAI,kBAAkB,OAAO,SAAS,SAAS,GAAG;KAEvE,UAAU,KAAK,0BAA0B;;KAEzC,WAAW,GAAG,UAAU,eAAe,qBAAqB,gBAAgB,IAAI,EAAE;KAClF,WAAW,KAAK;YAAsB,YAAY,yBAAyB;IAAS;KACpF,eAAe,GAAG,wBACN,WAAW,gBAErB,QAAQ,WAAW,IAAI;KAGzB,cAAc,KAAK,UAAU,oBAAoB,IAAI,8BAA8B,QAAQ;KAC3F,eAAe,KAAK,0BAA0B;KAC9C,eAAe,GAAG,sBAAsB,eAAe,aAAa,eAAe,cAAc,IAAI;KACrG,iBAAiB,GAAG,SAAS,UAAU,QAAQ,UAAU,UAAU,4BACpE,aACG,KAAK,UAAU,MAAM,eAAe,WAAW,GAAG,IAAI;KAGxD,YAAY,UAAU,QAAQ,OAC7B,QAAQ,2DAEG,iBAAiB,QAAQ,gCAAgC,aAAa,kBACjF,QAAQ,kDAEN,iBAAiB,QAAQ,wBAAwB,aAAa;KACjE,iBAAiB,KAAK;WAAqB,cAAc;WAAY,YAAY;IAClF,WAAW,GAAG,wBAAwB,IAAI,QAAQ,QAAQ,aAAa,uBAEpE,WAAW,IAAI,UAAU,eACtB,EAAE,mCACG,WAAW,EAAE,KAAK,iBAAiB,EAAE,GAAG;KAIlD,kBAAkB,GAAG,UAAU,cAAc,mBAAmB,gFAEjE,aAAa,WAAW,gBAAgB,KACtC,QAAQ,UAAU,aAAa,KAAK,UAAU,oBAC5C,eAAe,KACb,iBAAiB,MAChB,UAAU,kBAAkB,gBAAgB,cAAc;KAGhE,aAAa,KAAK;WACR,QAAQ,eAAe;;WACvB,QAAQ,eAAe;;WACvB,QAAQ,eAAe;IAClC;KAEC,YAAY,KAAK;WACP,cAAc;;WACd,cAAc;;WACd,cAAc;IACzB;KAEC,eAAe,6BAGf;WAAqB;gBACN;WAAqB;iEACO;WAAqB"}
|
package/build/execute.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import { ColumnsOf, TypeMapEntry } from "./typeMap.mjs";
|
|
|
3
3
|
import { ExprBrand, ExprLike, exprBrand } from "./Expr.mjs";
|
|
4
4
|
import { TableFor, tableMgmt } from "./Tables.mjs";
|
|
5
5
|
import { DriverQueryResult } from "./drivers/Driver.mjs";
|
|
6
|
-
import { CheckReadQuery, CheckScope, CheckSetQuery, EntityHydrator, NameOf, Plan, Query, QueryJoins, QueryRow, ReadQueryRow, SetOperand, SetOperation, SetQuery, Subquery, entityQueryBrand, subqueryBrand } from "./query.mjs";
|
|
6
|
+
import { CheckReadQuery, CheckScope, CheckSetQuery, EntityHydrator, NameOf, Plan, Query, QueryJoins, QueryRow, ReadQueryRow, SetOperand, SetOperation, SetQuery, Subquery, WithInput, entityQueryBrand, subqueryBrand } from "./query.mjs";
|
|
7
7
|
import { IdOf } from "./EntityManager.mjs";
|
|
8
8
|
import { Entity } from "./Entity.mjs";
|
|
9
9
|
//#region src/execute.d.ts
|
|
@@ -32,6 +32,8 @@ type InsertStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
32
32
|
readonly where?: never;
|
|
33
33
|
readonly allowAll?: never;
|
|
34
34
|
readonly softDeletes?: never;
|
|
35
|
+
/** CTEs to add to a `WITH` before the INSERT; see `Clauses.with`. */
|
|
36
|
+
readonly with?: WithInput;
|
|
35
37
|
} & NoMutationReadClauses & ({
|
|
36
38
|
readonly values: InsertValues<T> | readonly InsertValues<T>[];
|
|
37
39
|
readonly from?: never;
|
|
@@ -48,6 +50,8 @@ type UpdateStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
48
50
|
readonly delete?: never;
|
|
49
51
|
readonly values?: never;
|
|
50
52
|
readonly from?: never;
|
|
53
|
+
/** CTEs to add to a `WITH` before the UPDATE; see `Clauses.with`. */
|
|
54
|
+
readonly with?: WithInput;
|
|
51
55
|
} & MutationFilter & NoMutationReadClauses;
|
|
52
56
|
/** A reusable guarded physical DELETE POJO, not an ORM soft delete. */
|
|
53
57
|
type DeleteStatement<T extends Entity, R extends MutationReturning | undefined = MutationReturning | undefined> = {
|
|
@@ -58,6 +62,8 @@ type DeleteStatement<T extends Entity, R extends MutationReturning | undefined =
|
|
|
58
62
|
readonly values?: never;
|
|
59
63
|
readonly from?: never;
|
|
60
64
|
readonly set?: never;
|
|
65
|
+
/** CTEs to add to a `WITH` before the DELETE; see `Clauses.with`. */
|
|
66
|
+
readonly with?: WithInput;
|
|
61
67
|
} & MutationFilter & NoMutationReadClauses;
|
|
62
68
|
/** Public statement annotations retain the target's physical field policy. */
|
|
63
69
|
type MutationStatement<T extends Entity, R extends MutationReturning | undefined = MutationReturning | undefined> = InsertStatement<T, R> | UpdateStatement<T, R> | DeleteStatement<T, R>;
|
|
@@ -77,6 +83,7 @@ type MutationInput = ({
|
|
|
77
83
|
readonly delete: TableFor<Entity>;
|
|
78
84
|
}) & {
|
|
79
85
|
readonly returning?: MutationReturning;
|
|
86
|
+
readonly with?: WithInput;
|
|
80
87
|
} & MutationFilter;
|
|
81
88
|
/** Without RETURNING the row type is never; scalar expressions produce scalar rows. */
|
|
82
89
|
type MutationRow<M> = M extends {
|
|
@@ -118,7 +125,7 @@ type MutationFilter = {
|
|
|
118
125
|
readonly allowAll?: boolean;
|
|
119
126
|
readonly softDeletes?: "include" | "exclude";
|
|
120
127
|
};
|
|
121
|
-
type NoMutationReadClauses = Partial<Record<"select" | "join" | "groupBy" | "having" | "orderBy" | "limit" | "offset" | "distinct" | "pruneJoins" | "as" | "union" | "unionAll" | "intersect" | "intersectAll" | "except" | "exceptAll" | "
|
|
128
|
+
type NoMutationReadClauses = Partial<Record<"select" | "join" | "groupBy" | "having" | "orderBy" | "limit" | "offset" | "distinct" | "pruneJoins" | "as" | "union" | "unionAll" | "intersect" | "intersectAll" | "except" | "exceptAll" | "ctes" | "using" | "onConflict", never>>;
|
|
122
129
|
/** Column keys allowed in INSERT, i.e. Book's optional `id` and required `author_id`. */
|
|
123
130
|
type InsertKey<T> = { [K in keyof ColumnsOf<T>]: ColumnsOf<T>[K] extends {
|
|
124
131
|
insert: "required" | "optional";
|
|
@@ -176,7 +183,7 @@ type TargetTable<M> = M extends {
|
|
|
176
183
|
} | {
|
|
177
184
|
readonly delete: infer A;
|
|
178
185
|
} ? A : never;
|
|
179
|
-
type MutationClause<M> = "returning" | (M extends {
|
|
186
|
+
type MutationClause<M> = "returning" | "with" | (M extends {
|
|
180
187
|
readonly insert: unknown;
|
|
181
188
|
} ? "insert" | (M extends {
|
|
182
189
|
readonly values: unknown;
|
package/build/execute.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.mts","names":[],"sources":["../src/execute.ts"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"execute.d.mts","names":[],"sources":["../src/execute.ts"],"mappings":"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"}
|
package/build/execute.js
CHANGED
|
@@ -6,7 +6,7 @@ import "./EntityMetadata.js";
|
|
|
6
6
|
import { fail } from "./utils.js";
|
|
7
7
|
import { asNode, isExpr } from "./Expr.js";
|
|
8
8
|
import { getTableMgmt, isTable } from "./Tables.js";
|
|
9
|
-
import { Ctx, conditionToSql, injectedConditions, isReadQueryValue, parseUserQuery, projectionToSql } from "./query.js";
|
|
9
|
+
import { Ctx, conditionToSql, injectedConditions, isReadQueryValue, parseNestedQuery, parseUserQuery, projectionToSql, pruneCtes, registerCtes, withFragment } from "./query.js";
|
|
10
10
|
import "./drivers/Driver.js";
|
|
11
11
|
import "./EntityManager.js";
|
|
12
12
|
import { isEntity } from "./Entity.js";
|
|
@@ -39,13 +39,15 @@ function parseStatement(arg) {
|
|
|
39
39
|
"insert",
|
|
40
40
|
"values",
|
|
41
41
|
"from",
|
|
42
|
-
"returning"
|
|
42
|
+
"returning",
|
|
43
|
+
"with"
|
|
43
44
|
] : [
|
|
44
45
|
operation,
|
|
45
46
|
"where",
|
|
46
47
|
"allowAll",
|
|
47
48
|
"softDeletes",
|
|
48
49
|
"returning",
|
|
50
|
+
"with",
|
|
49
51
|
...operation === "update" ? ["set"] : []
|
|
50
52
|
], `SQL ${operation}`);
|
|
51
53
|
const target = statement[operation];
|
|
@@ -57,10 +59,14 @@ function parseStatement(arg) {
|
|
|
57
59
|
const fields = Object.values(meta.columns);
|
|
58
60
|
for (const field of fields) requireColumnMetadata(meta, field);
|
|
59
61
|
const assigner = new AliasAssigner();
|
|
60
|
-
const
|
|
62
|
+
const withCtx = new Ctx(assigner, void 0);
|
|
63
|
+
const ctes = registerCtes(statement, withCtx, assigner);
|
|
64
|
+
const refs = [];
|
|
65
|
+
const ctx = new Ctx(assigner, withCtx);
|
|
61
66
|
const alias = assigner.getAlias(meta.tableName);
|
|
62
67
|
ctx.register(mgmt, alias);
|
|
63
68
|
const returning = statement.returning === void 0 ? void 0 : projectionToSql(statement.returning, ctx);
|
|
69
|
+
if (returning) for (const select of returning.selects) refs.push(...select.refs);
|
|
64
70
|
let sql = `${operation === "delete" ? "DELETE FROM" : operation.toUpperCase() + (operation === "insert" ? " INTO" : "")} ${kq(meta.tableName)} AS ${kq(alias)}`;
|
|
65
71
|
const bindings = [];
|
|
66
72
|
if (operation === "insert") {
|
|
@@ -68,7 +74,7 @@ function parseStatement(arg) {
|
|
|
68
74
|
const required = fields.filter((column) => column.insert === "required");
|
|
69
75
|
if ("values" in statement) {
|
|
70
76
|
const rows = Array.isArray(statement.values) ? statement.values : [statement.values];
|
|
71
|
-
const valuesCtx = new Ctx(assigner,
|
|
77
|
+
const valuesCtx = new Ctx(assigner, withCtx);
|
|
72
78
|
const entries = rows.map((row) => assignments(meta, row, "insert"));
|
|
73
79
|
for (const row of entries) for (const field of required) if (!row.some((entry) => entry[0] === field.columnName)) fail(`INSERT requires ${meta.type}.${field.columnName}`);
|
|
74
80
|
if (rows.length === 0) return void 0;
|
|
@@ -80,11 +86,12 @@ function parseStatement(arg) {
|
|
|
80
86
|
if (!entry) return "DEFAULT";
|
|
81
87
|
const cell = assignmentToSql(meta, field, entry[1], valuesCtx);
|
|
82
88
|
bindings.push(...cell.bindings);
|
|
89
|
+
refs.push(...cell.refs);
|
|
83
90
|
return cell.sql;
|
|
84
91
|
}).join(", ")})`;
|
|
85
92
|
}).join(", ");
|
|
86
93
|
} else {
|
|
87
|
-
const source =
|
|
94
|
+
const source = parseNestedQuery(statement.from, withCtx, assigner);
|
|
88
95
|
if (source.output.kind !== "pojo") fail("INSERT SELECT requires named POJO output columns");
|
|
89
96
|
const columns = source.output.columns;
|
|
90
97
|
for (const field of required) if (!columns.some((column) => column[0] === field.columnName)) fail(`INSERT requires ${meta.type}.${field.columnName}`);
|
|
@@ -99,6 +106,7 @@ function parseStatement(arg) {
|
|
|
99
106
|
const sourceAlias = safeKq(assigner.getLiteralAlias("sq"));
|
|
100
107
|
sql += ` (${keys.map((field) => kq(field.columnName)).join(", ")}) SELECT ${keys.map((field) => `${sourceAlias}.${safeKq(field.columnName)}`).join(", ")} FROM (${source.sql}) AS ${sourceAlias}`;
|
|
101
108
|
bindings.push(...source.bindings);
|
|
109
|
+
refs.push(...source.outerRefs);
|
|
102
110
|
}
|
|
103
111
|
} else {
|
|
104
112
|
if (statement.allowAll !== void 0 && typeof statement.allowAll !== "boolean") fail("allowAll must be a boolean");
|
|
@@ -112,6 +120,7 @@ function parseStatement(arg) {
|
|
|
112
120
|
const field = writableField(meta, key, "update");
|
|
113
121
|
const cell = assignmentToSql(meta, field, value, ctx);
|
|
114
122
|
bindings.push(...cell.bindings);
|
|
123
|
+
refs.push(...cell.refs);
|
|
115
124
|
return `${kq(field.columnName)} = ${cell.sql}`;
|
|
116
125
|
}).join(", ");
|
|
117
126
|
}
|
|
@@ -121,13 +130,22 @@ function parseStatement(arg) {
|
|
|
121
130
|
}, statement.softDeletes ?? "exclude") }, ctx, true)].filter((condition) => condition !== void 0);
|
|
122
131
|
if (conditions.length) {
|
|
123
132
|
sql += ` WHERE ${conditions.map((condition) => `(${condition.sql})`).join(" AND ")}`;
|
|
124
|
-
for (const condition of conditions)
|
|
133
|
+
for (const condition of conditions) {
|
|
134
|
+
bindings.push(...condition.bindings);
|
|
135
|
+
refs.push(...condition.refs);
|
|
136
|
+
}
|
|
125
137
|
}
|
|
126
138
|
}
|
|
127
139
|
if (returning) {
|
|
128
140
|
sql += ` RETURNING ${returning.selects.map((select) => select.sql).join(", ")}`;
|
|
129
141
|
for (const select of returning.selects) bindings.push(...select.bindings);
|
|
130
142
|
}
|
|
143
|
+
const keptCtes = pruneCtes(ctes, new Set(refs));
|
|
144
|
+
if (keptCtes.length > 0) {
|
|
145
|
+
const clause = withFragment(keptCtes);
|
|
146
|
+
sql = clause.sql + sql;
|
|
147
|
+
bindings.unshift(...clause.bindings);
|
|
148
|
+
}
|
|
131
149
|
return {
|
|
132
150
|
sql,
|
|
133
151
|
bindings,
|