turbine-orm 0.90.2 → 0.91.0-next.32b6789
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -24
- package/dist/cjs/dialect.d.ts +26 -1
- package/dist/cjs/dialect.js +4 -0
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/mssql.js +2 -0
- package/dist/cjs/mysql.js +3 -0
- package/dist/cjs/powdb.js +2 -0
- package/dist/cjs/powql.d.ts +5 -2
- package/dist/cjs/powql.js +49 -28
- package/dist/cjs/prisma-compat.d.ts +2 -2
- package/dist/cjs/prisma-compat.js +8 -5
- package/dist/cjs/query/aggregates.js +74 -4
- package/dist/cjs/query/builder.d.ts +20 -7
- package/dist/cjs/query/builder.js +31 -22
- package/dist/cjs/query/expr.d.ts +47 -0
- package/dist/cjs/query/expr.js +129 -3
- package/dist/cjs/query/index.d.ts +1 -1
- package/dist/cjs/query/option-surface.js +3 -0
- package/dist/cjs/query/types.d.ts +107 -7
- package/dist/cjs/query/writes.d.ts +14 -2
- package/dist/cjs/query/writes.js +65 -18
- package/dist/cjs/sqlite.js +6 -0
- package/dist/dialect.d.ts +26 -1
- package/dist/dialect.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/mssql.js +2 -0
- package/dist/mysql.js +3 -0
- package/dist/powdb.js +2 -0
- package/dist/powql.d.ts +5 -2
- package/dist/powql.js +49 -28
- package/dist/prisma-compat.d.ts +2 -2
- package/dist/prisma-compat.js +8 -5
- package/dist/query/aggregates.js +74 -4
- package/dist/query/builder.d.ts +20 -7
- package/dist/query/builder.js +31 -22
- package/dist/query/expr.d.ts +47 -0
- package/dist/query/expr.js +128 -3
- package/dist/query/index.d.ts +1 -1
- package/dist/query/option-surface.js +3 -0
- package/dist/query/types.d.ts +107 -7
- package/dist/query/writes.d.ts +14 -2
- package/dist/query/writes.js +63 -18
- package/dist/sqlite.js +6 -0
- package/package.json +1 -1
- package/skills/turbine-orm/SKILL.md +8 -0
|
@@ -91,7 +91,7 @@ export declare function buildCreateMany<T extends object>(qi: BuilderCtx, args:
|
|
|
91
91
|
* builder (`skipGlobalFilters`), which a concurrent call could change across
|
|
92
92
|
* an await.
|
|
93
93
|
*/
|
|
94
|
-
export declare function planCreateMany<T extends object>(qi: BuilderCtx, args: CreateManyArgs<T>, projection?: WriteProjection): {
|
|
94
|
+
export declare function planCreateMany<T extends object>(qi: BuilderCtx, args: CreateManyArgs<T>, projection?: WriteProjection, canSplit?: boolean): {
|
|
95
95
|
chunks: DeferredQuery<T[]>[];
|
|
96
96
|
rowsPerChunk: number;
|
|
97
97
|
};
|
|
@@ -192,9 +192,21 @@ export declare function piiFields(_qi: BuilderCtx, meta: TableMetadata): string[
|
|
|
192
192
|
* 34,500/s with `RETURNING *`.
|
|
193
193
|
*/
|
|
194
194
|
export interface WriteProjection {
|
|
195
|
-
/**
|
|
195
|
+
/**
|
|
196
|
+
* Unquoted column names, in table order. Empty only for {@link COUNT_ONLY}:
|
|
197
|
+
* a caller's projection always names at least one column.
|
|
198
|
+
*/
|
|
196
199
|
readonly columns: readonly string[];
|
|
197
200
|
}
|
|
201
|
+
/**
|
|
202
|
+
* The projection of `createMany({ returning: false })`: no column. A plain
|
|
203
|
+
* insert then sends no RETURNING / OUTPUT and reports its row count; an
|
|
204
|
+
* onConflict call returns only its identity columns (see
|
|
205
|
+
* {@link conflictIdentity}), which the count is taken from.
|
|
206
|
+
*/
|
|
207
|
+
export declare const COUNT_ONLY: WriteProjection;
|
|
208
|
+
/** True for {@link COUNT_ONLY} (or any projection naming no column). */
|
|
209
|
+
export declare function isCountOnly(projection: WriteProjection | undefined): boolean;
|
|
198
210
|
/**
|
|
199
211
|
* The write-SQL cache segment for a projection. EMPTY for the default shape, so
|
|
200
212
|
* every existing key is byte-identical; a projected statement differs only in
|
package/dist/cjs/query/writes.js
CHANGED
|
@@ -45,6 +45,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
45
|
};
|
|
46
46
|
})();
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.COUNT_ONLY = void 0;
|
|
48
49
|
exports.coerceWriteValue = coerceWriteValue;
|
|
49
50
|
exports.buildReselectByWhere = buildReselectByWhere;
|
|
50
51
|
exports.buildCreate = buildCreate;
|
|
@@ -62,6 +63,7 @@ exports.buildUpdateMany = buildUpdateMany;
|
|
|
62
63
|
exports.buildDeleteMany = buildDeleteMany;
|
|
63
64
|
exports.piiColumns = piiColumns;
|
|
64
65
|
exports.piiFields = piiFields;
|
|
66
|
+
exports.isCountOnly = isCountOnly;
|
|
65
67
|
exports.writeProjectionCacheSegment = writeProjectionCacheSegment;
|
|
66
68
|
exports.applyUpdatedAtColumns = applyUpdatedAtColumns;
|
|
67
69
|
exports.writeReturningColumns = writeReturningColumns;
|
|
@@ -891,12 +893,17 @@ function buildCreateMany(qi, args, overBindLimit = 'refuse', projection) {
|
|
|
891
893
|
* builder (`skipGlobalFilters`), which a concurrent call could change across
|
|
892
894
|
* an await.
|
|
893
895
|
*/
|
|
894
|
-
function planCreateMany(qi, args, projection) {
|
|
896
|
+
function planCreateMany(qi, args, projection, canSplit = true) {
|
|
895
897
|
const prepared = prepareCreateMany(qi, args, projection);
|
|
896
898
|
if ('deferred' in prepared)
|
|
897
899
|
return { chunks: [prepared.deferred], rowsPerChunk: args.data.length };
|
|
898
900
|
const rows = prepared.rowValues;
|
|
899
|
-
const
|
|
901
|
+
const { most, chunk } = statementSizes(qi, prepared);
|
|
902
|
+
// Rows that cannot be told apart across statements (refused below past one),
|
|
903
|
+
// and a call whose executor cannot run several statements in one
|
|
904
|
+
// transaction (`canSplit`), take the fewest statements the engine allows;
|
|
905
|
+
// the rest are split at the size the engine runs fastest.
|
|
906
|
+
const size = !canSplit || (prepared.conflict && !prepared.identity) ? most : chunk;
|
|
900
907
|
if (rows.length <= size) {
|
|
901
908
|
return { chunks: [emitCreateMany(qi, prepared, rows, 'allow', true)], rowsPerChunk: size };
|
|
902
909
|
}
|
|
@@ -924,12 +931,19 @@ function prepareCreateMany(qi, args, projection) {
|
|
|
924
931
|
// The data-independent half of onConflict is checked before the empty-data
|
|
925
932
|
// shortcut, so a call is never valid with no rows and invalid with some.
|
|
926
933
|
const conflict = args.onConflict === undefined ? null : resolveConflictPlan(qi, args);
|
|
934
|
+
const countOnly = isCountOnly(projection);
|
|
935
|
+
// Before the empty-data shortcut too, so the refusal never depends on the rows.
|
|
936
|
+
if (countOnly && args.skipDuplicates && qi.dialect.capabilities.skipDuplicatesCountsSkipped) {
|
|
937
|
+
throw new errors_js_1.UnsupportedFeatureError('createMany({ skipDuplicates: true, returning: false })', qi.dialect.name, 'It counts a skipped row as written, so the count would include the rows skipped. Without ' +
|
|
938
|
+
'returning: false the call writes the same rows and reports no count.');
|
|
939
|
+
}
|
|
927
940
|
if (args.data.length === 0) {
|
|
928
941
|
return {
|
|
929
942
|
deferred: {
|
|
930
|
-
|
|
943
|
+
// `1 = 0`, not `false`: T-SQL has no boolean literal in a condition.
|
|
944
|
+
sql: `SELECT * FROM ${qt} WHERE 1 = 0`,
|
|
931
945
|
params: [],
|
|
932
|
-
transform: () => [],
|
|
946
|
+
transform: () => (countOnly ? { count: 0 } : []),
|
|
933
947
|
tag: `${qi.table}.createMany`,
|
|
934
948
|
},
|
|
935
949
|
};
|
|
@@ -958,7 +972,9 @@ function prepareCreateMany(qi, args, projection) {
|
|
|
958
972
|
deferred: {
|
|
959
973
|
sql: buildDefaultValuesInsert(qi, args.data.length, args.skipDuplicates, projection),
|
|
960
974
|
params: [],
|
|
961
|
-
transform: (result) =>
|
|
975
|
+
transform: (result) => countOnly
|
|
976
|
+
? countOf(result)
|
|
977
|
+
: result.rows.map((row) => parseWriteRow(qi, row, projection)),
|
|
962
978
|
tag: `${qi.table}.createMany`,
|
|
963
979
|
},
|
|
964
980
|
};
|
|
@@ -1036,32 +1052,40 @@ function emitCreateMany(qi, prepared, rowValues, overBindLimit, first) {
|
|
|
1036
1052
|
return {
|
|
1037
1053
|
sql: built.sql,
|
|
1038
1054
|
params: built.params,
|
|
1039
|
-
transform: (result) =>
|
|
1055
|
+
transform: (result) => isCountOnly(projection)
|
|
1056
|
+
? countOf(result)
|
|
1057
|
+
: result.rows.map((row) => parseWriteRow(qi, row, projection)),
|
|
1040
1058
|
tag: `${qi.table}.createMany`,
|
|
1041
1059
|
};
|
|
1042
1060
|
}
|
|
1043
1061
|
/**
|
|
1044
|
-
* Rows one `createMany` statement may carry
|
|
1045
|
-
* parameters within the engine's limit and, on SQL Server, its rows
|
|
1046
|
-
* the 1000 a plain `INSERT ... VALUES` accepts.
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1049
|
-
*
|
|
1062
|
+
* Rows one `createMany` statement may carry. `most`: the most that keep its
|
|
1063
|
+
* bind parameters within the engine's limit and, on SQL Server, its rows
|
|
1064
|
+
* within the 1000 a plain `INSERT ... VALUES` accepts. `chunk`: the same under
|
|
1065
|
+
* the engine's `chunkBindParameters`, the size a call that runs as several
|
|
1066
|
+
* statements is split at. The parameter cost is measured from one-row and
|
|
1067
|
+
* two-row builds, which separates the per-row parameters from the ones bound
|
|
1068
|
+
* once per statement (an onConflict update's values); the PostgreSQL UNNEST
|
|
1069
|
+
* form binds one array per column, so its rows never run out.
|
|
1050
1070
|
*/
|
|
1051
|
-
function
|
|
1071
|
+
function statementSizes(qi, prepared) {
|
|
1052
1072
|
// An onConflict statement (SQL Server's MERGE) reads its rows as a derived
|
|
1053
1073
|
// table, which the plain INSERT ... VALUES row cap does not bind.
|
|
1054
1074
|
const cap = prepared.conflict ? Infinity : qi.dialect.capabilities.maxInsertRows;
|
|
1055
|
-
const limit = (0, dialect_js_1.maxBindParameters)(qi.dialect);
|
|
1075
|
+
const limit = (0, dialect_js_1.maxBindParameters)(qi.dialect) ?? Infinity;
|
|
1076
|
+
// A dialect written before the key existed has none, and splits at its limit.
|
|
1077
|
+
const preferred = qi.dialect.capabilities.chunkBindParameters;
|
|
1078
|
+
const chunkLimit = typeof preferred === 'number' && preferred < limit ? preferred : limit;
|
|
1056
1079
|
const rows = prepared.rowValues;
|
|
1057
|
-
if (
|
|
1058
|
-
return cap;
|
|
1080
|
+
if (!Number.isFinite(chunkLimit) || rows.length < 2)
|
|
1081
|
+
return { most: cap, chunk: cap };
|
|
1059
1082
|
const one = emitCreateMany(qi, prepared, rows.slice(0, 1), 'allow', true).params.length;
|
|
1060
1083
|
const perRow = emitCreateMany(qi, prepared, rows.slice(0, 2), 'allow', true).params.length - one;
|
|
1061
1084
|
if (perRow <= 0)
|
|
1062
|
-
return cap;
|
|
1085
|
+
return { most: cap, chunk: cap };
|
|
1063
1086
|
const fixed = Math.max(0, one - perRow);
|
|
1064
|
-
|
|
1087
|
+
const fit = (bound) => Number.isFinite(bound) ? Math.max(1, Math.min(cap, Math.floor((bound - fixed) / perRow))) : cap;
|
|
1088
|
+
return { most: fit(limit), chunk: fit(chunkLimit) };
|
|
1065
1089
|
}
|
|
1066
1090
|
const ON_CONFLICT_KEYS = new Set(['target', 'update', 'where', 'ignore']);
|
|
1067
1091
|
/**
|
|
@@ -1422,6 +1446,11 @@ function buildBulkUpsert(qi, conflict, insert, columns, overBindLimit, projectio
|
|
|
1422
1446
|
transform: (result) => {
|
|
1423
1447
|
if (identity)
|
|
1424
1448
|
assertEachRowWrittenOnce(qi, conflict, identity, result.rows, first);
|
|
1449
|
+
// COUNT_ONLY: the rows back are the identity columns (or none at all when
|
|
1450
|
+
// the written rows cannot be identified), counted and never returned.
|
|
1451
|
+
if (isCountOnly(projection)) {
|
|
1452
|
+
return (identity ? { count: result.rows.length } : countOf(result));
|
|
1453
|
+
}
|
|
1425
1454
|
const rows = result.rows.map((row) => parseWriteRow(qi, row, projection));
|
|
1426
1455
|
if (identity && identity.added.length > 0) {
|
|
1427
1456
|
for (const row of rows)
|
|
@@ -2052,6 +2081,21 @@ function piiFields(_qi, meta) {
|
|
|
2052
2081
|
}
|
|
2053
2082
|
return out;
|
|
2054
2083
|
}
|
|
2084
|
+
/**
|
|
2085
|
+
* The projection of `createMany({ returning: false })`: no column. A plain
|
|
2086
|
+
* insert then sends no RETURNING / OUTPUT and reports its row count; an
|
|
2087
|
+
* onConflict call returns only its identity columns (see
|
|
2088
|
+
* {@link conflictIdentity}), which the count is taken from.
|
|
2089
|
+
*/
|
|
2090
|
+
exports.COUNT_ONLY = Object.freeze({ columns: Object.freeze([]) });
|
|
2091
|
+
/** True for {@link COUNT_ONLY} (or any projection naming no column). */
|
|
2092
|
+
function isCountOnly(projection) {
|
|
2093
|
+
return projection !== undefined && projection.columns.length === 0;
|
|
2094
|
+
}
|
|
2095
|
+
/** `{ count }` from a write that returned no rows to count: the engine's row count. */
|
|
2096
|
+
function countOf(result) {
|
|
2097
|
+
return { count: typeof result.rowCount === 'number' ? result.rowCount : result.rows.length };
|
|
2098
|
+
}
|
|
2055
2099
|
/**
|
|
2056
2100
|
* The write-SQL cache segment for a projection. EMPTY for the default shape, so
|
|
2057
2101
|
* every existing key is byte-identical; a projected statement differs only in
|
|
@@ -2147,6 +2191,9 @@ function writeReturningColumns(qi, projection) {
|
|
|
2147
2191
|
*/
|
|
2148
2192
|
function writeReselectSelection(qi, projection) {
|
|
2149
2193
|
const cols = writeReturningColumns(qi, projection);
|
|
2194
|
+
// COUNT_ONLY: the re-read is counted, not returned, so it reads no column.
|
|
2195
|
+
if (cols !== '*' && cols.length === 0)
|
|
2196
|
+
return '1';
|
|
2150
2197
|
return cols === '*' ? '*' : cols.join(', ');
|
|
2151
2198
|
}
|
|
2152
2199
|
/**
|
package/dist/cjs/sqlite.js
CHANGED
|
@@ -913,12 +913,16 @@ exports.sqliteDialect = {
|
|
|
913
913
|
// The default SQLITE_MAX_VARIABLE_NUMBER.
|
|
914
914
|
maxBindParameters: 32766,
|
|
915
915
|
maxInsertRows: Number.POSITIVE_INFINITY,
|
|
916
|
+
// Measured: 40,000 rows insert 70 to 140 times faster in statements of 250
|
|
917
|
+
// parameters than of 32,766 (named-parameter lookup is a linear search).
|
|
918
|
+
chunkBindParameters: 250,
|
|
916
919
|
upsertConflictTarget: 'explicit',
|
|
917
920
|
setClauseOrder: 'snapshot',
|
|
918
921
|
reselectLocksRows: false,
|
|
919
922
|
integerDivision: '/',
|
|
920
923
|
updateExpressions: true,
|
|
921
924
|
bulkUpsertAppliesRepeatedKeys: true,
|
|
925
|
+
skipDuplicatesCountsSkipped: false,
|
|
922
926
|
readOnlyTransactions: false,
|
|
923
927
|
connectionParameters: false,
|
|
924
928
|
backendCancel: false,
|
|
@@ -1129,6 +1133,8 @@ exports.sqliteDialect = {
|
|
|
1129
1133
|
(boolean ? 'Write true or false.' : 'Write a number, or a string holding one, such as "12.5".'));
|
|
1130
1134
|
},
|
|
1131
1135
|
buildReturningClause(selection = '*') {
|
|
1136
|
+
if (selection !== '*' && selection.length === 0)
|
|
1137
|
+
return '';
|
|
1132
1138
|
return ` RETURNING ${selection === '*' ? '*' : selection.join(', ')}`;
|
|
1133
1139
|
},
|
|
1134
1140
|
buildInsertStatement(input) {
|
package/dist/dialect.d.ts
CHANGED
|
@@ -501,6 +501,17 @@ export interface EngineCapabilities {
|
|
|
501
501
|
* not bound by it.
|
|
502
502
|
*/
|
|
503
503
|
readonly maxInsertRows: number;
|
|
504
|
+
/**
|
|
505
|
+
* The most bind parameters each statement of a `createMany` that runs as
|
|
506
|
+
* several statements carries: at most `maxBindParameters`, and lower where
|
|
507
|
+
* an engine slows faster than linearly with a statement's size. SQLite
|
|
508
|
+
* finds each named parameter by a linear search, at prepare and at bind, so
|
|
509
|
+
* 40,000 six-column rows took 141 s in statements of 32,766 parameters and
|
|
510
|
+
* 1 s in statements of 250. A call whose rows cannot be told apart
|
|
511
|
+
* across statements, or on a pool with no `connect()`, is not split below
|
|
512
|
+
* `maxBindParameters` (see `planCreateMany`).
|
|
513
|
+
*/
|
|
514
|
+
readonly chunkBindParameters: number;
|
|
504
515
|
/**
|
|
505
516
|
* What a single-statement upsert conflicts on. `'explicit'`: the conflict
|
|
506
517
|
* target it names. `'any-unique-key'`: whichever unique key collides first
|
|
@@ -531,6 +542,16 @@ export interface EngineCapabilities {
|
|
|
531
542
|
* it afterwards, so the statement runs in a transaction it can roll back.
|
|
532
543
|
*/
|
|
533
544
|
readonly bulkUpsertAppliesRepeatedKeys: boolean;
|
|
545
|
+
/**
|
|
546
|
+
* A `skipDuplicates` insert reports a skipped row as affected, so its row
|
|
547
|
+
* count cannot be the rows it inserted. MySQL: its skip is a no-op
|
|
548
|
+
* `ON DUPLICATE KEY UPDATE`, which under `CLIENT_FOUND_ROWS` (mysql2's
|
|
549
|
+
* default) counts a matched row, and a one-row statement's result carries no
|
|
550
|
+
* `info` to subtract the duplicates from. `createMany` refuses
|
|
551
|
+
* `skipDuplicates` with `returning: false` here (E017). False on an engine
|
|
552
|
+
* that never runs a skip.
|
|
553
|
+
*/
|
|
554
|
+
readonly skipDuplicatesCountsSkipped: boolean;
|
|
534
555
|
/** `$transaction({ readOnly: true })`: `READ ONLY` after the dialect's BEGIN. Else E017. */
|
|
535
556
|
readonly readOnlyTransactions: boolean;
|
|
536
557
|
/**
|
|
@@ -817,7 +838,11 @@ export interface Dialect {
|
|
|
817
838
|
readonly explainQuery?: {
|
|
818
839
|
prefix: string;
|
|
819
840
|
};
|
|
820
|
-
/**
|
|
841
|
+
/**
|
|
842
|
+
* Build a dialect-specific RETURNING clause. Return an empty string when
|
|
843
|
+
* unsupported, and for an empty column list (a write that returns no column,
|
|
844
|
+
* `createMany({ returning: false })`).
|
|
845
|
+
*/
|
|
821
846
|
buildReturningClause(selection?: ReturningSelection): string;
|
|
822
847
|
/** Build a single-row INSERT statement. Inputs are SQL-ready quoted fragments. */
|
|
823
848
|
buildInsertStatement(input: InsertStatementInput): string;
|
package/dist/dialect.js
CHANGED
|
@@ -102,12 +102,14 @@ export const postgresDialect = {
|
|
|
102
102
|
// Counted in a 16-bit field.
|
|
103
103
|
maxBindParameters: 65535,
|
|
104
104
|
maxInsertRows: Number.POSITIVE_INFINITY,
|
|
105
|
+
chunkBindParameters: 65535,
|
|
105
106
|
upsertConflictTarget: 'explicit',
|
|
106
107
|
setClauseOrder: 'snapshot',
|
|
107
108
|
reselectLocksRows: false,
|
|
108
109
|
integerDivision: '/',
|
|
109
110
|
updateExpressions: true,
|
|
110
111
|
bulkUpsertAppliesRepeatedKeys: false,
|
|
112
|
+
skipDuplicatesCountsSkipped: false,
|
|
111
113
|
readOnlyTransactions: true,
|
|
112
114
|
connectionParameters: true,
|
|
113
115
|
backendCancel: true,
|
|
@@ -185,6 +187,8 @@ export const postgresDialect = {
|
|
|
185
187
|
return `COALESCE((${subquery}), ${fallback})`;
|
|
186
188
|
},
|
|
187
189
|
buildReturningClause(selection = '*') {
|
|
190
|
+
if (selection !== '*' && selection.length === 0)
|
|
191
|
+
return '';
|
|
188
192
|
return ` RETURNING ${selection === '*' ? '*' : selection.join(', ')}`;
|
|
189
193
|
},
|
|
190
194
|
buildInsertStatement(input) {
|
package/dist/index.d.ts
CHANGED
|
@@ -47,9 +47,9 @@ export { HttpJsonSink, type HttpJsonSinkOptions, type MetricsFlushBatch, type Me
|
|
|
47
47
|
export { executePipeline, type PipelineOptions, type PipelineResults, pipelineSupported } from './pipeline.js';
|
|
48
48
|
export { fingerprintPrismaSchema } from './prisma-schema-fingerprint.js';
|
|
49
49
|
export { type CaseArm, type ExprOperand, expr, type NumericOperand } from './query/expr.js';
|
|
50
|
-
export { type AggregateArgs, type AggregateResult, type ArrayFilter, AUTO_ASSUMED_ROUND_TRIP_MS, AUTO_COUNT_BATCH_MIN_PARENT_ROWS, AUTO_JOIN_PENALTY_MS_PER_ROW, AUTO_TO_ONE_JOIN_MAX_ROWS, AUTO_TO_ONE_JOIN_ROWS_MAX, AUTO_TO_ONE_JOIN_ROWS_MIN, type ColumnRef, type ConnectOrCreateOp, type CountArgs, type CreateArgs, type CreateDataInput, type CreateManyArgs, col, type DeferredQuery, type DeleteArgs, type DeleteManyArgs, type FieldResult, type FindManyArgs, type FindManyStreamArgs, type FindUniqueArgs, type GlobalFilters, type GroupByAggregateSpec, type GroupByArgs, type GroupByDistinctOn, type GroupByResult, type HavingClause, type JsonEncoding, type JsonFilter, type JsonPathAggregateTarget, type JsonPathGroupKey, type JsonPathOrderBy, type JsonValue, jsonValue, type MiddlewareFn, type NestedCreateOp, type NestedUpdateOp, type NestedUpdateOpItem, type NestedUpsertOpItem, type OmitResult, type OrderByClause, type OrderByObject, type OrderBySpec, type OrderDirection, type PrivilegeOption, type QueryEvent, type QueryEventListener, QueryInterface, type QueryResult, type RelationDescriptor, type RelationFilter, type RelationLoadStrategy, type RelationOrderBy, type RelationOrderByChain, type RelationPickBy, type RelationPickOrderBy, type SelectResult, type SkipGlobalFilters, type TemporalInfinityReading, type TextSearchFilter, type TypedWithClause, UNSAFE, type Unsafe, type UpdateArgs, type UpdateDataInput, type UpdateInput, type UpdateManyArgs, type UpdateOperatorInput, type UpsertArgs, type VectorDistanceFilter, type VectorFilter, type VectorMetric, type VectorOrderBy, type VectorOrderByDistance, type WhereClause, type WhereOperator, type WhereValue, type WithClause, type WithOptions, type WithOrderByObject, type WithResult, } from './query/index.js';
|
|
50
|
+
export { type AggregateArgs, type AggregateResult, type ArrayFilter, AUTO_ASSUMED_ROUND_TRIP_MS, AUTO_COUNT_BATCH_MIN_PARENT_ROWS, AUTO_JOIN_PENALTY_MS_PER_ROW, AUTO_TO_ONE_JOIN_MAX_ROWS, AUTO_TO_ONE_JOIN_ROWS_MAX, AUTO_TO_ONE_JOIN_ROWS_MIN, type ColumnRef, type ConnectOrCreateOp, type CountArgs, type CreateArgs, type CreateDataInput, type CreateManyArgs, type CreateManyCount, type CreateManyResult, col, type DeferredQuery, type DeleteArgs, type DeleteManyArgs, type FieldResult, type FindManyArgs, type FindManyStreamArgs, type FindUniqueArgs, type GlobalFilters, type GroupByAggregateSpec, type GroupByArgs, type GroupByDistinctOn, type GroupByResult, type HavingClause, type JsonEncoding, type JsonFilter, type JsonPathAggregateTarget, type JsonPathGroupKey, type JsonPathOrderBy, type JsonValue, jsonValue, type MiddlewareFn, type NestedCreateOp, type NestedUpdateOp, type NestedUpdateOpItem, type NestedUpsertOpItem, type OmitResult, type OrderByClause, type OrderByObject, type OrderBySpec, type OrderDirection, type PrivilegeOption, type QueryEvent, type QueryEventListener, QueryInterface, type QueryResult, type RelationDescriptor, type RelationFilter, type RelationLoadStrategy, type RelationOrderBy, type RelationOrderByChain, type RelationPickBy, type RelationPickOrderBy, type SelectResult, type SkipGlobalFilters, type TemporalInfinityReading, type TextSearchFilter, type TypedWithClause, UNSAFE, type Unsafe, type UpdateArgs, type UpdateDataInput, type UpdateInput, type UpdateManyArgs, type UpdateOperatorInput, type UpsertArgs, type VectorDistanceFilter, type VectorFilter, type VectorMetric, type VectorOrderBy, type VectorOrderByDistance, type WhereClause, type WhereOperator, type WhereValue, type WithClause, type WithOptions, type WithOrderByObject, type WithResult, } from './query/index.js';
|
|
51
51
|
export type { SqlCommentOptions } from './query/sql-comment.js';
|
|
52
|
-
export type { AggregateResultOf, ConflictTarget, ConflictUpdateData, CreateManyOnConflict, DefaultInputTypes, ExcludedRef, GlobalFilter, NestedToOneCreateOp, NestedToOneUpdateOp, OptionalInput, PercentileMethod, PercentileSpec, RelationKind, RowLock, RowLockMode, SqlExpr, SqlExprKind, TableInputTypes, } from './query/types.js';
|
|
52
|
+
export type { AggregateResultOf, ConflictTarget, ConflictUpdateData, CreateManyOnConflict, DefaultInputTypes, ExcludedRef, FieldPercentiles, GlobalFilter, NestedToOneCreateOp, NestedToOneUpdateOp, OptionalInput, PercentileArgs, PercentileExprSpec, PercentileKeysChecked, PercentileMethod, PercentileSpec, RelationKind, RowLock, RowLockMode, SqlExpr, SqlExprKind, TableInputTypes, } from './query/types.js';
|
|
53
53
|
export { MAX_QUERY_TAG_LENGTH, RAW_QUERY_MODEL } from './query-events.js';
|
|
54
54
|
export { type ActiveSubscription, type ListenOptions, type ListenReconnectOptions, type NotificationHandler, type Subscription, validateChannel, } from './realtime.js';
|
|
55
55
|
export type { CheckMetadata, ColumnMetadata, IndexMetadata, PrismaCompatMap, PrismaModelMap, PrismaRelationMap, PrismaSchemaSource, ReferentialAction, RelationDef, SchemaMetadata, TableMetadata, } from './schema.js';
|
package/dist/mssql.js
CHANGED
|
@@ -633,6 +633,7 @@ export const mssqlDialect = {
|
|
|
633
633
|
// The limit the driver can actually send (see MSSQL_MAX_PARAMS), not 2100.
|
|
634
634
|
maxBindParameters: MSSQL_MAX_PARAMS,
|
|
635
635
|
maxInsertRows: MSSQL_MAX_INSERT_ROWS,
|
|
636
|
+
chunkBindParameters: MSSQL_MAX_PARAMS,
|
|
636
637
|
upsertConflictTarget: 'explicit',
|
|
637
638
|
setClauseOrder: 'snapshot',
|
|
638
639
|
reselectLocksRows: false,
|
|
@@ -640,6 +641,7 @@ export const mssqlDialect = {
|
|
|
640
641
|
updateExpressions: true,
|
|
641
642
|
// MERGE refuses a target row matched twice (error 8672).
|
|
642
643
|
bulkUpsertAppliesRepeatedKeys: false,
|
|
644
|
+
skipDuplicatesCountsSkipped: false,
|
|
643
645
|
readOnlyTransactions: false,
|
|
644
646
|
connectionParameters: false,
|
|
645
647
|
backendCancel: false,
|
package/dist/mysql.js
CHANGED
|
@@ -698,6 +698,7 @@ export const mysqlDialect = {
|
|
|
698
698
|
// Counted in a 16-bit field.
|
|
699
699
|
maxBindParameters: 65535,
|
|
700
700
|
maxInsertRows: Number.POSITIVE_INFINITY,
|
|
701
|
+
chunkBindParameters: 65535,
|
|
701
702
|
upsertConflictTarget: 'any-unique-key',
|
|
702
703
|
setClauseOrder: 'left-to-right',
|
|
703
704
|
reselectLocksRows: true,
|
|
@@ -705,6 +706,8 @@ export const mysqlDialect = {
|
|
|
705
706
|
updateExpressions: true,
|
|
706
707
|
// Caught by the onConflict re-read, which runs in the reselect transaction.
|
|
707
708
|
bulkUpsertAppliesRepeatedKeys: true,
|
|
709
|
+
// A skipped row is a no-op ON DUPLICATE KEY UPDATE, counted under FOUND_ROWS.
|
|
710
|
+
skipDuplicatesCountsSkipped: true,
|
|
708
711
|
readOnlyTransactions: true,
|
|
709
712
|
connectionParameters: false,
|
|
710
713
|
backendCancel: false,
|
package/dist/powdb.js
CHANGED
|
@@ -116,12 +116,14 @@ export const powdbDialect = {
|
|
|
116
116
|
structuredValueColumns: 'scalars',
|
|
117
117
|
maxBindParameters: Number.POSITIVE_INFINITY,
|
|
118
118
|
maxInsertRows: Number.POSITIVE_INFINITY,
|
|
119
|
+
chunkBindParameters: Number.POSITIVE_INFINITY,
|
|
119
120
|
upsertConflictTarget: 'explicit',
|
|
120
121
|
setClauseOrder: 'snapshot',
|
|
121
122
|
reselectLocksRows: false,
|
|
122
123
|
integerDivision: '/',
|
|
123
124
|
updateExpressions: false,
|
|
124
125
|
bulkUpsertAppliesRepeatedKeys: false,
|
|
126
|
+
skipDuplicatesCountsSkipped: false,
|
|
125
127
|
readOnlyTransactions: false,
|
|
126
128
|
connectionParameters: false,
|
|
127
129
|
backendCancel: false,
|
package/dist/powql.d.ts
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
import type { PowdbPool } from './powdb.js';
|
|
38
38
|
import type { MiddlewareFn, QueryInterfaceOptions } from './query/index.js';
|
|
39
39
|
import type { TableClient } from './query/table-client.js';
|
|
40
|
-
import type { AggregateArgs, AggregateResultOf, CountArgs, CreateArgs, CreateManyArgs, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindUniqueArgs, GroupByArgs, GroupByResult, OptionalInput, QueryResult, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs } from './query/types.js';
|
|
40
|
+
import type { AggregateArgs, AggregateResultOf, CountArgs, CreateArgs, CreateManyArgs, CreateManyResult, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindUniqueArgs, GroupByArgs, GroupByResult, OptionalInput, QueryResult, TypedWithClause, UpdateArgs, UpdateManyArgs, UpsertArgs } from './query/types.js';
|
|
41
41
|
import { type SchemaMetadata } from './schema.js';
|
|
42
42
|
/**
|
|
43
43
|
* Max values one `in` / `notIn` on a PowDB-native `datetime` column may carry.
|
|
@@ -1146,7 +1146,10 @@ export declare class PowqlInterface<T extends object = Record<string, unknown>>
|
|
|
1146
1146
|
* byte-identical PowQL.
|
|
1147
1147
|
*/
|
|
1148
1148
|
private assertUniformCreateManyRows;
|
|
1149
|
-
createMany<S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined>(args: CreateManyArgs<T, OptionalInput<T>, S, O>): Promise<FieldResult<T, S, O
|
|
1149
|
+
createMany<S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined, C extends boolean | undefined = undefined>(args: CreateManyArgs<T, OptionalInput<T>, S, O, C>): Promise<CreateManyResult<FieldResult<T, S, O>, C>>;
|
|
1150
|
+
/** `returning: false` validated: a boolean, and not combined with a projection. */
|
|
1151
|
+
private createManyCountOnly;
|
|
1152
|
+
private insertMany;
|
|
1150
1153
|
update<S extends Record<string, boolean> | undefined = undefined, O extends Record<string, boolean> | undefined = undefined>(args: UpdateArgs<T, NoRelations, S, O>): Promise<FieldResult<T, S, O>>;
|
|
1151
1154
|
updateMany(args: UpdateManyArgs<T>): Promise<{
|
|
1152
1155
|
count: number;
|
package/dist/powql.js
CHANGED
|
@@ -3857,35 +3857,56 @@ export class PowqlInterface {
|
|
|
3857
3857
|
async createMany(args) {
|
|
3858
3858
|
args = this.normalizeArgs(args);
|
|
3859
3859
|
return this.withMiddleware('createMany', args, async () => {
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3860
|
+
// `returning: false` is checked as the SQL engines check it. PowQL's
|
|
3861
|
+
// insert still returns the rows, which are counted and dropped.
|
|
3862
|
+
const countOnly = this.createManyCountOnly(args);
|
|
3863
|
+
const rows = await this.insertMany(args);
|
|
3864
|
+
return countOnly ? { count: rows.length } : rows;
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3867
|
+
/** `returning: false` validated: a boolean, and not combined with a projection. */
|
|
3868
|
+
createManyCountOnly(args) {
|
|
3869
|
+
const { returning } = args;
|
|
3870
|
+
if (returning === undefined || returning === true)
|
|
3871
|
+
return false;
|
|
3872
|
+
if (returning !== false) {
|
|
3873
|
+
throw new ValidationError(`createMany on "${this.table}": returning must be true or false, received ${typeof returning}.`);
|
|
3874
|
+
}
|
|
3875
|
+
if (args.select !== undefined || args.omit !== undefined) {
|
|
3876
|
+
throw new ValidationError(`createMany on "${this.table}": returning: false returns { count } and no rows, so it takes no ` +
|
|
3877
|
+
`\`${args.select !== undefined ? 'select' : 'omit'}\`. Drop one of them.`);
|
|
3878
|
+
}
|
|
3879
|
+
return true;
|
|
3880
|
+
}
|
|
3881
|
+
async insertMany(args) {
|
|
3882
|
+
if (args.onConflict !== undefined) {
|
|
3883
|
+
throw new UnsupportedFeatureError('createMany({ onConflict })', 'powdb', "PowQL's upsert statement takes one row. Call upsert() per row inside $transaction.");
|
|
3884
|
+
}
|
|
3885
|
+
// Validated as every engine validates it; it acts only on onConflict's
|
|
3886
|
+
// update, which is refused above.
|
|
3887
|
+
resolveSkipGlobalFilters(args.skipGlobalFilters);
|
|
3888
|
+
if (args.skipDuplicates) {
|
|
3889
|
+
// PowQL's `insert … returning` has no conflict clause, so there is no
|
|
3890
|
+
// faithful skip-duplicates form; refuse rather than silently insert.
|
|
3891
|
+
throw new UnsupportedFeatureError('createMany({ skipDuplicates: true })', 'powdb', 'PowQL insert has no ON CONFLICT DO NOTHING equivalent, filter duplicates before inserting.');
|
|
3892
|
+
}
|
|
3893
|
+
// Resolved before the write, so a bad projection writes nothing.
|
|
3894
|
+
const plan = this.writeReturnPlan(args);
|
|
3895
|
+
const supplied = args.data.map((d) => this.applyPkDefault(d));
|
|
3896
|
+
if (!supplied.length)
|
|
3897
|
+
return [];
|
|
3898
|
+
// Uniformity is judged on what the caller supplied, as the SQL engines
|
|
3899
|
+
// judge it; defaults are then filled per row.
|
|
3900
|
+
this.assertUniformCreateManyRows(supplied);
|
|
3901
|
+
const inputs = supplied.map((d) => this.applyColumnDefaults(d));
|
|
3902
|
+
const params = [];
|
|
3903
|
+
const tuples = inputs.map((d) => {
|
|
3904
|
+
const assigns = this.scalarData(d);
|
|
3905
|
+
return `{ ${assigns.map((a) => `${quotePowqlIdent(a.col.name)} := ${this.writeRef(a.value, a.col, params)}`).join(', ')} }`;
|
|
3888
3906
|
});
|
|
3907
|
+
// Multi-row insert with `returning` hands back every inserted row in one round-trip.
|
|
3908
|
+
const { rows, native } = await this.exec(`insert ${this.qt} ${tuples.join(', ')} returning`, params, args.timeout, 'createMany');
|
|
3909
|
+
return this.shape(rows, native).map((r) => this.shapeWriteRow(r, plan));
|
|
3889
3910
|
}
|
|
3890
3911
|
async update(args) {
|
|
3891
3912
|
args = this.normalizeArgs(args);
|
package/dist/prisma-compat.d.ts
CHANGED
|
@@ -137,7 +137,7 @@ export interface CompatQueryInterface {
|
|
|
137
137
|
findFirstOrThrow(args?: Record<string, unknown>): Promise<unknown>;
|
|
138
138
|
findUniqueOrThrow(args: Record<string, unknown>): Promise<unknown>;
|
|
139
139
|
create(args: Record<string, unknown>): Promise<unknown>;
|
|
140
|
-
createMany(args: Record<string, unknown>): Promise<unknown
|
|
140
|
+
createMany(args: Record<string, unknown>): Promise<unknown>;
|
|
141
141
|
update(args: Record<string, unknown>): Promise<unknown>;
|
|
142
142
|
updateMany(args: Record<string, unknown>): Promise<{
|
|
143
143
|
count: number;
|
|
@@ -156,7 +156,7 @@ export interface CompatQueryInterface {
|
|
|
156
156
|
buildFindFirstOrThrow(args?: Record<string, unknown>): DeferredQuery<unknown>;
|
|
157
157
|
buildFindUniqueOrThrow(args: Record<string, unknown>): DeferredQuery<unknown>;
|
|
158
158
|
buildCreate(args: Record<string, unknown>): DeferredQuery<unknown>;
|
|
159
|
-
buildCreateMany(args: Record<string, unknown>): DeferredQuery<unknown
|
|
159
|
+
buildCreateMany(args: Record<string, unknown>): DeferredQuery<unknown>;
|
|
160
160
|
buildUpdate(args: Record<string, unknown>): DeferredQuery<unknown>;
|
|
161
161
|
buildUpdateMany(args: Record<string, unknown>): DeferredQuery<{
|
|
162
162
|
count: number;
|
package/dist/prisma-compat.js
CHANGED
|
@@ -1864,12 +1864,12 @@ function createManyRunsOf(t) {
|
|
|
1864
1864
|
async function createManyByRun(qi, t, runs) {
|
|
1865
1865
|
let count = 0;
|
|
1866
1866
|
for (const run of runs) {
|
|
1867
|
-
const args = { data: run };
|
|
1867
|
+
const args = { data: run, returning: false };
|
|
1868
1868
|
if (t.skipDuplicates)
|
|
1869
1869
|
args.skipDuplicates = true;
|
|
1870
1870
|
if (t.timeout !== undefined)
|
|
1871
1871
|
args.timeout = t.timeout;
|
|
1872
|
-
count += (await qi.createMany(args)).
|
|
1872
|
+
count += (await qi.createMany(args)).count;
|
|
1873
1873
|
}
|
|
1874
1874
|
return { count };
|
|
1875
1875
|
}
|
|
@@ -1965,7 +1965,10 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
|
|
|
1965
1965
|
`array of them, received ${describeValue(data)}.`);
|
|
1966
1966
|
}
|
|
1967
1967
|
const rows = list.map((d) => translateWriteData(ctx, mm, applyCreateDefaults(mm, d)));
|
|
1968
|
-
|
|
1968
|
+
// Prisma's createMany resolves to { count }, which core counts
|
|
1969
|
+
// without returning the rows (a plain MySQL insert returns none, so
|
|
1970
|
+
// counting rows reported 0 there).
|
|
1971
|
+
const t = { data: rows, returning: false };
|
|
1969
1972
|
applyNativeOptions(CREATE_MANY_OPTIONS, args, t);
|
|
1970
1973
|
if (args.skipDuplicates)
|
|
1971
1974
|
t.skipDuplicates = true;
|
|
@@ -1977,11 +1980,11 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
|
|
|
1977
1980
|
// stays all-or-nothing and the count is the total actually inserted.
|
|
1978
1981
|
const runs = createManyRunsOf(t);
|
|
1979
1982
|
if (runs.length <= 1)
|
|
1980
|
-
return qi.createMany(t)
|
|
1983
|
+
return qi.createMany(t);
|
|
1981
1984
|
return runInTx((table) => createManyByRun(table(mm.table), t, runs));
|
|
1982
1985
|
}, {
|
|
1983
1986
|
build: (qi, t) => qi.buildCreateMany(t),
|
|
1984
|
-
reshape: (raw) =>
|
|
1987
|
+
reshape: (raw) => raw,
|
|
1985
1988
|
// A mixed batch is more than one statement, so the array
|
|
1986
1989
|
// $transaction([...]) form runs the whole array sequentially in a tx.
|
|
1987
1990
|
nested: (t) => createManyRunsOf(t).length > 1,
|