uql-orm 0.66.0 → 0.67.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/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 +3 -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
package/dist/type/queryRaw.js
CHANGED
|
@@ -11,14 +11,7 @@ export class QueryRaw {
|
|
|
11
11
|
as(alias) {
|
|
12
12
|
return new QueryRaw(this[RAW_VALUE], alias);
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
* Emit this expression into `opts.ctx`. How a raw value becomes SQL is the raw value's own
|
|
16
|
-
* business, which is what lets a `raw` tagged template resolve an interpolated fragment without
|
|
17
|
-
* the dialect having to expose a method for it.
|
|
18
|
-
*
|
|
19
|
-
* The alias is not emitted here: it names a `$select` projection, which writes it after the term,
|
|
20
|
-
* and anywhere else it would land mid-expression.
|
|
21
|
-
*/
|
|
14
|
+
/** Writes the expression into `opts.ctx`. The alias is the projection's to write, after the term. */
|
|
22
15
|
render(opts) {
|
|
23
16
|
const emitted = this[RAW_VALUE](opts);
|
|
24
17
|
if (typeof emitted === 'string' || (typeof emitted === 'number' && !Number.isNaN(emitted))) {
|
|
@@ -22,19 +22,9 @@ export type QueryTextSearchOptions<E> = {
|
|
|
22
22
|
$config?: string;
|
|
23
23
|
};
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* filtered via nested typed objects; dotted relation paths are not supported (the dialects throw
|
|
29
|
-
* for non-JSON dotted keys).
|
|
30
|
-
*
|
|
31
|
-
* Fields and relations share one mapped type over `K extends keyof E`, which keeps each key linked to
|
|
32
|
-
* its property (see {@link QuerySelect}). JSON paths are not keys of `E`, so they are a second member,
|
|
33
|
-
* and only where the entity has one: an empty member would switch off the weak-type check that
|
|
34
|
-
* rejects `$where: 1`.
|
|
35
|
-
*
|
|
36
|
-
* An object and nothing else: in a union with ids or lists, TypeScript reports a wrong value against
|
|
37
|
-
* the whole `$where` instead of the key holding it. Ids are `{ id: 1 }`, or the by-id methods.
|
|
25
|
+
* A filter by fields, JSON paths (typed by their payload) and relations, one mapped type over the
|
|
26
|
+
* entity's keys so each stays linked for rename. An object and nothing else, so a wrong value is
|
|
27
|
+
* reported on its key: ids go through `{ id: 1 }` or the by-id methods.
|
|
38
28
|
*/
|
|
39
29
|
export type QueryWhere<E, K extends keyof E = FieldKey<E> | RelationKey<E>> = QueryWhereRootOperator<E> & {
|
|
40
30
|
[P in K]?: P extends FieldKey<E> ? QueryWhereFieldValue<E[P]> : QueryWhere<RelationTarget<E[P]>> | QueryRelationSizeFilter;
|
|
@@ -103,29 +93,9 @@ export type QuerySizeComparisonOps = {
|
|
|
103
93
|
[K in QueryHavingOp | '$between']?: NonNullable<QueryWhereFieldOperatorMap<number>[K]>;
|
|
104
94
|
};
|
|
105
95
|
/**
|
|
106
|
-
* Filter by distance to a
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* Bounded by {@link QueryOrderedOp} - what {@link QuerySizeComparisonOps} ranges over, minus
|
|
110
|
-
* `$eq`/`$ne`. A distance is a float, so exact equality against one is a bug every time, where
|
|
111
|
-
* `$size` compares an integer `COUNT`. No `$project` either: naming the distance is `$sort`'s job,
|
|
112
|
-
* since the `SELECT` list is built from `$sort` alone and a `$near` nested inside an `$or` has no
|
|
113
|
-
* business projecting a column.
|
|
114
|
-
*
|
|
115
|
-
* `$distance` is here for the same reason `$sort` has it: each clause states its own search
|
|
116
|
-
* completely, so neither depends on the other. Omitted, it falls back to the field's declared metric,
|
|
117
|
-
* which is where the metric belongs - beside the index it has to match. Naming a different one per
|
|
118
|
-
* query mostly buys a full scan, since an ANN index is built for exactly one operator class.
|
|
119
|
-
*
|
|
120
|
-
* `$vector` is required, and repeating it beside a `$sort` that ranks by the same field is the point:
|
|
121
|
-
* every other `$where` operator means the same thing wherever it appears, and inheriting one from a
|
|
122
|
-
* sibling clause would make this the first whose validity depends on what else the query contains -
|
|
123
|
-
* unfixable in the type, and carried into merged entity filters and `/http` payloads alike. Naming
|
|
124
|
-
* the vector in a `const` is what removes the repetition, at the call site where it belongs.
|
|
125
|
-
*
|
|
126
|
-
* A `$near` carrying no bound is a `WHERE` that is always true. The dialect rejects that rather than
|
|
127
|
-
* the type: `/http` casts client JSON straight to `Query`, so the check has to exist there anyway,
|
|
128
|
-
* and an "at least one of these five" union would cost every caller worse errors for a second copy.
|
|
96
|
+
* Filter by distance to a vector, `{ $near: { $vector: v, $lt: 0.35 } }`: ordered bounds only, since a
|
|
97
|
+
* distance is a float. Each clause names its own `$vector`, and `$distance` falls back to the field's.
|
|
98
|
+
* One with no bound is refused at run time, where `/http` input is checked anyway.
|
|
129
99
|
*/
|
|
130
100
|
export type QueryVectorNear = QueryVectorQuery & {
|
|
131
101
|
[K in QueryOrderedOp]?: NonNullable<QueryWhereFieldOperatorMap<number>[K]>;
|
|
@@ -224,13 +194,7 @@ export type QueryWhereFieldOperatorMap<T> = {
|
|
|
224
194
|
* @example { tags: { $all: ['typescript', 'orm'] } }
|
|
225
195
|
*/
|
|
226
196
|
$all?: unknown extends T ? unknown[] : NonNullable<T> extends readonly (infer U)[] ? ExpandScalar<U>[] : never;
|
|
227
|
-
/**
|
|
228
|
-
* whether an array has the specified length.
|
|
229
|
-
* Accepts a number for exact match, or a comparison operator object for range queries.
|
|
230
|
-
* @example { roles: { $size: 3 } }
|
|
231
|
-
* @example { roles: { $size: { $gte: 2 } } }
|
|
232
|
-
* @example { roles: { $size: { $gt: 0, $lte: 5 } } }
|
|
233
|
-
*/
|
|
197
|
+
/** whether an array has the given length, or one in range: `{ roles: { $size: { $gte: 2 } } }`. */
|
|
234
198
|
$size?: number | QuerySizeComparisonOps;
|
|
235
199
|
/**
|
|
236
200
|
* whether an array contains at least one element matching all specified conditions.
|
|
@@ -292,11 +256,8 @@ type QueryOrderedOp = QueryCompareOp | keyof Pick<QueryWhereFieldOperatorMap<unk
|
|
|
292
256
|
*/
|
|
293
257
|
type QueryVectorOp = keyof Pick<QueryWhereFieldOperatorMap<unknown>, '$near'>;
|
|
294
258
|
/**
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
* @remarks This is a subtraction, not a list, so an operator added to
|
|
298
|
-
* {@link QueryWhereFieldOperatorMap} without also being classified above lands here and is offered
|
|
299
|
-
* on every field - `$near` on a `boolean`, say. Classify first, then add.
|
|
259
|
+
* The operators every field takes. A subtraction, so an operator added to the map without being
|
|
260
|
+
* classified above is offered on every field: classify it first.
|
|
300
261
|
*/
|
|
301
262
|
type QueryCommonOp = Exclude<keyof QueryWhereFieldOperatorMap<unknown>, QueryStringOp | QueryArrayOp | QueryOrderedOp | QueryVectorOp>;
|
|
302
263
|
/**
|
|
@@ -305,13 +266,8 @@ type QueryCommonOp = Exclude<keyof QueryWhereFieldOperatorMap<unknown>, QueryStr
|
|
|
305
266
|
*/
|
|
306
267
|
type QueryAllowedOp<T> = QueryCommonOp | ([NonNullable<T>] extends [QueryComparableScalar] ? QueryOrderedOp : never) | ([NonNullable<T>] extends [string] ? QueryStringOp : never) | ([NonNullable<T>] extends [readonly number[] | Uint8Array] ? QueryVectorOp : never) | (IsMany<T> extends true ? QueryArrayOp : never);
|
|
307
268
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* Two shapes stay fully permissive, because neither says anything to check against: `unknown`
|
|
312
|
-
* (untyped JSON dot-paths, erased dialect shapes), and a field typed as every scalar at once - the
|
|
313
|
-
* column of a content type defined at runtime. Narrowing to what they share would leave a dynamic
|
|
314
|
-
* row with equality alone, since no operator applies to a boolean and a blob both.
|
|
269
|
+
* The operators a field of type `T` takes. `unknown`, and a column typed as every scalar at once (a
|
|
270
|
+
* runtime-defined entity), take all of them, since nothing narrows what they hold.
|
|
315
271
|
*/
|
|
316
272
|
export type QueryWhereFieldOperators<T> = unknown extends T ? QueryWhereFieldOperatorMap<T> : IsUntypedColumn<T> extends true ? QueryWhereFieldOperatorMap<T> : Pick<QueryWhereFieldOperatorMap<T>, QueryAllowedOp<T>>;
|
|
317
273
|
/**
|
|
@@ -321,12 +277,8 @@ export type QueryWhereFieldOperators<T> = unknown extends T ? QueryWhereFieldOpe
|
|
|
321
277
|
*/
|
|
322
278
|
type IsUntypedColumn<T> = [Scalar] extends [NonNullable<T>] ? true : false;
|
|
323
279
|
/**
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
* membership there requires an explicit operator.
|
|
327
|
-
*
|
|
328
|
-
* `null` is accepted on a nullable field (an optional property is a nullable column), matching what
|
|
329
|
-
* `$eq: null` already took.
|
|
280
|
+
* A field's filter value: the value, `null` where it is optional, a list as an implicit `$in` (not on
|
|
281
|
+
* an array field, where it would be ambiguous), or an operator map.
|
|
330
282
|
*/
|
|
331
283
|
export type QueryWhereFieldValue<T> = T | (undefined extends T ? null : never) | (IsMany<T> extends true ? never : T[]) | QueryWhereFieldOperators<T> | QueryRaw;
|
|
332
284
|
/**
|
|
@@ -4,24 +4,11 @@ import type { QueryAggMap, QueryAggregate, QueryAggregateResult, QueryGroupMap }
|
|
|
4
4
|
import type { Type } from './utility.js';
|
|
5
5
|
import type { QuerierCountedResult, QuerierResult, QuerierTransport } from './wire.js';
|
|
6
6
|
/**
|
|
7
|
-
* The operations
|
|
8
|
-
*
|
|
9
|
-
* `SharedQuerier<'client', RequestOptions, QueryOptions & RequestOptions>`. See {@link QuerierResult}
|
|
10
|
-
* for how the return type follows `W`.
|
|
11
|
-
*
|
|
12
|
-
* @typeParam W - which side of the wire, picking each method's return type.
|
|
13
|
-
* @typeParam O - the per-call options.
|
|
14
|
-
* @typeParam DO - the delete methods' options, which the client also lets carry {@link QueryOptions}
|
|
15
|
-
* (`hardDelete`, `filters`) since it has no other way to reach them.
|
|
7
|
+
* The operations the server and the browser client declare alike, per transport `W`, options `O`,
|
|
8
|
+
* and delete options `DO`, which on the client also carry the {@link QueryOptions} it cannot pass otherwise.
|
|
16
9
|
*/
|
|
17
10
|
export interface SharedQuerier<W extends QuerierTransport, O, DO = O> {
|
|
18
|
-
/**
|
|
19
|
-
* obtains the record with the given primary key.
|
|
20
|
-
* @param entity the target entity
|
|
21
|
-
* @param id the primary key value
|
|
22
|
-
* @param q the additional criteria options
|
|
23
|
-
* @return the record
|
|
24
|
-
*/
|
|
11
|
+
/** Find the record with the given primary key. */
|
|
25
12
|
findOneById<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, id: EntityId<E>, q?: QueryOneProjected<E, S, V, X, P, C>, opts?: O): QuerierResult<W, QueryFindResult<E, S, V, X, P, C> | undefined>;
|
|
26
13
|
/**
|
|
27
14
|
* obtains the first record matching the given search parameters.
|
|
@@ -37,45 +24,15 @@ export interface SharedQuerier<W extends QuerierTransport, O, DO = O> {
|
|
|
37
24
|
* @return the records
|
|
38
25
|
*/
|
|
39
26
|
findMany<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: O): QuerierResult<W, QueryFindResult<E, S, V, X, P, C>[]>;
|
|
40
|
-
/**
|
|
41
|
-
* obtains the records matching the given search parameters,
|
|
42
|
-
* also counts the number of matches ignoring pagination.
|
|
43
|
-
* @param entity the target entity
|
|
44
|
-
* @param q the criteria options
|
|
45
|
-
* @return the records and the count
|
|
46
|
-
*/
|
|
27
|
+
/** Find the records matching the query, and count every match past its page. */
|
|
47
28
|
findManyAndCount<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: O): QuerierCountedResult<W, QueryFindResult<E, S, V, X, P, C>>;
|
|
48
|
-
/**
|
|
49
|
-
* counts the number of records matching the given filter, optionally paged - a `$skip`/`$limit`
|
|
50
|
-
* settles the matching rows first and counts them, rather than scanning every match.
|
|
51
|
-
* @param entity the target entity
|
|
52
|
-
* @param q the filter
|
|
53
|
-
* @return the count
|
|
54
|
-
*/
|
|
29
|
+
/** Count the records matching the filter, or those a page of them takes. */
|
|
55
30
|
count<E extends object>(entity: Type<E>, q?: QueryPage<E>, opts?: O): QuerierResult<W, number>;
|
|
56
|
-
/**
|
|
57
|
-
* whether any record matches the given filter - a count capped at one row, so the engine stops at
|
|
58
|
-
* the first match instead of scanning every other one.
|
|
59
|
-
* @param entity the target entity
|
|
60
|
-
* @param q the filter
|
|
61
|
-
* @return whether anything matched
|
|
62
|
-
*/
|
|
31
|
+
/** Whether any record matches: a count capped at one row, so the engine stops at the first match. */
|
|
63
32
|
exists<E extends object>(entity: Type<E>, q?: QueryFilter<E>, opts?: O): QuerierResult<W, boolean>;
|
|
64
|
-
/**
|
|
65
|
-
* updates a record partially.
|
|
66
|
-
* @param entity the entity to persist on
|
|
67
|
-
* @param id the primary key of the record to be updated
|
|
68
|
-
* @param payload the data to be persisted
|
|
69
|
-
* @return the number of affected records
|
|
70
|
-
*/
|
|
33
|
+
/** Update the record with the given primary key; resolves to the number of affected rows. */
|
|
71
34
|
updateOneById<E extends object>(entity: Type<E>, id: EntityId<E>, payload: UpdatePayload<E>, opts?: O): QuerierResult<W, number>;
|
|
72
|
-
/**
|
|
73
|
-
* updates many records partially.
|
|
74
|
-
* @param entity the entity to persist on
|
|
75
|
-
* @param q the criteria to look for the records
|
|
76
|
-
* @param payload the data to be persisted
|
|
77
|
-
* @return the number of affected records
|
|
78
|
-
*/
|
|
35
|
+
/** Update the records matching the query; resolves to the number of affected rows. */
|
|
79
36
|
updateMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: O): QuerierResult<W, number>;
|
|
80
37
|
/**
|
|
81
38
|
* delete or SoftDelete a record.
|
|
@@ -97,56 +54,21 @@ export interface SharedQuerier<W extends QuerierTransport, O, DO = O> {
|
|
|
97
54
|
*/
|
|
98
55
|
export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions> {
|
|
99
56
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* bulk reads (ETL, exports, migrations).
|
|
103
|
-
* @param entity the target entity
|
|
104
|
-
* @param q the criteria options
|
|
105
|
-
* @return an async iterable of records
|
|
57
|
+
* Stream the records matching the query one at a time, each with the relations and counts `findMany`
|
|
58
|
+
* reads, for bulk reads. Fires no lifecycle hooks.
|
|
106
59
|
*/
|
|
107
60
|
findManyStream<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never, const C extends RelationKey<E> = never>(entity: Type<E>, q: QueryProjected<E, S, V, X, P, C>, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P, C>>;
|
|
108
|
-
/**
|
|
109
|
-
* Insert a single record and return its ID (provided, `onInsert`-generated, or
|
|
110
|
-
* database-generated - see {@link UniversalQuerier.insertMany} for the exact semantics).
|
|
111
|
-
* Returns `undefined` only where the database cannot report one: MySQL, whose `LAST_INSERT_ID()`
|
|
112
|
-
* speaks for `AUTO_INCREMENT` columns alone and is left *stale* rather than cleared otherwise, so
|
|
113
|
-
* a non-auto-increment key the caller did not supply has no id to give and a header read would
|
|
114
|
-
* hand back an earlier row's. Every other backend uses `RETURNING` and is exact, SQLite included.
|
|
115
|
-
* @param entity the entity to persist on
|
|
116
|
-
* @param payload the data to be persisted
|
|
117
|
-
* @return the ID
|
|
118
|
-
*/
|
|
61
|
+
/** Insert a record and resolve to its id. See {@link UniversalQuerier.insertMany}. */
|
|
119
62
|
insertOne<E extends object>(entity: Type<E>, payload: EntityData<E>): Promise<WrittenId<E> | undefined>;
|
|
120
63
|
/**
|
|
121
|
-
* Insert
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* Provided IDs and client-generated ones (`@Id({ onInsert })`) are always returned as-is.
|
|
125
|
-
* Database-generated IDs are exact wherever the statement returns them, which is everywhere but
|
|
126
|
-
* MySQL: there they are inferred from the driver header, which is only reliable for
|
|
127
|
-
* auto-increment keys in batches without explicit IDs - otherwise those entries are
|
|
128
|
-
* `undefined` rather than potentially wrong values. A composite key is never one the statement
|
|
129
|
-
* reports, so those rows are named as written, `onInsert` columns included.
|
|
130
|
-
* @param entity the entity to persist on
|
|
131
|
-
* @param payload the data to be persisted
|
|
132
|
-
* @return the IDs
|
|
64
|
+
* Insert records in as few statements as the bind limit allows, resolving to their ids in payload order.
|
|
65
|
+
* Ids are exact everywhere but MySQL, which infers them from its header and reports `undefined` rather
|
|
66
|
+
* than a guess where it cannot: a batch naming some keys, or a key that is not `AUTO_INCREMENT`.
|
|
133
67
|
*/
|
|
134
68
|
insertMany<E extends object>(entity: Type<E>, payload: EntityData<E>[]): Promise<(WrittenId<E> | undefined)[]>;
|
|
135
|
-
/**
|
|
136
|
-
* Insert or update a record based on the conflict paths.
|
|
137
|
-
* @param entity the entity to persist on
|
|
138
|
-
* @param conflictPaths the keys to use for the unique search
|
|
139
|
-
* @param payload the data to be persisted
|
|
140
|
-
* @return the id and whether it was created; see {@link QueryUpsertOneResult}
|
|
141
|
-
*/
|
|
69
|
+
/** Insert or update a record by its conflict paths; resolves to its id and whether it was created. */
|
|
142
70
|
upsertOne<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>): Promise<QueryUpsertOneResult<E>>;
|
|
143
|
-
/**
|
|
144
|
-
* Insert or update many records based on the conflict paths.
|
|
145
|
-
* @param entity the entity to persist on
|
|
146
|
-
* @param conflictPaths the keys to use for the unique search
|
|
147
|
-
* @param payload the data to be persisted
|
|
148
|
-
* @return the ids, in payload order; see {@link QueryUpsertManyResult}
|
|
149
|
-
*/
|
|
71
|
+
/** Insert or update records by their conflict paths; resolves to their ids in payload order. */
|
|
150
72
|
upsertMany<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>[]): Promise<QueryUpsertManyResult<E>>;
|
|
151
73
|
/**
|
|
152
74
|
* insert or update a record.
|
|
@@ -176,17 +98,8 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
|
|
|
176
98
|
*/
|
|
177
99
|
aggregate<E extends object, const G extends QueryGroupMap<E>, const A extends QueryAggMap<E>>(entity: Type<E>, q: QueryAggregate<E, G, A>, opts?: QueryOptions): Promise<QueryAggregateResult<E, G, A>[]>;
|
|
178
100
|
/**
|
|
179
|
-
*
|
|
180
|
-
* `
|
|
181
|
-
* MongoDB's `estimatedDocumentCount`. For a table too big to {@link count} cheaply.
|
|
182
|
-
*
|
|
183
|
-
* The whole table, and only ever approximately. It takes no filter because none of those sources
|
|
184
|
-
* can answer one, which also puts soft-deleted rows and every entity `filters` inside the number.
|
|
185
|
-
* It is as stale as the last `ANALYZE`/autovacuum (Postgres reports nothing at all until the
|
|
186
|
-
* first one, which reads here as `0`), and a table SQLite can answer for does not exist - it
|
|
187
|
-
* throws there rather than quietly running the scan this exists to avoid.
|
|
188
|
-
* @param entity the target entity
|
|
189
|
-
* @return the estimated number of rows
|
|
101
|
+
* The table's row count as the engine's statistics state it, without reading a row: approximate, as
|
|
102
|
+
* stale as the last `ANALYZE`, and unfiltered, so soft-deleted rows count. SQLite has none and throws.
|
|
190
103
|
*/
|
|
191
104
|
estimatedCount<E extends object>(entity: Type<E>): Promise<number>;
|
|
192
105
|
}
|
package/dist/type/utility.d.ts
CHANGED
|
@@ -4,14 +4,8 @@ export type MongoId = {
|
|
|
4
4
|
toHexString: () => string;
|
|
5
5
|
};
|
|
6
6
|
/**
|
|
7
|
-
* Every value
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `Uint8Array` rather than `Buffer`, which every `Buffer` still satisfies: naming an ambient Node
|
|
11
|
-
* global here made the whole key-checking layer depend on `@types/node` being in scope. Without it
|
|
12
|
-
* `Buffer` resolves to nothing, this union collapses to `any`, and `FieldKey` - the basis of
|
|
13
|
-
* `$select`, `$where`, `$sort`, `@Index` and `defineEntity({ fields })` - silently stops checking
|
|
14
|
-
* anything. A browser or edge project would have got no type safety and no error saying so.
|
|
7
|
+
* Every value a column may hold. `Uint8Array` rather than `Buffer`, which would need `@types/node` and
|
|
8
|
+
* collapse to `any` without it, switching every key check off.
|
|
15
9
|
*/
|
|
16
10
|
export type Scalar = string | number | boolean | bigint | Date | RegExp | Uint8Array | MongoId;
|
|
17
11
|
/**
|
|
@@ -23,16 +17,8 @@ export type QueryComparableScalar = string | number | bigint | Date;
|
|
|
23
17
|
*/
|
|
24
18
|
export type PrimaryKey = string | number | bigint;
|
|
25
19
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* (not a `RelationKey`), enabling type-safe usage in `$where`, `$select`, and `$sort`. A column
|
|
29
|
-
* holding a list of documents is `Json<T>[]`, also a field, whose dot-paths address the element.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* @Field({ type: 'jsonb' })
|
|
34
|
-
* settings?: Json<{ isArchived?: boolean }>;
|
|
35
|
-
* ```
|
|
20
|
+
* Brands a JSON field, `settings?: Json<{ isArchived?: boolean }>`, so it reads as a field rather than a
|
|
21
|
+
* relation; `Json<T>[]` is a list of documents.
|
|
36
22
|
*/
|
|
37
23
|
export type Json<T = unknown> = T & {
|
|
38
24
|
readonly __json?: never;
|
|
@@ -48,16 +34,18 @@ export type Writable<T> = {
|
|
|
48
34
|
-readonly [K in keyof T]: T[K];
|
|
49
35
|
};
|
|
50
36
|
/**
|
|
51
|
-
* `Omit
|
|
52
|
-
*
|
|
53
|
-
* over unions, where `Omit` intersects each member's keys and flattens a discriminated union (e.g.
|
|
54
|
-
* `EntityIndexMeta`'s `type`/`distance` pairing) into one non-discriminated shape. And it removes
|
|
55
|
-
* the key from types carrying an index signature, where `Exclude<keyof T, K>` widens back to
|
|
56
|
-
* `string | number` and leaves the key in place.
|
|
37
|
+
* `Omit` whose key has to exist, which distributes over a union rather than flattening it, and removes
|
|
38
|
+
* a key from a type with an index signature.
|
|
57
39
|
*/
|
|
58
40
|
export type Except<T, K extends keyof T> = {
|
|
59
41
|
[P in keyof T as P extends K ? never : P]: T[P];
|
|
60
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Each key of `K` mapped to `never`, so an intersection with it makes naming one a compile error;
|
|
45
|
+
* `unknown`, inert, when there are none. A captured type parameter needs it: TypeScript skips the
|
|
46
|
+
* excess-property check on one.
|
|
47
|
+
*/
|
|
48
|
+
export type RejectKeys<K> = [K] extends [never] ? unknown : Record<K & string, never>;
|
|
61
49
|
export type Unpacked<T> = T extends readonly (infer U)[] ? U : T extends (...args: unknown[]) => infer U ? U : T extends Promise<infer U> ? U : T;
|
|
62
50
|
/**
|
|
63
51
|
* Whether the value a property holds is many rather than one: a to-many relation, a scalar array, a
|
package/dist/type/vector.d.ts
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import type { IndexType } from '../schema/types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - `l2` - Euclidean distance
|
|
6
|
-
* - `inner` - inner (dot) product
|
|
7
|
-
* - `l1` - Manhattan distance
|
|
8
|
-
*
|
|
9
|
-
* @remarks Hamming distance is absent because no engine can express it over a float vector column:
|
|
10
|
-
* pgvector's `<~>`/`bit_hamming_ops` and sqlite-vec's `vec_distance_hamming` both require a *bit*
|
|
11
|
-
* vector, which no field type maps to. It would be a value that compiles and always throws.
|
|
3
|
+
* A vector search's metric: `cosine` (the default), `l2`, `inner` product or `l1`. No hamming: every
|
|
4
|
+
* engine's takes a bit vector, which no field type maps to.
|
|
12
5
|
*/
|
|
13
6
|
export type VectorDistance = 'cosine' | 'l2' | 'inner' | 'l1';
|
|
14
7
|
/**
|
|
@@ -24,42 +17,19 @@ export interface QueryVectorQuery {
|
|
|
24
17
|
}
|
|
25
18
|
/** The keys that describe the search rather than bound it, so `$near`'s bounds are what is left. */
|
|
26
19
|
export declare const VECTOR_QUERY_KEYS: readonly ["$vector", "$distance"];
|
|
27
|
-
/**
|
|
28
|
-
* Vector similarity search options - used inside `$sort` on vector fields.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```ts
|
|
32
|
-
* querier.findMany(Article, {
|
|
33
|
-
* $sort: { embedding: { $vector: queryVec } },
|
|
34
|
-
* $limit: 10,
|
|
35
|
-
* });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
20
|
+
/** A vector search in `$sort`: `{ $sort: { embedding: { $vector: queryVec } }, $limit: 10 }`. */
|
|
38
21
|
export interface QueryVectorSearch extends QueryVectorQuery {
|
|
39
22
|
/** Project the computed distance as a named field in the result. */
|
|
40
23
|
readonly $project?: string;
|
|
41
24
|
}
|
|
42
25
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* ```ts
|
|
46
|
-
* const results = (await querier.findMany(Article, {
|
|
47
|
-
* $sort: { embedding: { $vector: queryVec, $project: 'similarity' } },
|
|
48
|
-
* })) as WithDistance<Article, 'similarity'>[];
|
|
49
|
-
* ```
|
|
26
|
+
* A row with the distance a `$sort` `$project` names, which is not inferred:
|
|
27
|
+
* `(await querier.findMany(Article, q)) as WithDistance<Article, 'similarity'>[]`.
|
|
50
28
|
*/
|
|
51
29
|
export type WithDistance<E, K extends string = '_distance'> = E & Record<K, number>;
|
|
52
30
|
/**
|
|
53
|
-
* How
|
|
54
|
-
*
|
|
55
|
-
* SQLite family) - so they are one discriminated map rather than two parallel ones. That is what
|
|
56
|
-
* lets a single `appendVectorSort` serve every engine, and makes the map's key set the one answer
|
|
57
|
-
* to "does this dialect have this metric".
|
|
58
|
-
*
|
|
59
|
-
* `opsSuffix` rides along on the operator form because pgvector's index operator class is named from
|
|
60
|
-
* the same metric (`vector_cosine_ops`): keeping them together is what stops a dialect from having
|
|
61
|
-
* the operator but not the class it indexes with. `metricArg` is for the engine with one function
|
|
62
|
-
* taking the metric by name: SQL Server's `VECTOR_DISTANCE('cosine', a, b)`.
|
|
31
|
+
* How a dialect spells a metric: an operator with the operator class an index names from it, or a
|
|
32
|
+
* function, `metricArg` where it takes the metric by name. One map, so its keys say which metrics exist.
|
|
63
33
|
*/
|
|
64
34
|
export type VectorMetric = {
|
|
65
35
|
readonly op: string;
|
|
@@ -72,7 +42,7 @@ export type VectorMetric = {
|
|
|
72
42
|
export type VectorOperatorMetric = Extract<VectorMetric, {
|
|
73
43
|
op: string;
|
|
74
44
|
}>;
|
|
75
|
-
/**
|
|
45
|
+
/** The error every dialect throws for a metric it lacks. */
|
|
76
46
|
export declare function unsupportedVectorMetric(dialectName: string, distance: VectorDistance, indexName?: string): TypeError;
|
|
77
47
|
/**
|
|
78
48
|
* Vector-specific tuning options shared by `@Index` decorator, entity metadata, and migration schema.
|
package/dist/type/vector.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** The keys that describe the search rather than bound it, so `$near`'s bounds are what is left. */
|
|
2
2
|
export const VECTOR_QUERY_KEYS = ['$vector', '$distance'];
|
|
3
|
-
/**
|
|
3
|
+
/** The error every dialect throws for a metric it lacks. */
|
|
4
4
|
export function unsupportedVectorMetric(dialectName, distance, indexName) {
|
|
5
5
|
const where = indexName === undefined ? '' : ` (index "${indexName}")`;
|
|
6
6
|
return new TypeError(`${dialectName} does not support vector distance metric: ${distance}${where}`);
|
package/dist/type/wire.d.ts
CHANGED
|
@@ -17,11 +17,8 @@ export type RequestCountedSuccessResponse<E> = RequestSuccessResponse<E> & {
|
|
|
17
17
|
*/
|
|
18
18
|
export type QuerierTransport = 'server' | 'client';
|
|
19
19
|
/**
|
|
20
|
-
* A querier method's result on the
|
|
21
|
-
*
|
|
22
|
-
* `Promise<RequestSuccessResponse<User[]>>`. Indexing a map by the transport is what stands in for
|
|
23
|
-
* the higher-kinded wrapper TypeScript cannot express, and it resolves away: errors and hovers show
|
|
24
|
-
* the `Promise<User[]>` it picked, never this indirection.
|
|
20
|
+
* A querier method's result on a transport: `Promise<User[]>` on the server, the response envelope on
|
|
21
|
+
* the client. A map indexed by the transport, which resolves away in hovers.
|
|
25
22
|
*/
|
|
26
23
|
export type QuerierResult<W extends QuerierTransport, T> = {
|
|
27
24
|
server: Promise<T>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CascadeType, type EntityData, type EntityId, type EntityIndexMeta, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type Query, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySearch, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryTextSearchOptions, type QueryVectorSearch, type QueryWhere, type RelationKey, type UpdatePayload } from '../type/index.js';
|
|
2
2
|
export type CallbackKey = keyof Pick<FieldOptions, 'onInsert' | 'onUpdate'>;
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** The keys of `payload` a write persists as columns. */
|
|
4
|
+
export declare function filterFieldKeys<E>(meta: EntityMeta<E>, payload: EntityData<E> | UpdatePayload<E>, callbackKey: CallbackKey): FieldKey<E>[];
|
|
5
5
|
/**
|
|
6
6
|
* The insertable keys `record` itself carries, as a string, for grouping rows by the statement they
|
|
7
7
|
* can share. Only the row's own keys: the `onInsert` columns {@link getInsertFieldKeys} appends are a
|
|
@@ -9,16 +9,8 @@ export declare function filterFieldKeys<E>(meta: EntityMeta<E>, payload: EntityD
|
|
|
9
9
|
*/
|
|
10
10
|
export declare function insertShapeOf<E>(meta: EntityMeta<E>, record: EntityData<E>): string;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* columns insert its database default.
|
|
15
|
-
*
|
|
16
|
-
* The column list is seeded from the first record, then extended by every other record's
|
|
17
|
-
* not-yet-seen columns - a no-op scan for a homogeneous batch (every record the same shape).
|
|
18
|
-
*
|
|
19
|
-
* `onInsert` fields are always included so the column set is stable whether or not the caller
|
|
20
|
-
* has run {@link fillOnFields} first (it stamps them on every record, but the querier's
|
|
21
|
-
* chunk-size estimate inspects the raw payload).
|
|
12
|
+
* An insert's columns: every record's writable fields in first-seen order, plus every `onInsert` field,
|
|
13
|
+
* whether or not it was filled yet. A record missing one writes its default.
|
|
22
14
|
*/
|
|
23
15
|
export declare function getInsertFieldKeys<E>(meta: EntityMeta<E>, payloads: EntityData<E>[]): FieldKey<E>[];
|
|
24
16
|
export declare function getFieldCallbackValue(val: OnFieldCallback): string | number | bigint | boolean | Date | QueryRaw | readonly {
|
|
@@ -104,17 +96,9 @@ export declare function assertWhere<E>(meta: EntityMeta<E>, where: unknown): voi
|
|
|
104
96
|
/** Returns a `QueryOptions.filters` value with the built-in soft-delete filter disabled (used by hard delete). */
|
|
105
97
|
export declare function withoutSoftDeleteFilter(filters: QueryOptions['filters']): QueryOptions['filters'];
|
|
106
98
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* Convenience filters are active by default (unless `opts.filters === false` or bypassed by name), and
|
|
111
|
-
* their keys are applied only when absent from the map, so an explicit `$where` on that key opts out.
|
|
112
|
-
*
|
|
113
|
-
* `security` filters are always active (bypass is ignored) and AND-merged, so a client `$where` on the
|
|
114
|
-
* same field can't override them. A security condition that returns `undefined` fails the query closed
|
|
115
|
-
* (throws {@link UqlSecurityError}) unless its `onMissing` is `skip`; one that returns an empty object
|
|
116
|
-
* (`{}`) resolved to "no restriction" and adds nothing - the escape hatch for trusted cross-tenant
|
|
117
|
-
* work (e.g. a maintenance job running under a `system` context).
|
|
99
|
+
* `$where` with the entity's active filters merged in, against the ambient {@link UqlContext}. A convenience
|
|
100
|
+
* filter yields to a `$where` on its key; a `security` one is always ANDed, and throws where its condition
|
|
101
|
+
* resolves to nothing, unless `onMissing: 'skip'`.
|
|
118
102
|
*/
|
|
119
103
|
export declare function applyFilters<E>(meta: EntityMeta<E>, whereMap: QueryWhere<E>, opts?: QueryOptions): QueryWhere<E>;
|
|
120
104
|
/**
|
|
@@ -132,10 +116,8 @@ export type ParsedGroupEntry = {
|
|
|
132
116
|
readonly distinct: boolean;
|
|
133
117
|
};
|
|
134
118
|
/**
|
|
135
|
-
* The `$size` of a relation condition
|
|
136
|
-
*
|
|
137
|
-
* a relation key means, and so the ambiguous mix fails loudly: `{ $size: 2, name: 'x' }` used to fall
|
|
138
|
-
* through to field filtering and emit a condition on a `$size` *column*.
|
|
119
|
+
* The `$size` of a relation condition, `{ comments: { $size: { $gte: 2 } } }`, or `undefined` where it
|
|
120
|
+
* filters the target's fields; a mix of the two, `{ $size: 2, name: 'x' }`, is refused.
|
|
139
121
|
*/
|
|
140
122
|
export declare function parseRelationSize(val: unknown): number | QuerySizeComparisonOps | undefined;
|
|
141
123
|
/**
|
|
@@ -4,6 +4,7 @@ import { QueryRaw, resolveAggregateOp, SOFT_DELETE_FILTER, } from '../type/index
|
|
|
4
4
|
import { VECTOR_INDEX_TYPES } from '../type/vector.js';
|
|
5
5
|
import { isDatabaseWritten } from './field.util.js';
|
|
6
6
|
import { entityName, getFieldKeys, getKeys, hasKeys, isScalarId, isRecord, isWhereMap, someKey, } from './object.util.js';
|
|
7
|
+
/** The keys of `payload` a write persists as columns. */
|
|
7
8
|
export function filterFieldKeys(meta, payload, callbackKey) {
|
|
8
9
|
return getKeys(payload).filter((key) => {
|
|
9
10
|
const fieldOpts = meta.fields[key];
|
|
@@ -15,7 +16,6 @@ function isInsertableField(meta, record, key) {
|
|
|
15
16
|
const field = meta.fields[key];
|
|
16
17
|
return !!field && !isDatabaseWritten(field) && record[key] !== undefined;
|
|
17
18
|
}
|
|
18
|
-
/** Appends `record`'s not-yet-`seen` insertable keys (real, caller-written, defined value) to `keys`. */
|
|
19
19
|
/**
|
|
20
20
|
* The insertable keys `record` itself carries, as a string, for grouping rows by the statement they
|
|
21
21
|
* can share. Only the row's own keys: the `onInsert` columns {@link getInsertFieldKeys} appends are a
|
|
@@ -30,6 +30,7 @@ export function insertShapeOf(meta, record) {
|
|
|
30
30
|
}
|
|
31
31
|
return shape;
|
|
32
32
|
}
|
|
33
|
+
/** Appends `record`'s not-yet-`seen` insertable keys to `keys`. */
|
|
33
34
|
function addInsertFieldKeys(meta, record, seen, keys) {
|
|
34
35
|
for (const key of getKeys(record)) {
|
|
35
36
|
if (!seen.has(key) && isInsertableField(meta, record, key)) {
|
|
@@ -39,16 +40,8 @@ function addInsertFieldKeys(meta, record, seen, keys) {
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* columns insert its database default.
|
|
45
|
-
*
|
|
46
|
-
* The column list is seeded from the first record, then extended by every other record's
|
|
47
|
-
* not-yet-seen columns - a no-op scan for a homogeneous batch (every record the same shape).
|
|
48
|
-
*
|
|
49
|
-
* `onInsert` fields are always included so the column set is stable whether or not the caller
|
|
50
|
-
* has run {@link fillOnFields} first (it stamps them on every record, but the querier's
|
|
51
|
-
* chunk-size estimate inspects the raw payload).
|
|
43
|
+
* An insert's columns: every record's writable fields in first-seen order, plus every `onInsert` field,
|
|
44
|
+
* whether or not it was filled yet. A record missing one writes its default.
|
|
52
45
|
*/
|
|
53
46
|
export function getInsertFieldKeys(meta, payloads) {
|
|
54
47
|
const seen = new Set();
|
|
@@ -186,7 +179,7 @@ export function isVectorSearch(value) {
|
|
|
186
179
|
* which, as they did when one took the first and the other the last.
|
|
187
180
|
*/
|
|
188
181
|
export function findVectorSort(sort) {
|
|
189
|
-
for (const key of getKeys(sort
|
|
182
|
+
for (const key of getKeys(sort)) {
|
|
190
183
|
const search = sort?.[key];
|
|
191
184
|
// The guard narrows here, where a `.find()` over entries would hand back an untyped tuple.
|
|
192
185
|
if (isVectorSearch(search)) {
|
|
@@ -259,17 +252,9 @@ export function withoutSoftDeleteFilter(filters) {
|
|
|
259
252
|
return filters === false ? false : { ...filters, [SOFT_DELETE_FILTER]: false };
|
|
260
253
|
}
|
|
261
254
|
/**
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* Convenience filters are active by default (unless `opts.filters === false` or bypassed by name), and
|
|
266
|
-
* their keys are applied only when absent from the map, so an explicit `$where` on that key opts out.
|
|
267
|
-
*
|
|
268
|
-
* `security` filters are always active (bypass is ignored) and AND-merged, so a client `$where` on the
|
|
269
|
-
* same field can't override them. A security condition that returns `undefined` fails the query closed
|
|
270
|
-
* (throws {@link UqlSecurityError}) unless its `onMissing` is `skip`; one that returns an empty object
|
|
271
|
-
* (`{}`) resolved to "no restriction" and adds nothing - the escape hatch for trusted cross-tenant
|
|
272
|
-
* work (e.g. a maintenance job running under a `system` context).
|
|
255
|
+
* `$where` with the entity's active filters merged in, against the ambient {@link UqlContext}. A convenience
|
|
256
|
+
* filter yields to a `$where` on its key; a `security` one is always ANDed, and throws where its condition
|
|
257
|
+
* resolves to nothing, unless `onMissing: 'skip'`.
|
|
273
258
|
*/
|
|
274
259
|
export function applyFilters(meta, whereMap, opts) {
|
|
275
260
|
if (!meta.filters) {
|
|
@@ -323,10 +308,8 @@ export function applyFilters(meta, whereMap, opts) {
|
|
|
323
308
|
return result;
|
|
324
309
|
}
|
|
325
310
|
/**
|
|
326
|
-
* The `$size` of a relation condition
|
|
327
|
-
*
|
|
328
|
-
* a relation key means, and so the ambiguous mix fails loudly: `{ $size: 2, name: 'x' }` used to fall
|
|
329
|
-
* through to field filtering and emit a condition on a `$size` *column*.
|
|
311
|
+
* The `$size` of a relation condition, `{ comments: { $size: { $gte: 2 } } }`, or `undefined` where it
|
|
312
|
+
* filters the target's fields; a mix of the two, `{ $size: 2, name: 'x' }`, is refused.
|
|
330
313
|
*/
|
|
331
314
|
export function parseRelationSize(val) {
|
|
332
315
|
if (!val || typeof val !== 'object' || !('$size' in val)) {
|