uql-orm 0.66.0 → 0.67.1
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/browser/querier/httpQuerier.js +1 -8
- package/dist/browser/uql-browser.min.js.map +5 -5
- package/dist/bunSql/bunSql.util.d.ts +2 -6
- package/dist/bunSql/bunSql.util.js +2 -6
- package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
- package/dist/bunSql/bunSqlQuerier.js +2 -5
- package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
- package/dist/cockroachdb/cockroachDialect.js +4 -13
- package/dist/context/context.browser.js +2 -10
- package/dist/context/context.d.ts +4 -17
- package/dist/context/context.js +4 -17
- package/dist/dialect/abstractDialect.d.ts +4 -19
- package/dist/dialect/abstractDialect.js +2 -20
- package/dist/dialect/abstractSqlDialect.d.ts +47 -212
- package/dist/dialect/abstractSqlDialect.js +68 -222
- package/dist/dialect/aliases.d.ts +2 -12
- package/dist/dialect/aliases.js +4 -12
- package/dist/dialect/hydrateColumn.d.ts +2 -6
- package/dist/dialect/hydrateColumn.js +3 -13
- package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
- package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
- package/dist/dialect/jsonSql.d.ts +6 -27
- package/dist/dialect/jsonSql.js +6 -27
- package/dist/dialect/mergeSqlDialect.d.ts +4 -22
- package/dist/dialect/mergeSqlDialect.js +4 -22
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
- package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
- package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
- package/dist/dialect/pgLikeSqlDialect.js +36 -39
- package/dist/dialect/queryContext.d.ts +4 -22
- package/dist/dialect/queryContext.js +4 -22
- package/dist/dialect/queryJoins.d.ts +3 -12
- package/dist/dialect/queryJoins.js +3 -12
- package/dist/dialect/vectorCast.d.ts +2 -12
- package/dist/dialect/vectorCast.js +3 -19
- package/dist/dialect/vectorSqlDialect.d.ts +8 -38
- package/dist/dialect/vectorSqlDialect.js +7 -38
- package/dist/entity/decorator/bag.d.ts +6 -19
- package/dist/entity/decorator/bag.js +6 -22
- package/dist/entity/decorator/entity.d.ts +2 -7
- package/dist/entity/decorator/entity.js +2 -7
- package/dist/entity/decorator/members.d.ts +7 -30
- package/dist/entity/decorator/members.js +3 -12
- package/dist/entity/metadata/definition.d.ts +2 -18
- package/dist/entity/metadata/definition.js +6 -28
- package/dist/http/handler.d.ts +2 -14
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/dist/libsql/libsqlDialect.d.ts +1 -8
- package/dist/libsql/libsqlDialect.js +1 -8
- package/dist/maria/mariaDialect.d.ts +3 -5
- package/dist/maria/mariaDialect.js +5 -5
- package/dist/maria/mariadbQuerier.js +2 -2
- package/dist/maria/mariadbQuerierPool.js +1 -6
- package/dist/migrate/builder/migrationBuilder.js +3 -19
- package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
- package/dist/migrate/builder/splitSqlStatements.js +2 -22
- package/dist/migrate/builder/types.d.ts +2 -15
- package/dist/migrate/cli-config.js +2 -11
- package/dist/migrate/cli.js +2 -7
- package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
- package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
- package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
- package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
- package/dist/migrate/ddl/indexDdl.d.ts +2 -5
- package/dist/migrate/ddl/indexDdl.js +2 -5
- package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
- package/dist/migrate/ddl/pgIndexDdl.js +3 -13
- package/dist/migrate/generator/definitionToNode.d.ts +2 -9
- package/dist/migrate/generator/definitionToNode.js +3 -17
- package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
- package/dist/migrate/generator/indexNodeToSchema.js +2 -3
- package/dist/migrate/generator/mongoCommand.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
- package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
- package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
- package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
- package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
- package/dist/migrate/introspection/mongoIntrospector.js +48 -46
- package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
- package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
- package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
- package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
- package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
- package/dist/migrate/introspection/postgresIntrospector.js +68 -59
- package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
- package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
- package/dist/migrate/migrator.d.ts +9 -53
- package/dist/migrate/migrator.js +32 -65
- package/dist/migrate/schemaGenerator.d.ts +16 -66
- package/dist/migrate/schemaGenerator.js +21 -74
- package/dist/mongo/mongoDialect.d.ts +21 -53
- package/dist/mongo/mongoDialect.js +25 -70
- package/dist/mongo/mongodbQuerier.d.ts +5 -8
- package/dist/mongo/mongodbQuerier.js +31 -65
- package/dist/mssql/mssqlDialect.d.ts +8 -34
- package/dist/mssql/mssqlDialect.js +37 -51
- package/dist/mssql/mssqlQuerier.d.ts +37 -4
- package/dist/mssql/mssqlQuerier.js +2 -2
- package/dist/mssql/mssqlWireTypes.d.ts +2 -14
- package/dist/mssql/mssqlWireTypes.js +2 -14
- package/dist/nestjs/uqlModule.js +2 -7
- package/dist/pglite/pgliteQuerier.d.ts +1 -9
- package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
- package/dist/pglite/pgliteQuerierPool.js +3 -18
- package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
- package/dist/postgres/abstractPgQuerierPool.js +1 -8
- package/dist/postgres/pgNumericTypes.d.ts +3 -26
- package/dist/postgres/pgNumericTypes.js +3 -26
- package/dist/postgres/postgresDialect.d.ts +4 -10
- package/dist/postgres/postgresDialect.js +4 -10
- package/dist/querier/abstractQuerier.d.ts +35 -103
- package/dist/querier/abstractQuerier.js +105 -201
- package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
- package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
- package/dist/querier/abstractSqlQuerier.d.ts +15 -36
- package/dist/querier/abstractSqlQuerier.js +49 -131
- package/dist/schema/canonicalType.d.ts +3 -21
- package/dist/schema/canonicalType.js +22 -67
- package/dist/schema/dependencyGraph.d.ts +2 -8
- package/dist/schema/dependencyGraph.js +2 -32
- package/dist/schema/index.d.ts +1 -25
- package/dist/schema/index.js +0 -26
- package/dist/schema/indexColumns.d.ts +1 -8
- package/dist/schema/indexColumns.js +1 -8
- package/dist/schema/indexDifferences.d.ts +7 -40
- package/dist/schema/indexDifferences.js +6 -31
- package/dist/schema/schemaAST.d.ts +8 -175
- package/dist/schema/schemaAST.js +13 -365
- package/dist/schema/schemaASTBuilder.d.ts +2 -24
- package/dist/schema/schemaASTBuilder.js +2 -30
- package/dist/schema/schemaASTDiffer.d.ts +6 -46
- package/dist/schema/schemaASTDiffer.js +8 -56
- package/dist/schema/types.d.ts +5 -61
- package/dist/schema/types.js +3 -6
- package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
- package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
- package/dist/sqlite/localSqliteQuerierPool.js +1 -7
- package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
- package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
- package/dist/sqlite/sqliteDialect.d.ts +5 -20
- package/dist/sqlite/sqliteDialect.js +29 -35
- package/dist/turso/tursoDialect.d.ts +4 -6
- package/dist/turso/tursoDialect.js +4 -6
- package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
- package/dist/turso/tursoLocalQuerierPool.js +1 -7
- package/dist/turso/tursoQuerierPool.d.ts +2 -6
- package/dist/turso/tursoQuerierPool.js +2 -6
- package/dist/turso/tursoSessionQuerier.d.ts +1 -7
- package/dist/turso/tursoSessionQuerier.js +1 -7
- package/dist/type/dialect.d.ts +42 -94
- package/dist/type/dialect.js +3 -13
- package/dist/type/entity.d.ts +163 -534
- package/dist/type/entity.js +26 -9
- package/dist/type/logger.d.ts +2 -14
- package/dist/type/migration.d.ts +9 -38
- package/dist/type/querier.d.ts +9 -28
- package/dist/type/querierPool.d.ts +4 -26
- package/dist/type/query.d.ts +19 -73
- package/dist/type/query.js +2 -7
- package/dist/type/queryAggregate.d.ts +18 -98
- package/dist/type/queryRaw.d.ts +1 -8
- package/dist/type/queryRaw.js +1 -8
- package/dist/type/queryWhere.d.ts +13 -61
- package/dist/type/universalQuerier.d.ts +18 -105
- package/dist/type/utility.d.ts +12 -24
- package/dist/type/vector.d.ts +8 -38
- package/dist/type/vector.js +1 -1
- package/dist/type/wire.d.ts +2 -5
- package/dist/util/dialect.util.d.ts +9 -27
- package/dist/util/dialect.util.js +10 -27
- package/dist/util/field.util.d.ts +2 -31
- package/dist/util/field.util.js +3 -43
- package/dist/util/fieldOption.util.d.ts +7 -15
- package/dist/util/fieldOption.util.js +1 -1
- package/dist/util/filters.util.d.ts +2 -5
- package/dist/util/filters.util.js +2 -5
- package/dist/util/logger.d.ts +2 -6
- package/dist/util/logger.js +2 -6
- package/dist/util/object.util.d.ts +2 -6
- package/dist/util/object.util.js +1 -5
- package/dist/util/raw.d.ts +3 -23
- package/dist/util/relationQuery.util.d.ts +3 -14
- package/dist/util/relationQuery.util.js +3 -14
- package/dist/util/rowKey.util.d.ts +2 -10
- package/dist/util/rowKey.util.js +2 -10
- package/dist/util/sql.util.d.ts +6 -37
- package/dist/util/sql.util.js +13 -73
- package/dist/util/sqlLiteral.d.ts +2 -13
- package/dist/util/sqlLiteral.js +8 -13
- package/dist/util/string.util.js +0 -2
- package/package.json +4 -4
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import { assertSoleId, getMeta, idOf, namesKey, relationOf
|
|
2
|
-
import { childrenOf, clone, entityName, fillOnFields, filterPersistableRelationKeys, forEachRequestedRelation, getKeys, getRelationRequestSummary, idOnlyQuery, isScalarId, LoggerWrapper, parentJoins, queryLoggerFor, parseRelationAtKey, parseRelationQueryValue, rowKey, runHooks, someKey, targetKeyColumns, whereIds, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
1
|
+
import { assertSoleId, getMeta, idOf, namesKey, relationOf } from '../entity/index.js';
|
|
2
|
+
import { cascadesOnDelete, childrenOf, clone, entityName, fillOnFields, filterFieldKeys, filterPersistableRelationKeys, forEachRequestedRelation, getKeys, getRelationRequestSummary, idOnlyQuery, isPagedQuery, isScalarId, LoggerWrapper, parentJoins, queryLoggerFor, parseRelationAtKey, parseRelationQueryValue, rowKey, runHooks, someKey, targetKeyColumns, whereIds, withoutSoftDeleteFilter, } from '../util/index.js';
|
|
3
3
|
import { enrichError } from './queryError.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* addresses the whole table. An entity declares its id optional, which puts `undefined` inside
|
|
8
|
-
* `IdValue<E>`, and the HTTP layer reaches these methods with parsed JSON regardless, so the guard
|
|
9
|
-
* belongs at runtime.
|
|
10
|
-
*
|
|
11
|
-
* Its callers are all `async` so this surfaces as a rejection on every one of them: a guard that
|
|
12
|
-
* threw synchronously from some and rejected from others would escape a caller's `.catch()`.
|
|
5
|
+
* Refuses a nullish id, which would reduce to no filter at all, and a composite id missing a column,
|
|
6
|
+
* which would address every row agreeing on the rest. Callers are `async`, so it always rejects.
|
|
13
7
|
*/
|
|
14
8
|
function assertIdValue(entity, id) {
|
|
15
9
|
if (id === undefined || id === null) {
|
|
@@ -29,13 +23,7 @@ function assertIdValue(entity, id) {
|
|
|
29
23
|
throw new TypeError(`'${entity.name}' is addressed by an object carrying every key of its primary key (${ids.join(', ')}); missing ${missing.join(', ')}.`);
|
|
30
24
|
}
|
|
31
25
|
}
|
|
32
|
-
/**
|
|
33
|
-
* The one column a write path matches a parent's key against.
|
|
34
|
-
*
|
|
35
|
-
* Every caller reaches its parents through a sole id - `soleIdOf` refused a composite before any of
|
|
36
|
-
* them - so the parent contributes exactly one column here, whether the relation goes through a
|
|
37
|
-
* junction or straight to the child.
|
|
38
|
-
*/
|
|
26
|
+
/** The column a write matches a parent's sole key against, on the junction or the child. */
|
|
39
27
|
function soleParentColumn(relOpts) {
|
|
40
28
|
return parentJoins(relOpts, 1)[0].joined;
|
|
41
29
|
}
|
|
@@ -100,12 +88,7 @@ export class AbstractQuerier {
|
|
|
100
88
|
}
|
|
101
89
|
});
|
|
102
90
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Resolves `[entity, query, opts]` for the dual call pattern: `(entity, q, opts)` (entity argument)
|
|
105
|
-
* vs `(query, opts)` (entity via the query's `$entity` field). Generic in the query `Q` because it
|
|
106
|
-
* only ever reads `$entity`: pinning it to one statement's shape made every caller launder its own
|
|
107
|
-
* through a cast, which is how a read query's `$sort` used to reach a write's.
|
|
108
|
-
*/
|
|
91
|
+
/** `[entity, query, opts]` from either call form, `(entity, q, opts)` or `({ $entity, ...q }, opts)`. */
|
|
109
92
|
resolveEntityQuery(entityOrQuery, maybeQueryOrOpts, maybeOpts) {
|
|
110
93
|
if (typeof entityOrQuery === 'function' && entityOrQuery.prototype) {
|
|
111
94
|
return [entityOrQuery, maybeQueryOrOpts ?? {}, maybeOpts];
|
|
@@ -163,16 +146,11 @@ export class AbstractQuerier {
|
|
|
163
146
|
}
|
|
164
147
|
async count(entityOrQuery, maybeQueryOrOpts, maybeOpts) {
|
|
165
148
|
const [entity, q, opts] = this.resolveEntityQuery(entityOrQuery, maybeQueryOrOpts, maybeOpts);
|
|
166
|
-
if (q.$skip !== undefined || q.$limit !== undefined) {
|
|
167
|
-
const meta = getMeta(entity);
|
|
168
|
-
const rows = await this.internalFindMany(entity, idOnlyQuery(meta, { $where: q.$where, $skip: q.$skip, $limit: q.$limit }), opts);
|
|
169
|
-
return rows.length;
|
|
170
|
-
}
|
|
171
149
|
return this.internalCount(entity, q, opts);
|
|
172
150
|
}
|
|
173
151
|
async exists(entityOrQuery, maybeQueryOrOpts, maybeOpts) {
|
|
174
152
|
const [entity, q, opts] = this.resolveEntityQuery(entityOrQuery, maybeQueryOrOpts, maybeOpts);
|
|
175
|
-
return (await this.
|
|
153
|
+
return (await this.internalCount(entity, { $where: q.$where, $limit: 1 }, opts)) > 0;
|
|
176
154
|
}
|
|
177
155
|
/**
|
|
178
156
|
* Run an aggregate query.
|
|
@@ -203,12 +181,41 @@ export class AbstractQuerier {
|
|
|
203
181
|
assertIdValue(entity, id);
|
|
204
182
|
return this.updateMany(entity, { $where: whereIds(getMeta(entity), id) }, payload, opts);
|
|
205
183
|
}
|
|
184
|
+
/** Settles the rows first where the update cascades, so a payload changing what `$where` reads still names them. */
|
|
206
185
|
async updateMany(entity, q, payload, opts) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
186
|
+
const meta = getMeta(entity);
|
|
187
|
+
return this.hooked(entity, 'Update', [payload], async ([row]) => {
|
|
188
|
+
fillOnFields(meta, [row], 'onUpdate');
|
|
189
|
+
const relKeys = filterPersistableRelationKeys(meta, row, 'persist');
|
|
190
|
+
if (!relKeys.length && !this.settlesWrite(entity, q)) {
|
|
191
|
+
return this.updateColumns(entity, q, row, opts, 0);
|
|
192
|
+
}
|
|
193
|
+
const ids = await this.settleIds(entity, q, opts);
|
|
194
|
+
if (!ids.length) {
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
const changes = await this.updateColumns(entity, { $where: whereIds(meta, ids) }, row, opts, ids.length);
|
|
198
|
+
for (const relKey of relKeys) {
|
|
199
|
+
await this.saveRelation(entity, relKey, ids.map((id) => ({ id, value: row[relKey] })), true);
|
|
200
|
+
}
|
|
201
|
+
return changes;
|
|
210
202
|
});
|
|
211
203
|
}
|
|
204
|
+
/** The UPDATE, skipped where the payload writes no column, reporting `unwritten` instead. */
|
|
205
|
+
async updateColumns(entity, q, row, opts, unwritten) {
|
|
206
|
+
const writes = filterFieldKeys(getMeta(entity), row, 'onUpdate').length > 0;
|
|
207
|
+
return writes ? this.internalUpdateMany(entity, q, row, opts) : unwritten;
|
|
208
|
+
}
|
|
209
|
+
/** Whether a write has to name the rows `q` matches by their ids: no engine pages or orders an update or delete. */
|
|
210
|
+
settlesWrite(_entity, q) {
|
|
211
|
+
return isPagedQuery(q);
|
|
212
|
+
}
|
|
213
|
+
/** The ids `q` matches, in its own order and page. */
|
|
214
|
+
async settleIds(entity, q, opts) {
|
|
215
|
+
const meta = getMeta(entity);
|
|
216
|
+
const rows = await this.internalFindMany(entity, idOnlyQuery(meta, q), opts);
|
|
217
|
+
return rows.map((row) => idOf(meta, row));
|
|
218
|
+
}
|
|
212
219
|
async restoreOneById(entity, id) {
|
|
213
220
|
assertIdValue(entity, id);
|
|
214
221
|
return this.restoreMany(entity, { $where: whereIds(getMeta(entity), id) });
|
|
@@ -223,12 +230,7 @@ export class AbstractQuerier {
|
|
|
223
230
|
filters: { softDelete: false },
|
|
224
231
|
});
|
|
225
232
|
}
|
|
226
|
-
/**
|
|
227
|
-
* `beforeUpsert`/`afterUpsert` rather than the insert's or the update's pair: the database decides
|
|
228
|
-
* which branch each row takes as the statement runs, so neither of those could be fired honestly -
|
|
229
|
-
* but the upsert itself is a fact known before and after, and a row written with no hook at all
|
|
230
|
-
* was how an `@Id({ onInsert })` or an audit trail silently skipped this path.
|
|
231
|
-
*/
|
|
233
|
+
/** Fires `beforeUpsert`/`afterUpsert`: which branch a row takes is the database's to decide, so neither the insert's nor the update's pair fits. */
|
|
232
234
|
async upsertOne(entity, conflictPaths, payload) {
|
|
233
235
|
const meta = getMeta(entity);
|
|
234
236
|
return this.hooked(entity, 'Upsert', [payload], async (rows) => {
|
|
@@ -252,40 +254,29 @@ export class AbstractQuerier {
|
|
|
252
254
|
}
|
|
253
255
|
async deleteMany(entityOrQuery, qOrOpts, maybeOpts) {
|
|
254
256
|
const [entity, q, opts] = this.resolveEntityQuery(entityOrQuery, qOrOpts, maybeOpts);
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
+
const meta = getMeta(entity);
|
|
258
|
+
const cascades = cascadesOnDelete(meta);
|
|
259
|
+
const watched = this.hasHook(entity, 'beforeDelete') || this.hasHook(entity, 'afterDelete');
|
|
260
|
+
if (!watched && !cascades && !this.settlesWrite(entity, q)) {
|
|
261
|
+
return this.internalDeleteMany(entity, q, opts);
|
|
262
|
+
}
|
|
263
|
+
// A hard delete takes already-soft-deleted rows too, so reading them back has to see them.
|
|
264
|
+
const readOpts = opts?.hardDelete ? { ...opts, filters: withoutSoftDeleteFilter(opts.filters) } : opts;
|
|
265
|
+
// A hook receives the rows themselves; the ids read off them name the same rows a second read might not.
|
|
266
|
+
const doomed = watched ? await this.internalFindMany(entity, q, readOpts) : [];
|
|
267
|
+
const ids = watched ? doomed.map((row) => idOf(meta, row)) : await this.settleIds(entity, q, readOpts);
|
|
268
|
+
if (!ids.length) {
|
|
257
269
|
return 0;
|
|
258
270
|
}
|
|
259
|
-
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (doomed) {
|
|
264
|
-
const meta = getMeta(entity);
|
|
265
|
-
const ids = doomed.map((it) => idOf(meta, it));
|
|
266
|
-
target = { $where: whereIds(meta, ids) };
|
|
271
|
+
await this.emitHook(entity, 'beforeDelete', doomed);
|
|
272
|
+
// Children first: they hold the foreign key, which a schema without `ON DELETE CASCADE` enforces.
|
|
273
|
+
if (cascades) {
|
|
274
|
+
await this.deleteRelations(entity, ids, opts);
|
|
267
275
|
}
|
|
268
|
-
await this.
|
|
269
|
-
|
|
270
|
-
await this.emitHook(entity, 'afterDelete', doomed ?? []);
|
|
276
|
+
const changes = await this.internalDeleteMany(entity, { $where: whereIds(meta, ids) }, opts);
|
|
277
|
+
await this.emitHook(entity, 'afterDelete', doomed);
|
|
271
278
|
return changes;
|
|
272
279
|
}
|
|
273
|
-
/**
|
|
274
|
-
* The rows a delete is about to take, loaded only when a hook or listener is there to receive
|
|
275
|
-
* them: the round trip is pure overhead for the (common) delete nobody is watching, and
|
|
276
|
-
* `internalDeleteMany` has its own fast path that never reads the rows at all.
|
|
277
|
-
*
|
|
278
|
-
* `undefined` means nobody was watching, which is not the same as the empty array meaning nothing
|
|
279
|
-
* matched - the caller deletes by `q` for the first and skips the statement entirely for the second.
|
|
280
|
-
*/
|
|
281
|
-
async findDoomed(entity, q, opts) {
|
|
282
|
-
if (!this.hasHook(entity, 'beforeDelete') && !this.hasHook(entity, 'afterDelete')) {
|
|
283
|
-
return undefined;
|
|
284
|
-
}
|
|
285
|
-
// A hard delete takes already-soft-deleted rows too, so reading them back has to see them.
|
|
286
|
-
const findOpts = opts?.hardDelete ? { ...opts, filters: withoutSoftDeleteFilter(opts.filters) } : opts;
|
|
287
|
-
return this.internalFindMany(entity, q, findOpts);
|
|
288
|
-
}
|
|
289
280
|
async saveOne(entity, payload) {
|
|
290
281
|
const [id] = await this.saveMany(entity, [payload]);
|
|
291
282
|
return id;
|
|
@@ -339,39 +330,18 @@ export class AbstractQuerier {
|
|
|
339
330
|
await (toInsert.length && toUpsert.length ? this.transaction(write) : write());
|
|
340
331
|
return ids;
|
|
341
332
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
const entries = payload.reduce((acc, it) => {
|
|
345
|
-
const relKeys = filterPersistableRelationKeys(meta, it, 'persist');
|
|
346
|
-
if (relKeys.length > 0)
|
|
347
|
-
acc.push({ it, relKeys });
|
|
348
|
-
return acc;
|
|
349
|
-
}, []);
|
|
350
|
-
if (!entries.length)
|
|
351
|
-
return;
|
|
352
|
-
const idKey = soleIdOf(meta, 'saving a relation');
|
|
353
|
-
await Promise.all(entries.map(({ it, relKeys }) => Promise.all(relKeys.map((relKey) => this.saveRelation(entity, [it[idKey]], it[relKey], relKey)))));
|
|
354
|
-
}
|
|
355
|
-
async updateRelations(entity, q, payload, opts) {
|
|
333
|
+
/** Writes each inserted row's relations, one set of statements per relation whatever the number of rows. */
|
|
334
|
+
async insertRelations(entity, rows) {
|
|
356
335
|
const meta = getMeta(entity);
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
const ids = founds.map((found) => found[idKey]);
|
|
364
|
-
if (!ids.length) {
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
for (const relKey of relKeys) {
|
|
368
|
-
await this.saveRelation(entity, ids, payload[relKey], relKey, true);
|
|
336
|
+
const [idKey] = meta.ids;
|
|
337
|
+
for (const relKey of filterPersistableRelationKeys(meta, meta.relations, 'persist')) {
|
|
338
|
+
const writes = rows.flatMap((row) => (row[relKey] == null ? [] : [{ id: row[idKey], value: row[relKey] }]));
|
|
339
|
+
if (writes.length) {
|
|
340
|
+
await this.saveRelation(entity, relKey, writes, false);
|
|
341
|
+
}
|
|
369
342
|
}
|
|
370
343
|
}
|
|
371
|
-
/**
|
|
372
|
-
* `EntityId` because a settled set names composite rows as objects, which is also what the parent's
|
|
373
|
-
* own delete takes - and what {@link childrenOf} reads each child's foreign key columns out of.
|
|
374
|
-
*/
|
|
344
|
+
/** `EntityId` because a settled composite row is an object, which {@link childrenOf} reads each foreign key column out of. */
|
|
375
345
|
async deleteRelations(entity, ids, opts) {
|
|
376
346
|
const meta = getMeta(entity);
|
|
377
347
|
const relKeys = filterPersistableRelationKeys(meta, meta.relations, 'delete');
|
|
@@ -385,101 +355,53 @@ export class AbstractQuerier {
|
|
|
385
355
|
}
|
|
386
356
|
}
|
|
387
357
|
/**
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* row wherever the cardinality allows it.
|
|
358
|
+
* Writes each parent's value into one relation. The parent owns what it points at: an update replaces
|
|
359
|
+
* it, and a `null` only clears it.
|
|
391
360
|
*/
|
|
392
|
-
async saveRelation(entity,
|
|
361
|
+
async saveRelation(entity, relKey, writes, isUpdate) {
|
|
393
362
|
const meta = getMeta(entity);
|
|
394
|
-
|
|
395
|
-
// Here rather than only in the callers below: writing the parent's key into a child is one column
|
|
396
|
-
// per key, so a composite takes a statement per parent. `soleParentColumn` and the sole
|
|
397
|
-
// `targetKeyColumns` under it read the *first* pair, which is a real column of a wrong pairing
|
|
398
|
-
// unless this has run - and this method is `protected`, so a caller can arrive without them.
|
|
363
|
+
// Writing the parent's key into a child is one column per key, and the helpers below read the first pair.
|
|
399
364
|
assertSoleId(meta, 'saving a relation');
|
|
365
|
+
const relOpts = relationOf(meta, relKey);
|
|
400
366
|
const relEntity = relOpts.entity();
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
case 'mm':
|
|
404
|
-
return this.saveToMany(relOpts, relEntity, ids, relValue, isUpdate);
|
|
405
|
-
case '11':
|
|
406
|
-
return this.saveOneToOne(relEntity, relOpts, ids, relValue, isUpdate);
|
|
407
|
-
case 'm1':
|
|
408
|
-
if (relValue)
|
|
409
|
-
return this.saveManyToOne(entity, relEntity, relOpts, ids, relValue);
|
|
367
|
+
if (relOpts.cardinality === 'm1') {
|
|
368
|
+
return this.saveManyToOne(entity, relEntity, relOpts.references[0].local, writes);
|
|
410
369
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
if (relPayload) {
|
|
422
|
-
// Saved per parent on purpose: each one owns its copies of the children, and saving them once
|
|
423
|
-
// would link every parent to a single shared row instead.
|
|
424
|
-
for (const id of ids) {
|
|
425
|
-
const savedIds = await this.saveMany(relEntity, relPayload);
|
|
426
|
-
// A link needs the target's id, and a driver that cannot report one (a MySQL batch mixing
|
|
427
|
-
// supplied and generated keys) would otherwise write a row pointing at `undefined`.
|
|
428
|
-
if (savedIds.some((relId) => relId === undefined)) {
|
|
429
|
-
throw new TypeError(`'${relEntity.name}' rows saved through '${throughEntity.name}' reported no id, so they cannot be linked. ` +
|
|
430
|
-
'Insert them with their own ids, or save the relation in its own statement.');
|
|
431
|
-
}
|
|
432
|
-
await this.insertMany(throughEntity, savedIds.map((relId) => ({ [localField]: id, [targetColumn]: relId })));
|
|
433
|
-
}
|
|
434
|
-
}
|
|
370
|
+
const holder = relOpts.through ? relOpts.through() : relEntity;
|
|
371
|
+
const parentColumn = soleParentColumn(relOpts);
|
|
372
|
+
if (isUpdate) {
|
|
373
|
+
const ids = writes.map(({ id }) => id);
|
|
374
|
+
await this.deleteMany(holder, { $where: { [parentColumn]: ids } });
|
|
375
|
+
}
|
|
376
|
+
// Each parent gets its own copies, so a row listed for two parents is written twice.
|
|
377
|
+
const children = writes.flatMap(({ id, value }) => [value ?? []].flat().map((row) => ({ id, row })));
|
|
378
|
+
if (!children.length) {
|
|
435
379
|
return;
|
|
436
380
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
381
|
+
if (!relOpts.through) {
|
|
382
|
+
await this.saveMany(relEntity, children.map(({ id, row }) => ({ ...row, [parentColumn]: id })));
|
|
383
|
+
return;
|
|
440
384
|
}
|
|
441
|
-
|
|
442
|
-
|
|
385
|
+
const savedIds = await this.saveMany(relEntity, children.map(({ row }) => row));
|
|
386
|
+
// A link needs the target's id, which a MySQL batch mixing supplied and generated keys cannot report.
|
|
387
|
+
if (savedIds.includes(undefined)) {
|
|
388
|
+
throw new TypeError(`'${relEntity.name}' rows saved through '${holder.name}' reported no id, so they cannot be linked. ` +
|
|
389
|
+
'Insert them with their own ids, or save the relation in its own statement.');
|
|
443
390
|
}
|
|
391
|
+
const [targetColumn] = targetKeyColumns(relOpts, 1);
|
|
392
|
+
await this.insertMany(holder, children.map(({ id }, index) => ({ [parentColumn]: id, [targetColumn]: savedIds[index] })));
|
|
444
393
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
await this.
|
|
451
|
-
if (relPayload === null) {
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
await this.saveMany(relEntity, ids.map((id) => ({ ...relPayload, [foreignField]: id })));
|
|
456
|
-
}
|
|
457
|
-
async saveManyToOne(entity, relEntity, relOpts, ids, relPayload) {
|
|
458
|
-
// Not `soleParentColumn`: a many-to-one points the other way, so this is the *parent's* own column
|
|
459
|
-
// holding the child's id - the one place `references[0].local` does not name a key of the parent.
|
|
460
|
-
const localField = relOpts.references[0].local;
|
|
461
|
-
// Per parent: each gets its own reference row, so each `SET` carries a different value.
|
|
462
|
-
for (const id of ids) {
|
|
463
|
-
const referenceId = await this.insertOne(relEntity, relPayload);
|
|
464
|
-
await this.updateOneById(entity, id, { [localField]: referenceId });
|
|
394
|
+
/** Each parent gets its own referenced row, and its own column pointing at it. */
|
|
395
|
+
async saveManyToOne(entity, relEntity, localColumn, writes) {
|
|
396
|
+
const pointing = writes.filter(({ value }) => value);
|
|
397
|
+
const referenceIds = await this.insertMany(relEntity, pointing.map(({ value }) => value));
|
|
398
|
+
for (const [index, { id }] of pointing.entries()) {
|
|
399
|
+
await this.updateOneById(entity, id, { [localColumn]: referenceIds[index] });
|
|
465
400
|
}
|
|
466
401
|
}
|
|
467
402
|
/**
|
|
468
|
-
* Runs `callback` in a transaction
|
|
469
|
-
*
|
|
470
|
-
* The single place that sequence is written; everything else delegates here, because both subtleties
|
|
471
|
-
* below were got wrong by code that hand-rolled it:
|
|
472
|
-
*
|
|
473
|
-
* - `beginTransaction` connects before it begins, so a refused connection lands in the catch with no
|
|
474
|
-
* transaction open. `rollbackTransaction` is a no-op there rather than an error, which is why a
|
|
475
|
-
* wrong password no longer surfaces as a transaction-state error.
|
|
476
|
-
* - A rollback that fails too is a consequence of the original failure, not news, so it must not
|
|
477
|
-
* replace it either.
|
|
478
|
-
*
|
|
479
|
-
* The connection is **not** released here: whoever took it from the pool gives it back, through
|
|
480
|
-
* {@link QuerierPool.transaction}, {@link QuerierPool.withQuerier} or `await using`. Releasing a
|
|
481
|
-
* connection this method never acquired is what forced every caller to know whether it still owned
|
|
482
|
-
* one afterwards.
|
|
403
|
+
* Runs `callback` in a transaction, joining one already open. A rollback that fails is logged, never
|
|
404
|
+
* thrown over the original error, and the connection stays with whoever acquired it.
|
|
483
405
|
*/
|
|
484
406
|
async transaction(callback, opts) {
|
|
485
407
|
if (this.hasOpenTransaction) {
|
|
@@ -578,27 +500,13 @@ export class AbstractQuerier {
|
|
|
578
500
|
}
|
|
579
501
|
await runHooks(entity, event, payloads, { querier: this });
|
|
580
502
|
}
|
|
581
|
-
/**
|
|
582
|
-
* Runs `task` after everything already queued on this querier, one at a time.
|
|
583
|
-
*
|
|
584
|
-
* @remarks Not re-entrant: only one task runs at a time, so a serialized method awaited from inside
|
|
585
|
-
* another one would wait for a task queued behind itself. Callers below keep their `serialize` calls
|
|
586
|
-
* sequential rather than nested.
|
|
587
|
-
*/
|
|
503
|
+
/** Runs `task` after everything already queued, one at a time. Not re-entrant: never nest `serialize` calls. */
|
|
588
504
|
serialize(task) {
|
|
589
505
|
const res = this.taskQueue.then(task);
|
|
590
506
|
this.taskQueue = res.catch(() => { });
|
|
591
507
|
return res;
|
|
592
508
|
}
|
|
593
|
-
/**
|
|
594
|
-
* Runs `task`, logs `query` with how long it took, and tags any error it throws with that query.
|
|
595
|
-
*
|
|
596
|
-
* A method rather than the `@Log()` decorator it replaces. A standard-spec method decorator works by
|
|
597
|
-
* returning a replacement function, and a replacement cannot carry the original's type parameters, so
|
|
598
|
-
* decorating `internalFindMany<E extends Document>` made its signature unresolvable. Most of the query
|
|
599
|
-
* surface is generic like that, and wrapping at the call site costs one line while keeping the
|
|
600
|
-
* signature intact.
|
|
601
|
-
*/
|
|
509
|
+
/** Runs `task`, logs `query` with its duration, and tags a failure with it: a method, since a decorator would lose the generics. */
|
|
602
510
|
async timed(query, values, task) {
|
|
603
511
|
const startTime = performance.now();
|
|
604
512
|
try {
|
|
@@ -612,12 +520,8 @@ export class AbstractQuerier {
|
|
|
612
520
|
}
|
|
613
521
|
}
|
|
614
522
|
/**
|
|
615
|
-
* Rolls back an unfinished transaction, then hands the connection back
|
|
616
|
-
*
|
|
617
|
-
* @remarks Refusing to release was the opposite of safe: the throw came *before* the connection went
|
|
618
|
-
* back, so it destroyed the error that got here and cost the pool a connection with a live `BEGIN` on
|
|
619
|
-
* it. It is also the only option `await using` can reach, which calls `Symbol.asyncDispose` with no
|
|
620
|
-
* arguments and discards what it returns.
|
|
523
|
+
* Rolls back an unfinished transaction, then hands the connection back, discarding it if the rollback
|
|
524
|
+
* failed. Never throws first, since `await using` has no other way to release.
|
|
621
525
|
*/
|
|
622
526
|
async release() {
|
|
623
527
|
let discard = false;
|
|
@@ -2,23 +2,9 @@ import type { AbstractSqlDialect } from '../dialect/index.js';
|
|
|
2
2
|
import type { SqlQuerier } from '../type/index.js';
|
|
3
3
|
import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* The handle is shared, but each acquisition gets its own querier, so transaction state stays per unit
|
|
9
|
-
* of work. On a single connection that state is not *isolated*, which is the one way these differ from
|
|
10
|
-
* a real pool: two queriers cannot hold independent transactions, and a unit of work that needs one needs
|
|
11
|
-
* its own pool and therefore its own database. libSQL's client opens a session per transaction instead.
|
|
12
|
-
*
|
|
13
|
-
* What a second `BEGIN` then does is the engine's, not this class's: SQLite and the embedded Turso
|
|
14
|
-
* engine both refuse it ("cannot start a transaction within a transaction"), while PGlite accepts it
|
|
15
|
-
* into the transaction already open - see {@link PgliteQuerierPool}, which is why that one is worth
|
|
16
|
-
* saying out loud.
|
|
17
|
-
*
|
|
18
|
-
* Subclasses supply only how to open the handle and how to wrap it.
|
|
19
|
-
*
|
|
20
|
-
* @remarks Deliberately not re-exported from `querier/index.ts`, which the root entry point re-exports:
|
|
21
|
-
* only the driver entries that open a single handle need this, and each imports it by path.
|
|
5
|
+
* A pool over one handle kept for its lifetime: a local SQLite file, the embedded Turso engine, PGlite, or a
|
|
6
|
+
* libSQL client. Each acquisition gets its own querier, but on one connection two cannot hold separate
|
|
7
|
+
* transactions: a unit of work needing its own needs its own pool. Imported by path, not from `querier/index.ts`.
|
|
22
8
|
*/
|
|
23
9
|
export declare abstract class AbstractSharedHandleQuerierPool<DB extends {
|
|
24
10
|
close(): unknown;
|
|
@@ -1,22 +1,8 @@
|
|
|
1
1
|
import { AbstractSqlQuerierPool } from './abstractSqlQuerierPool.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* The handle is shared, but each acquisition gets its own querier, so transaction state stays per unit
|
|
7
|
-
* of work. On a single connection that state is not *isolated*, which is the one way these differ from
|
|
8
|
-
* a real pool: two queriers cannot hold independent transactions, and a unit of work that needs one needs
|
|
9
|
-
* its own pool and therefore its own database. libSQL's client opens a session per transaction instead.
|
|
10
|
-
*
|
|
11
|
-
* What a second `BEGIN` then does is the engine's, not this class's: SQLite and the embedded Turso
|
|
12
|
-
* engine both refuse it ("cannot start a transaction within a transaction"), while PGlite accepts it
|
|
13
|
-
* into the transaction already open - see {@link PgliteQuerierPool}, which is why that one is worth
|
|
14
|
-
* saying out loud.
|
|
15
|
-
*
|
|
16
|
-
* Subclasses supply only how to open the handle and how to wrap it.
|
|
17
|
-
*
|
|
18
|
-
* @remarks Deliberately not re-exported from `querier/index.ts`, which the root entry point re-exports:
|
|
19
|
-
* only the driver entries that open a single handle need this, and each imports it by path.
|
|
3
|
+
* A pool over one handle kept for its lifetime: a local SQLite file, the embedded Turso engine, PGlite, or a
|
|
4
|
+
* libSQL client. Each acquisition gets its own querier, but on one connection two cannot hold separate
|
|
5
|
+
* transactions: a unit of work needing its own needs its own pool. Imported by path, not from `querier/index.ts`.
|
|
20
6
|
*/
|
|
21
7
|
export class AbstractSharedHandleQuerierPool extends AbstractSqlQuerierPool {
|
|
22
8
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AbstractSqlDialect } from '../dialect/index.js';
|
|
2
|
-
import type { EntityData, ExtraOptions, Query, QueryAggMap, QueryAggregate, QueryAggregateResult, QueryConflictPaths,
|
|
2
|
+
import type { EntityData, ExtraOptions, Query, QueryAggMap, QueryAggregate, QueryAggregateResult, QueryConflictPaths, QueryPage, QueryGroupMap, QueryOptions, QuerySearch, QueryUpdateResult, SqlQuerier, TransactionOptions, Type, UpdatePayload } from '../type/index.js';
|
|
3
3
|
import type { BuildUpdateResultPayload } from '../util/sql.util.js';
|
|
4
4
|
import { AbstractQuerier } from './abstractQuerier.js';
|
|
5
5
|
export declare abstract class AbstractSqlQuerier extends AbstractQuerier implements SqlQuerier {
|
|
@@ -34,46 +34,27 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
|
|
|
34
34
|
protected lazyConnect(): Promise<void>;
|
|
35
35
|
all<T>(query: string, values?: unknown[]): Promise<T[]>;
|
|
36
36
|
run(query: string, values?: unknown[]): Promise<QueryUpdateResult>;
|
|
37
|
+
/** The rows of a statement the dialect builds. */
|
|
38
|
+
private query;
|
|
39
|
+
/** Runs a statement the dialect builds. */
|
|
40
|
+
private exec;
|
|
37
41
|
/**
|
|
38
|
-
* `$lock`
|
|
39
|
-
*
|
|
40
|
-
* before the caller has seen a row: the SQL is correct, nothing is omitted, and no layer below
|
|
41
|
-
* this one can tell. The dialect cannot check it either, being stateless and shared by every
|
|
42
|
-
* connection of the pool, so this is the only place it can be caught.
|
|
43
|
-
*
|
|
44
|
-
* The capability check runs first on purpose: "this engine has no row locks" is the more
|
|
45
|
-
* actionable answer, and on SQLite it is the answer either way.
|
|
42
|
+
* Refuses a `$lock` the engine lacks, then one outside a transaction, where the lock would drop as the
|
|
43
|
+
* statement commits; only the querier knows whether one is open.
|
|
46
44
|
*/
|
|
47
45
|
protected assertLockable<E>(entity: Type<E>, q: Query<E>): void;
|
|
48
46
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* Same shape as {@link assertLockable} and for the same reason: a `SET LOCAL` outside a transaction
|
|
52
|
-
* is accepted, applies to nothing, and leaves the query running at the engine's default recall -
|
|
53
|
-
* correct SQL, silently untuned. Only the querier knows whether a transaction is open.
|
|
54
|
-
*
|
|
55
|
-
* The statements go through `internalRun`, sharing this querier's single connection with the query
|
|
56
|
-
* they precede; `SET LOCAL` then expires with the transaction, so nothing is left behind.
|
|
47
|
+
* Runs the `SET`s tuning an ANN index for the query on its connection, refusing where they would apply to
|
|
48
|
+
* nothing: a `SET LOCAL` outside a transaction.
|
|
57
49
|
*/
|
|
58
50
|
private applyVectorTuning;
|
|
59
51
|
protected internalFindMany<E extends object>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): Promise<E[]>;
|
|
52
|
+
/** Every row `q` matches past its page, deduplicated where it reads `$distinct`. */
|
|
53
|
+
private countUnpaged;
|
|
60
54
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* pair outright. Both then cost a second statement; only the counting differs.
|
|
65
|
-
*/
|
|
66
|
-
private countedSeparately;
|
|
67
|
-
/**
|
|
68
|
-
* One statement for both: the page carries its own unpaged total in an extra column. An empty page
|
|
69
|
-
* has no row to carry it, which is the one case still needing a count of its own - a `$skip` past
|
|
70
|
-
* the end, or a filter nothing matched.
|
|
71
|
-
*
|
|
72
|
-
* A `$required` relation needs no special case: the window counts what the INNER JOIN left, which
|
|
73
|
-
* is exactly the total a caller of a filtered read is asking for. A `$lock` is the one clause an
|
|
74
|
-
* engine may refuse to have in the same statement, which {@link AbstractSqlDialect.supportsWindowWithRowLock}
|
|
75
|
-
* answers; where it does, the total comes from a count of its own. A `$distinct` read needs one
|
|
76
|
-
* too, and a deduplicating one: see {@link AbstractSqlDialect.countDistinct}.
|
|
55
|
+
* The page and its unpaged total in one statement, a window column on each row, and a count of its own for
|
|
56
|
+
* an empty page. A window counts before `DISTINCT`, and the Postgres family refuses one beside a `$lock`,
|
|
57
|
+
* so those count apart.
|
|
77
58
|
*/
|
|
78
59
|
protected internalFindManyAndCount<E extends object>(entity: Type<E>, q: Query<E>, opts?: QueryOptions): Promise<[E[], number]>;
|
|
79
60
|
private selectRows;
|
|
@@ -104,13 +85,11 @@ export declare abstract class AbstractSqlQuerier extends AbstractQuerier impleme
|
|
|
104
85
|
* a catalog that does not know the table answers with no row, which is nothing counted.
|
|
105
86
|
*/
|
|
106
87
|
private runCount;
|
|
107
|
-
protected internalCount<E extends object>(entity: Type<E>, q
|
|
88
|
+
protected internalCount<E extends object>(entity: Type<E>, q: QueryPage<E>, opts?: QueryOptions): Promise<number>;
|
|
108
89
|
estimatedCount<E extends object>(entity: Type<E>): Promise<number>;
|
|
109
90
|
protected internalAggregate<E extends object, G extends QueryGroupMap<E>, A extends QueryAggMap<E>>(entity: Type<E>, q: QueryAggregate<E, G, A>, opts?: QueryOptions): Promise<QueryAggregateResult<E, G, A>[]>;
|
|
110
91
|
internalInsertMany<E extends object>(entity: Type<E>, rows: EntityData<E>[]): Promise<void>;
|
|
111
92
|
internalUpdateMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): Promise<number>;
|
|
112
|
-
/** The ids matching `q`, in `q`'s own order and page, so a write can name the rows it settled on. */
|
|
113
|
-
private settleIds;
|
|
114
93
|
protected internalUpsertOne<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>): Promise<QueryUpdateResult>;
|
|
115
94
|
protected internalUpsertMany<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>[]): Promise<QueryUpdateResult>;
|
|
116
95
|
private runUpsert;
|