@vibeorm/sql 5.1.0 → 5.3.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/ast.d.ts +41 -5
- package/dist/dialect.d.ts +10 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +80 -15
- package/dist/index.js.map +8 -8
- package/dist/locks.d.ts +12 -1
- package/dist/query/index.js.map +1 -1
- package/package.json +2 -2
package/dist/ast.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export type ColRef = {
|
|
|
45
45
|
* storage and read-back stay the exact text.
|
|
46
46
|
*/
|
|
47
47
|
readonly castReal?: boolean;
|
|
48
|
+
/** Native enum order key through a scalar subquery: MySQL reads its member index, other dialects keep the column. */
|
|
49
|
+
readonly enumOrdinal?: true;
|
|
48
50
|
/**
|
|
49
51
|
* Order/distinct/compare cast, postgres `json` columns only (`Json @db.Json`,
|
|
50
52
|
* release-3.0 D3): `json` has no ordering or equality operator, so ORDER BY,
|
|
@@ -93,6 +95,8 @@ export type AggRef = {
|
|
|
93
95
|
} | {
|
|
94
96
|
readonly fn: AggFn;
|
|
95
97
|
readonly column: ColRef;
|
|
98
|
+
/** Native enum MIN/MAX: projections and HAVING return the database label; order keys keep its ordinal. */
|
|
99
|
+
readonly enumOrder?: "value" | "ordinal";
|
|
96
100
|
};
|
|
97
101
|
/**
|
|
98
102
|
* One aggregate projection: `FN("col") AS "alias"`. The alias is part of the
|
|
@@ -463,18 +467,27 @@ export type OrderByAggregate = {
|
|
|
463
467
|
};
|
|
464
468
|
/**
|
|
465
469
|
* ORDER BY a correlated scalar subquery — relation orderBy
|
|
466
|
-
* (`orderBy: { posts: { _count: "desc" } }` → `(SELECT COUNT(*) …)
|
|
470
|
+
* (`orderBy: { posts: { _count: "desc" } }` → `(SELECT COUNT(*) …)`,
|
|
471
|
+
* `orderBy: { posts: { _max: { createdAt: "desc" } } }` → `(SELECT MAX(…) …)`,
|
|
467
472
|
* `orderBy: { author: { email: "asc" } }` → `(SELECT "email" …)`).
|
|
468
473
|
* Portable: all three dialects order by scalar subqueries. The subquery
|
|
469
474
|
* correlates to the outer scope through table-qualified `cmpCol` predicates,
|
|
470
475
|
* exactly like `exists`; its parameters merge into the statement's single
|
|
471
|
-
* sequence in render order.
|
|
472
|
-
*
|
|
473
|
-
* missing
|
|
476
|
+
* sequence in render order.
|
|
477
|
+
*
|
|
478
|
+
* `nulls` places the NULL a missing to-one row or a parent without related
|
|
479
|
+
* rows (under MIN/MAX/AVG/SUM) sorts as. Without it, NULL sorts at the
|
|
480
|
+
* engine's native position. Postgres and sqlite render `NULLS FIRST|LAST`;
|
|
481
|
+
* mysql renders the bare term when its native placement already matches, and
|
|
482
|
+
* otherwise a leading `(<subquery>) IS NULL` term — the subquery then renders
|
|
483
|
+
* twice and its parameters bind twice, in text order.
|
|
474
484
|
*/
|
|
475
485
|
export type OrderBySubquery = {
|
|
476
486
|
readonly select: SelectStatement;
|
|
487
|
+
/** A count behind a missing to-one row is zero, not NULL. */
|
|
488
|
+
readonly coalesce?: 0;
|
|
477
489
|
readonly direction: "asc" | "desc";
|
|
490
|
+
readonly nulls?: "first" | "last";
|
|
478
491
|
};
|
|
479
492
|
export type OrderTerm = OrderByColumn | OrderByAggregate | OrderBySubquery;
|
|
480
493
|
/**
|
|
@@ -519,6 +532,17 @@ export type LateralJoin = {
|
|
|
519
532
|
/** The correlated child select — may reference outer columns via table-qualified refs. */
|
|
520
533
|
readonly select: SelectStatement;
|
|
521
534
|
};
|
|
535
|
+
/**
|
|
536
|
+
* One scalar subquery in a projection. The builder guarantees a single column
|
|
537
|
+
* and at most one row. Hidden sort values stay inside derived tables rather
|
|
538
|
+
* than becoming result fields. `coalesce` preserves a count across a missing
|
|
539
|
+
* to-one hop.
|
|
540
|
+
*/
|
|
541
|
+
export type ScalarSubquery = {
|
|
542
|
+
readonly alias: string;
|
|
543
|
+
readonly select: SelectStatement;
|
|
544
|
+
readonly coalesce?: 0;
|
|
545
|
+
};
|
|
522
546
|
/**
|
|
523
547
|
* One correlated scalar `COUNT(*)` projected into a select list:
|
|
524
548
|
* `(SELECT COUNT(*) FROM … WHERE <correlation>) AS "alias"` — the relation
|
|
@@ -765,6 +789,8 @@ export type SelectStatement = {
|
|
|
765
789
|
readonly aggregates?: readonly AggSelect[];
|
|
766
790
|
/** Correlated `COUNT(*)` subqueries, rendered after `aggregates` — see {@link CountSubquery}. */
|
|
767
791
|
readonly countSubqueries?: readonly CountSubquery[];
|
|
792
|
+
/** Scalar values projected after count subqueries and before a row number. */
|
|
793
|
+
readonly scalarSubqueries?: readonly ScalarSubquery[];
|
|
768
794
|
/**
|
|
769
795
|
* `SELECT DISTINCT ON (cols)` — postgres only (`capabilities.distinctOn`;
|
|
770
796
|
* other dialects refuse at render time and the runtime emulates client-side
|
|
@@ -1146,6 +1172,12 @@ export type AdvisoryLockStatement = {
|
|
|
1146
1172
|
readonly wait: "wait" | "nowait";
|
|
1147
1173
|
readonly key: AdvisoryLockKey;
|
|
1148
1174
|
};
|
|
1175
|
+
/** An ordered set of transaction-scoped bigint advisory locks. */
|
|
1176
|
+
export type AdvisoryLocksStatement = {
|
|
1177
|
+
readonly kind: "advisoryLocks";
|
|
1178
|
+
readonly keys: readonly bigint[];
|
|
1179
|
+
readonly mode: AdvisoryLockMode;
|
|
1180
|
+
};
|
|
1149
1181
|
/** The column an advisory try-lock projects its verdict into. */
|
|
1150
1182
|
export declare const ADVISORY_LOCK_RESULT_COLUMN: string;
|
|
1151
1183
|
/**
|
|
@@ -1264,6 +1296,7 @@ export type ChainStep = {
|
|
|
1264
1296
|
* verdict-row outcome (the upsert fold always rolls it back).
|
|
1265
1297
|
*/
|
|
1266
1298
|
export type ChainResult = {
|
|
1299
|
+
/** Both lists may be empty for a tally-only result: one count row, no model values. */
|
|
1267
1300
|
readonly rowsFrom: readonly string[];
|
|
1268
1301
|
readonly columns: readonly string[];
|
|
1269
1302
|
readonly verdict?: {
|
|
@@ -1296,12 +1329,15 @@ export type ChainResult = {
|
|
|
1296
1329
|
* `minRows` (EPIC W) makes the veto count-sensitive: the statement fails when
|
|
1297
1330
|
* `step` returned FEWER rows than that (a multi-row INSERT a trigger shortened).
|
|
1298
1331
|
* Omitted or 1 = "no row". A positive safe integer, rendered as SQL text.
|
|
1332
|
+
* `exactRows` instead requires equality, including zero. It is a nonnegative
|
|
1333
|
+
* safe integer and cannot combine with `minRows`.
|
|
1299
1334
|
*/
|
|
1300
1335
|
export type ChainVeto = {
|
|
1301
1336
|
readonly step: string;
|
|
1302
1337
|
readonly token: string;
|
|
1303
1338
|
readonly nonce: string;
|
|
1304
1339
|
readonly minRows?: number;
|
|
1340
|
+
readonly exactRows?: number;
|
|
1305
1341
|
};
|
|
1306
1342
|
/** Count the RETURNING rows of `steps` into the result column `alias`. */
|
|
1307
1343
|
export type ChainTally = {
|
|
@@ -1341,7 +1377,7 @@ export type ChainStatement = {
|
|
|
1341
1377
|
readonly steps: readonly ChainStep[];
|
|
1342
1378
|
readonly result: ChainResult;
|
|
1343
1379
|
};
|
|
1344
|
-
export type SqlStatement = SelectStatement | InsertStatement | UpdateStatement | DeleteStatement | RlsEnableStatement | RlsForceStatement | RlsDisableStatement | RlsNoForceStatement | RlsDropPolicyStatement | RlsPolicyStatement | RlsContextStatement | RlsRoleStatement | AdvisoryLockStatement | ChainStatement;
|
|
1380
|
+
export type SqlStatement = SelectStatement | InsertStatement | UpdateStatement | DeleteStatement | RlsEnableStatement | RlsForceStatement | RlsDisableStatement | RlsNoForceStatement | RlsDropPolicyStatement | RlsPolicyStatement | RlsContextStatement | RlsRoleStatement | AdvisoryLockStatement | AdvisoryLocksStatement | ChainStatement;
|
|
1345
1381
|
/** Readiness statements remain distinct from application queries. */
|
|
1346
1382
|
export type RlsReadinessStatement = {
|
|
1347
1383
|
readonly kind: "rlsReadiness";
|
package/dist/dialect.d.ts
CHANGED
|
@@ -446,6 +446,16 @@ export type SqlDialect = {
|
|
|
446
446
|
quoteStringLiteral(params: {
|
|
447
447
|
value: string;
|
|
448
448
|
}): string;
|
|
449
|
+
/** Keep a native enum's ordering through a scalar subquery that may lose its physical enum type. */
|
|
450
|
+
renderEnumOrdinal(params: {
|
|
451
|
+
column: string;
|
|
452
|
+
}): string;
|
|
453
|
+
/** Render native enum MIN/MAX in database declaration order, returning its label or an order key. */
|
|
454
|
+
renderEnumMinMax(params: {
|
|
455
|
+
fn: "min" | "max";
|
|
456
|
+
column: string;
|
|
457
|
+
result: "value" | "ordinal";
|
|
458
|
+
}): string;
|
|
449
459
|
/** Positional placeholder for the 1-based parameter index ($n or ?). */
|
|
450
460
|
placeholder(params: {
|
|
451
461
|
index: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -40,10 +40,10 @@ export type { ResultDecoder, ResultReadDecoder, ResultParameterEncoder, ResultSc
|
|
|
40
40
|
* lives in this package; see the root sql-catalog.md for the reviewable surface.
|
|
41
41
|
*/
|
|
42
42
|
export { compileExclusion, renderExclusionSetup, renderExclusionDdl, renderExclusionCatalog, renderExclusionProbe } from "./exclusion.ts";
|
|
43
|
-
export type { AdvisoryLockKey, AdvisoryLockStatement, AggFn, AggRef, AggSelect, ChainResult, ChainRowSource, ChainStatement, ChainStep, ChainStepStatement, ChainTally, ChainVeto, ColRef, ComparisonOp, DateTruncation, CountSubquery, DeleteStatement, ExcludedRef, InnerJoin, KeyListMember, KeyPage, KeyRows, KeyTableJoin, KeyTableMember, InsertSelectStatement, InsertStatement, ReturningColumn, JsonFilterOp, LateralJoin, LeftJoin, ListSetOperation, OnConflictClause, OnConflictDoNothing, OnConflictUpdate, OrderByAggregate, OrderByColumn, OrderBySubquery, OrderTerm, RowLock, RowNumberProjection, DbNowMarker, JsonParamCell, SelectExpr, SelectStatement, SetOperation, SetOperator, SqlExpr, SqlStatement, StepColumnRef, TableRef, UpdateStatement, } from "./ast.ts";
|
|
43
|
+
export type { AdvisoryLockKey, AdvisoryLockStatement, AdvisoryLocksStatement, AggFn, AggRef, AggSelect, ChainResult, ChainRowSource, ChainStatement, ChainStep, ChainStepStatement, ChainTally, ChainVeto, ColRef, ComparisonOp, DateTruncation, CountSubquery, ScalarSubquery, DeleteStatement, ExcludedRef, InnerJoin, KeyListMember, KeyPage, KeyRows, KeyTableJoin, KeyTableMember, InsertSelectStatement, InsertStatement, ReturningColumn, JsonFilterOp, LateralJoin, LeftJoin, ListSetOperation, OnConflictClause, OnConflictDoNothing, OnConflictUpdate, OrderByAggregate, OrderByColumn, OrderBySubquery, OrderTerm, RowLock, RowNumberProjection, DbNowMarker, JsonParamCell, SelectExpr, SelectStatement, SetOperation, SetOperator, SqlExpr, SqlStatement, StepColumnRef, TableRef, UpdateStatement, } from "./ast.ts";
|
|
44
44
|
export { ADVISORY_LOCK_RESULT_COLUMN, CHAIN_VETO_PREFIX, CHAIN_VETO_TOKEN_PATTERN, SQL_DEFAULT_CELL, SQL_KEEP_CELL, chainVetoToken, dbNowMarker, excludedRef, isDbNowMarker, isExcludedRef, isJsonParamCell, isListSetOperation, isSetOperation, isSqlDefaultCell, isSqlKeepCell, isStepColumnRef, jsonParamCell, returningColumnName, stepColumnRef, } from "./ast.ts";
|
|
45
45
|
export type { AdvisoryLockFunctions, AdvisoryLockModeFunctions, RowLockSyntax, EmptyInsertSyntax, SqlDialect, } from "./dialect.ts";
|
|
46
|
-
export { ADVISORY_KEY_BOUNDS, describeRowLock, renderAdvisoryLock, renderRowLockClause } from "./locks.ts";
|
|
46
|
+
export { ADVISORY_KEY_BOUNDS, describeRowLock, renderAdvisoryLock, renderAdvisoryLocks, renderRowLockClause } from "./locks.ts";
|
|
47
47
|
export { JSON_TRANSPORT, projectionOutputName } from "./json-transport.ts";
|
|
48
48
|
export { postgresDialect } from "./dialects/postgres.ts";
|
|
49
49
|
export { sqliteDialect } from "./dialects/sqlite.ts";
|
package/dist/index.js
CHANGED
|
@@ -2402,6 +2402,12 @@ var sqliteDialect = {
|
|
|
2402
2402
|
quoteStringLiteral({ value }) {
|
|
2403
2403
|
return `'${value.replaceAll("'", "''")}'`;
|
|
2404
2404
|
},
|
|
2405
|
+
renderEnumOrdinal({ column }) {
|
|
2406
|
+
return column;
|
|
2407
|
+
},
|
|
2408
|
+
renderEnumMinMax({ fn, column }) {
|
|
2409
|
+
return `${fn === "min" ? "MIN" : "MAX"}(${column})`;
|
|
2410
|
+
},
|
|
2405
2411
|
placeholder() {
|
|
2406
2412
|
return "?";
|
|
2407
2413
|
},
|
|
@@ -2984,6 +2990,28 @@ function renderAdvisoryLock(params) {
|
|
|
2984
2990
|
returning: "none"
|
|
2985
2991
|
};
|
|
2986
2992
|
}
|
|
2993
|
+
function renderAdvisoryLocks(params) {
|
|
2994
|
+
const { dialect, keys, mode } = params;
|
|
2995
|
+
const functions = dialect.advisoryLockFunctions;
|
|
2996
|
+
if (functions === null)
|
|
2997
|
+
throw unsupportedCapability15({ dialect: dialect.name, feature: "advisory locks" });
|
|
2998
|
+
if (mode !== "exclusive" && mode !== "shared")
|
|
2999
|
+
throw internalError({ message: "advisory lock mode must be exclusive or shared" });
|
|
3000
|
+
if (keys.some((key) => typeof key !== "bigint" || key < ADVISORY_KEY_BOUNDS.single.min || key > ADVISORY_KEY_BOUNDS.single.max)) {
|
|
3001
|
+
throw internalError({ message: "advisory lock keys must be signed 64-bit integers" });
|
|
3002
|
+
}
|
|
3003
|
+
const collector = new ParamCollector(dialect);
|
|
3004
|
+
const binding = collector.add(JSON.stringify(keys.map((key) => key.toString())));
|
|
3005
|
+
const fn = (mode === "exclusive" ? functions.exclusive : functions.shared).wait;
|
|
3006
|
+
const table = dialect.quoteIdent({ name: "__vibe_locks" });
|
|
3007
|
+
const key = dialect.quoteIdent({ name: "key" });
|
|
3008
|
+
const order = dialect.quoteIdent({ name: "ordinal" });
|
|
3009
|
+
return {
|
|
3010
|
+
text: `SELECT ${fn}(${table}.${key}${functions.keyCast.single}) FROM jsonb_array_elements_text(${binding}::text::jsonb) WITH ORDINALITY AS ${table}(${key}, ${order}) ORDER BY ${table}.${order}`,
|
|
3011
|
+
values: collector.values,
|
|
3012
|
+
returning: "none"
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
2987
3015
|
function assertInt32(params) {
|
|
2988
3016
|
const { value, part } = params;
|
|
2989
3017
|
if (!Number.isInteger(value) || value < ADVISORY_KEY_BOUNDS.pair.min || value > ADVISORY_KEY_BOUNDS.pair.max) {
|
|
@@ -3075,6 +3103,12 @@ var postgresDialect = {
|
|
|
3075
3103
|
quoteStringLiteral({ value }) {
|
|
3076
3104
|
return `'${value.replaceAll("'", "''")}'`;
|
|
3077
3105
|
},
|
|
3106
|
+
renderEnumOrdinal({ column }) {
|
|
3107
|
+
return column;
|
|
3108
|
+
},
|
|
3109
|
+
renderEnumMinMax({ fn, column }) {
|
|
3110
|
+
return `${fn === "min" ? "MIN" : "MAX"}(${column})`;
|
|
3111
|
+
},
|
|
3078
3112
|
placeholder({ index }) {
|
|
3079
3113
|
return `$${index}`;
|
|
3080
3114
|
},
|
|
@@ -3148,6 +3182,15 @@ var mysqlDialect = {
|
|
|
3148
3182
|
quoteStringLiteral({ value }) {
|
|
3149
3183
|
return `'${value.replaceAll("\\", "\\\\").replaceAll("'", "''")}'`;
|
|
3150
3184
|
},
|
|
3185
|
+
renderEnumOrdinal({ column }) {
|
|
3186
|
+
return `${column} + 0`;
|
|
3187
|
+
},
|
|
3188
|
+
renderEnumMinMax({ fn, column, result }) {
|
|
3189
|
+
const aggregate = fn === "min" ? "MIN" : "MAX";
|
|
3190
|
+
if (result === "ordinal")
|
|
3191
|
+
return `${aggregate}(${column} + 0)`;
|
|
3192
|
+
return `SUBSTRING(${aggregate}(CONCAT(LPAD(${column} + 0, 5, '0'), ${column})), 6)`;
|
|
3193
|
+
},
|
|
3151
3194
|
placeholder() {
|
|
3152
3195
|
return "?";
|
|
3153
3196
|
},
|
|
@@ -4090,6 +4133,8 @@ function renderStatement(params) {
|
|
|
4090
4133
|
}
|
|
4091
4134
|
case "select":
|
|
4092
4135
|
return renderSelect({ dialect, statement, collector });
|
|
4136
|
+
case "advisoryLocks":
|
|
4137
|
+
return renderAdvisoryLocks({ dialect, keys: statement.keys, mode: statement.mode });
|
|
4093
4138
|
case "advisoryLock":
|
|
4094
4139
|
return renderAdvisoryLock({ dialect, statement, collector });
|
|
4095
4140
|
case "insert":
|
|
@@ -4129,6 +4174,8 @@ function quoteCol(dialect, column) {
|
|
|
4129
4174
|
const ref = column.table === undefined ? name : `${dialect.quoteIdent({ name: column.table })}.${name}`;
|
|
4130
4175
|
if (column.truncate !== undefined)
|
|
4131
4176
|
return renderDateTruncation({ dialect, reference: ref, truncation: column.truncate });
|
|
4177
|
+
if (column.enumOrdinal === true)
|
|
4178
|
+
return dialect.renderEnumOrdinal({ column: ref });
|
|
4132
4179
|
if (column.castReal === true) {
|
|
4133
4180
|
if (dialect.name !== "sqlite") {
|
|
4134
4181
|
throw internalError4({ message: "ColRef.castReal is a sqlite Decimal construct" });
|
|
@@ -4229,7 +4276,11 @@ var AGG_FN_SQL = {
|
|
|
4229
4276
|
function renderAggRef(dialect, agg) {
|
|
4230
4277
|
if (agg.fn === "countAll")
|
|
4231
4278
|
return "COUNT(*)";
|
|
4232
|
-
|
|
4279
|
+
const column = quoteCol(dialect, agg.column);
|
|
4280
|
+
if ((agg.fn === "min" || agg.fn === "max") && agg.enumOrder !== undefined) {
|
|
4281
|
+
return dialect.renderEnumMinMax({ fn: agg.fn, column, result: agg.enumOrder });
|
|
4282
|
+
}
|
|
4283
|
+
return `${AGG_FN_SQL[agg.fn]}(${column})`;
|
|
4233
4284
|
}
|
|
4234
4285
|
function assertScalarArrays(dialect, feature) {
|
|
4235
4286
|
if (dialect.capabilities.scalarArrays)
|
|
@@ -4770,23 +4821,20 @@ function renderOrderTerm(params) {
|
|
|
4770
4821
|
if ("agg" in term) {
|
|
4771
4822
|
return `${renderAggRef(dialect, term.agg)} ${term.direction === "asc" ? "ASC" : "DESC"}`;
|
|
4772
4823
|
}
|
|
4773
|
-
|
|
4774
|
-
const sub = renderSelect({ dialect, statement: term.select, collector });
|
|
4775
|
-
return `(${sub.text}) ${term.direction === "asc" ? "ASC" : "DESC"}`;
|
|
4776
|
-
}
|
|
4777
|
-
const column = quoteCol(dialect, term.column);
|
|
4824
|
+
const expression = "select" in term ? () => renderScalarSubquery({ dialect, subquery: term, collector }) : () => quoteCol(dialect, term.column);
|
|
4778
4825
|
const direction = term.direction === "asc" ? "ASC" : "DESC";
|
|
4779
4826
|
if (term.nulls === undefined) {
|
|
4780
|
-
return `${
|
|
4827
|
+
return `${expression()} ${direction}`;
|
|
4781
4828
|
}
|
|
4782
4829
|
if (dialect.orderByNullsMode === "native") {
|
|
4783
|
-
return `${
|
|
4830
|
+
return `${expression()} ${direction} NULLS ${term.nulls === "first" ? "FIRST" : "LAST"}`;
|
|
4784
4831
|
}
|
|
4785
4832
|
if (term.nulls === "first" === (term.direction === "asc")) {
|
|
4786
|
-
return `${
|
|
4833
|
+
return `${expression()} ${direction}`;
|
|
4787
4834
|
}
|
|
4788
|
-
const
|
|
4789
|
-
|
|
4835
|
+
const tested = expression();
|
|
4836
|
+
const nullsTerm = term.nulls === "first" ? `${tested} IS NULL DESC` : `${tested} IS NULL`;
|
|
4837
|
+
return `${nullsTerm}, ${expression()} ${direction}`;
|
|
4790
4838
|
}
|
|
4791
4839
|
function renderSelectExpr(params) {
|
|
4792
4840
|
const { dialect, expr } = params;
|
|
@@ -4837,7 +4885,7 @@ function renderLateralJoin(params) {
|
|
|
4837
4885
|
const json = lateralJsonOf({ dialect });
|
|
4838
4886
|
let aggOrder = "";
|
|
4839
4887
|
if (json.order === "inAggregate" && join.agg === "jsonArray" && join.select.orderBy !== undefined && join.select.orderBy.length > 0) {
|
|
4840
|
-
const projected = new Set(join.select.columns.filter((column) => column.transform === undefined && column.castReal !== true).map((column) => column.name));
|
|
4888
|
+
const projected = new Set(join.select.columns.filter((column) => column.transform === undefined && column.castReal !== true).map((column) => column.name).concat((join.select.scalarSubqueries ?? []).map((subquery) => subquery.alias)));
|
|
4841
4889
|
const terms = join.select.orderBy;
|
|
4842
4890
|
const columnTerms = terms.filter((term) => ("column" in term));
|
|
4843
4891
|
if (columnTerms.length === terms.length && columnTerms.every((term) => projected.has(term.column.name))) {
|
|
@@ -4863,12 +4911,17 @@ function renderLateralJoin(params) {
|
|
|
4863
4911
|
function renderCountSubquery(params) {
|
|
4864
4912
|
const { dialect, subquery, collector } = params;
|
|
4865
4913
|
const select = subquery.select;
|
|
4866
|
-
if (select.columns.length !== 0 || select.selectExpr?.kind !== "countAll" || (select.aggregates?.length ?? 0) > 0 || select.rowNumber !== undefined || select.groupBy !== undefined || select.having !== undefined || select.limit !== undefined || select.offset !== undefined || select.distinctOn !== undefined || select.distinct !== undefined || select.rowLock !== undefined || select.countSubqueries !== undefined) {
|
|
4914
|
+
if (select.columns.length !== 0 || select.selectExpr?.kind !== "countAll" || (select.aggregates?.length ?? 0) > 0 || select.rowNumber !== undefined || select.groupBy !== undefined || select.having !== undefined || select.limit !== undefined || select.offset !== undefined || select.distinctOn !== undefined || select.distinct !== undefined || select.rowLock !== undefined || select.countSubqueries !== undefined || select.scalarSubqueries !== undefined) {
|
|
4867
4915
|
throw internalError4({ message: "count subquery must be one ungrouped COUNT(*)" });
|
|
4868
4916
|
}
|
|
4869
4917
|
const inner = renderSelect({ dialect, statement: select, collector });
|
|
4870
4918
|
return `(${inner.text}) AS ${dialect.quoteIdent({ name: subquery.alias })}`;
|
|
4871
4919
|
}
|
|
4920
|
+
function renderScalarSubquery(params) {
|
|
4921
|
+
const { dialect, subquery, collector } = params;
|
|
4922
|
+
const value = `(${renderSelect({ dialect, statement: subquery.select, collector }).text})`;
|
|
4923
|
+
return subquery.coalesce === 0 ? `COALESCE(${value}, 0)` : value;
|
|
4924
|
+
}
|
|
4872
4925
|
function applyReturning(params) {
|
|
4873
4926
|
const { dialect, requested } = params;
|
|
4874
4927
|
if (requested === undefined || requested.length === 0) {
|
|
@@ -4977,6 +5030,11 @@ function renderSelect(params) {
|
|
|
4977
5030
|
columnList.push(renderCountSubquery({ dialect, subquery, collector }));
|
|
4978
5031
|
}
|
|
4979
5032
|
}
|
|
5033
|
+
if (statement.scalarSubqueries !== undefined) {
|
|
5034
|
+
for (const subquery of statement.scalarSubqueries) {
|
|
5035
|
+
columnList.push(`${renderScalarSubquery({ dialect, subquery, collector })} AS ${dialect.quoteIdent({ name: subquery.alias })}`);
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
4980
5038
|
if (statement.rowNumber !== undefined) {
|
|
4981
5039
|
const rowNumber = statement.rowNumber;
|
|
4982
5040
|
if (rowNumber.partitionBy.length === 0 && rowNumber.orderBy.length === 0) {
|
|
@@ -5393,6 +5451,9 @@ function renderChain(params) {
|
|
|
5393
5451
|
defined.add(step.name);
|
|
5394
5452
|
}
|
|
5395
5453
|
const result = statement.result;
|
|
5454
|
+
if (result.rowsFrom.length === 0 && result.columns.length === 0 && result.tally !== undefined && result.verdict === undefined) {
|
|
5455
|
+
return { text: `WITH ${steps.join(", ")} SELECT ${renderTallyColumn({ dialect, result, defined, collector })}`, values: collector.values, returning: "none" };
|
|
5456
|
+
}
|
|
5396
5457
|
if (result.rowsFrom.length === 0 || result.columns.length === 0) {
|
|
5397
5458
|
throw internalError4({ message: "a chain result needs at least one source step and one column" });
|
|
5398
5459
|
}
|
|
@@ -5491,7 +5552,10 @@ function renderTallyColumn(params) {
|
|
|
5491
5552
|
const minRows = veto.minRows ?? 1;
|
|
5492
5553
|
if (!Number.isSafeInteger(minRows) || minRows < 1)
|
|
5493
5554
|
throw internalError4({ message: `chain veto "${veto.token}" needs a positive integer minRows` });
|
|
5494
|
-
|
|
5555
|
+
if (veto.exactRows !== undefined && (!Number.isSafeInteger(veto.exactRows) || veto.exactRows < 0 || veto.minRows !== undefined)) {
|
|
5556
|
+
throw internalError4({ message: `chain veto "${veto.token}" needs a nonnegative safe integer exactRows without minRows` });
|
|
5557
|
+
}
|
|
5558
|
+
const when = veto.exactRows !== undefined ? `WHEN ${count(veto.step)} <> ${veto.exactRows}` : minRows === 1 ? `WHEN NOT EXISTS (SELECT 1 FROM ${step(veto.step)})` : `WHEN ${count(veto.step)} < ${minRows}`;
|
|
5495
5559
|
return `${when} THEN CAST('${CHAIN_VETO_PREFIX}${veto.token}:' || ${collector.add(veto.nonce)} || ':' || ${count(veto.step)} AS integer)`;
|
|
5496
5560
|
});
|
|
5497
5561
|
return `CASE ${arms.join(" ")} ELSE ${sum} END AS ${dialect.quoteIdent({ name: tally.alias })}`;
|
|
@@ -6275,6 +6339,7 @@ export {
|
|
|
6275
6339
|
recordSqlBindingCheck,
|
|
6276
6340
|
registerSqlHandleCheck,
|
|
6277
6341
|
renderAdvisoryLock,
|
|
6342
|
+
renderAdvisoryLocks,
|
|
6278
6343
|
renderCheckProbe,
|
|
6279
6344
|
renderColumnStateQuery,
|
|
6280
6345
|
renderConstraintOwnedIndexDrop,
|
|
@@ -6380,4 +6445,4 @@ export {
|
|
|
6380
6445
|
toPgArrayLiteral
|
|
6381
6446
|
};
|
|
6382
6447
|
|
|
6383
|
-
//# debugId=
|
|
6448
|
+
//# debugId=A6FF0AC9CFF5903864756E2164756E21
|