uql-orm 0.36.1 → 0.37.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/http/http.d.ts +1 -1
- package/dist/browser/querier/httpQuerier.d.ts +12 -7
- package/dist/browser/querier/httpQuerier.js +6 -1
- package/dist/browser/type/clientQuerier.d.ts +10 -23
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +7 -7
- package/dist/cockroachdb/cockroachDialect.d.ts +8 -1
- package/dist/cockroachdb/cockroachDialect.js +12 -0
- package/dist/dialect/abstractSqlDialect.d.ts +31 -4
- package/dist/dialect/abstractSqlDialect.js +64 -15
- package/dist/dialect/aliases.d.ts +30 -0
- package/dist/dialect/aliases.js +32 -0
- package/dist/dialect/jsonSql.d.ts +0 -20
- package/dist/dialect/jsonSql.js +0 -20
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +6 -0
- package/dist/dialect/mysqlLikeSqlDialect.js +20 -1
- package/dist/dialect/pgLikeSqlDialect.d.ts +2 -0
- package/dist/dialect/pgLikeSqlDialect.js +4 -1
- package/dist/dialect/queryJoins.d.ts +6 -0
- package/dist/dialect/queryJoins.js +13 -0
- package/dist/http/contract.d.ts +0 -7
- package/dist/http/handler.d.ts +2 -2
- package/dist/http/handler.js +1 -1
- package/dist/http/query.js +3 -2
- package/dist/mongo/mongoDialect.d.ts +15 -4
- package/dist/mongo/mongoDialect.js +65 -16
- package/dist/mongo/mongodbQuerier.d.ts +13 -2
- package/dist/mongo/mongodbQuerier.js +46 -2
- package/dist/postgres/postgresDialect.d.ts +7 -0
- package/dist/postgres/postgresDialect.js +13 -0
- package/dist/querier/abstractQuerier.d.ts +34 -18
- package/dist/querier/abstractQuerier.js +43 -30
- package/dist/querier/abstractQuerierPool.d.ts +9 -7
- package/dist/querier/abstractQuerierPool.js +6 -0
- package/dist/querier/abstractSqlQuerier.d.ts +30 -2
- package/dist/querier/abstractSqlQuerier.js +61 -8
- package/dist/querier/relationCount.d.ts +16 -0
- package/dist/querier/relationCount.js +104 -0
- package/dist/sqlite/sqliteDialect.d.ts +6 -1
- package/dist/sqlite/sqliteDialect.js +12 -1
- package/dist/type/dialect.d.ts +10 -3
- package/dist/type/index.d.ts +1 -0
- package/dist/type/index.js +1 -0
- package/dist/type/querier.d.ts +21 -14
- package/dist/type/query.d.ts +77 -16
- package/dist/type/query.js +17 -0
- package/dist/type/universalQuerier.d.ts +85 -48
- package/dist/type/wire.d.ts +37 -0
- package/dist/type/wire.js +1 -0
- package/dist/util/dialect.util.d.ts +6 -0
- package/dist/util/dialect.util.js +15 -0
- package/dist/util/relationQuery.util.d.ts +9 -0
- package/dist/util/relationQuery.util.js +13 -0
- package/package.json +4 -4
package/dist/type/query.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
|
|
3
|
+
* which ones count. One statement per relation named here, batched over every parent at once, so it
|
|
4
|
+
* stays flat however many rows the read returned. Comes back under `_count`, which keeps it clear of
|
|
5
|
+
* a relation of the same name that `$populate` filled with rows.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* The key a read carries its relation tallies under. One spelling for the type and the runtime that
|
|
9
|
+
* fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
|
|
10
|
+
*/
|
|
11
|
+
export const COUNT_RESULT_KEY = '_count';
|
|
1
12
|
/**
|
|
2
13
|
* `Query`'s clauses grouped by the shape of their value - what a parser reading one off the wire and
|
|
3
14
|
* a validator checking a relation's own query both need, and what each used to enumerate for itself.
|
|
@@ -14,5 +25,11 @@ export const QUERY_OBJECT_CLAUSES = [
|
|
|
14
25
|
'$where',
|
|
15
26
|
'$sort',
|
|
16
27
|
];
|
|
28
|
+
/**
|
|
29
|
+
* Object clauses only the statement itself takes, never a relation's own query - the mirror of
|
|
30
|
+
* `$lock`, which neither takes. Counting a relation is batched over the rows a read returned, and a
|
|
31
|
+
* populated relation's rows are assembled after that, so there is nothing for a nested one to count.
|
|
32
|
+
*/
|
|
33
|
+
export const QUERY_ROOT_OBJECT_CLAUSES = ['$count'];
|
|
17
34
|
export const QUERY_NUMBER_CLAUSES = ['$skip', '$limit'];
|
|
18
35
|
export const QUERY_BOOLEAN_CLAUSES = ['$distinct'];
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import type { EntityData, FieldKey, IdValue, RelationKey, UpdatePayload } from './entity.js';
|
|
2
|
-
import type { QueryConflictPaths, QueryFilter, QueryFindResult, QueryOneProjected, QueryOptions, QueryProjected, QuerySearch, QueryUpdateResult } from './query.js';
|
|
2
|
+
import type { QueryConflictPaths, QueryFilter, QueryFindResult, QueryOneProjected, QueryOptions, QueryPage, QueryProjected, QuerySearch, QueryStreamProjected, QueryUpdateResult } from './query.js';
|
|
3
3
|
import type { QueryAggMap, QueryAggregate, QueryAggregateResult, QueryGroupMap } from './queryAggregate.js';
|
|
4
4
|
import type { Type } from './utility.js';
|
|
5
|
+
import type { QuerierCountedResult, QuerierResult, QuerierTransport } from './wire.js';
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* The operations {@link UniversalQuerier} and `ClientQuerier` declare identically, written once and
|
|
8
|
+
* instantiated per transport: `SharedQuerier<'server', QueryOptions>` against
|
|
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
16
|
*/
|
|
8
|
-
export interface
|
|
17
|
+
export interface SharedQuerier<W extends QuerierTransport, O, DO = O> {
|
|
9
18
|
/**
|
|
10
19
|
* obtains the record with the given primary key.
|
|
11
20
|
* @param entity the target entity
|
|
@@ -13,30 +22,21 @@ export interface UniversalQuerier {
|
|
|
13
22
|
* @param q the additional criteria options
|
|
14
23
|
* @return the record
|
|
15
24
|
*/
|
|
16
|
-
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>(entity: Type<E>, id: IdValue<E>, q?: QueryOneProjected<E, S, V, X, P>, opts?:
|
|
25
|
+
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: IdValue<E>, q?: QueryOneProjected<E, S, V, X, P, C>, opts?: O): QuerierResult<W, QueryFindResult<E, S, V, X, P, C> | undefined>;
|
|
17
26
|
/**
|
|
18
27
|
* obtains the first record matching the given search parameters.
|
|
19
28
|
* @param entity the target entity
|
|
20
29
|
* @param q the criteria options
|
|
21
30
|
* @return the record
|
|
22
31
|
*/
|
|
23
|
-
findOne<E extends object, const S extends FieldKey<E> = never, const V = true, const X extends FieldKey<E> = never, const P extends RelationKey<E> = never>(entity: Type<E>, q: QueryOneProjected<E, S, V, X, P>, opts?:
|
|
32
|
+
findOne<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: QueryOneProjected<E, S, V, X, P, C>, opts?: O): QuerierResult<W, QueryFindResult<E, S, V, X, P, C> | undefined>;
|
|
24
33
|
/**
|
|
25
34
|
* obtains the records matching the given search parameters.
|
|
26
35
|
* @param entity the target entity
|
|
27
36
|
* @param q the criteria options
|
|
28
37
|
* @return the records
|
|
29
38
|
*/
|
|
30
|
-
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>(entity: Type<E>, q: QueryProjected<E, S, V, X, P>, opts?:
|
|
31
|
-
/**
|
|
32
|
-
* streams the records matching the given search parameters as an async iterable.
|
|
33
|
-
* Does not fill relations or fire lifecycle hooks - designed for high-performance
|
|
34
|
-
* bulk reads (ETL, exports, migrations).
|
|
35
|
-
* @param entity the target entity
|
|
36
|
-
* @param q the criteria options
|
|
37
|
-
* @return an async iterable of records
|
|
38
|
-
*/
|
|
39
|
-
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>(entity: Type<E>, q: QueryProjected<E, S, V, X, P>, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P>>;
|
|
39
|
+
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
40
|
/**
|
|
41
41
|
* obtains the records matching the given search parameters,
|
|
42
42
|
* also counts the number of matches ignoring pagination.
|
|
@@ -44,14 +44,67 @@ export interface UniversalQuerier {
|
|
|
44
44
|
* @param q the criteria options
|
|
45
45
|
* @return the records and the count
|
|
46
46
|
*/
|
|
47
|
-
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>(entity: Type<E>, q: QueryProjected<E, S, V, X, P>, opts?:
|
|
47
|
+
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
48
|
/**
|
|
49
|
-
* counts the number of records matching the given filter
|
|
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.
|
|
50
51
|
* @param entity the target entity
|
|
51
52
|
* @param q the filter
|
|
52
53
|
* @return the count
|
|
53
54
|
*/
|
|
54
|
-
count<E extends object>(entity: Type<E>, q?:
|
|
55
|
+
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
|
+
*/
|
|
63
|
+
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
|
+
*/
|
|
71
|
+
updateOneById<E extends object>(entity: Type<E>, id: IdValue<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
|
+
*/
|
|
79
|
+
updateMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: O): QuerierResult<W, number>;
|
|
80
|
+
/**
|
|
81
|
+
* delete or SoftDelete a record.
|
|
82
|
+
* @param entity the entity to persist on
|
|
83
|
+
* @param id the primary key of the record
|
|
84
|
+
* @return the number of affected records
|
|
85
|
+
*/
|
|
86
|
+
deleteOneById<E extends object>(entity: Type<E>, id: IdValue<E>, opts?: DO): QuerierResult<W, number>;
|
|
87
|
+
/**
|
|
88
|
+
* delete or SoftDelete records.
|
|
89
|
+
* @param entity the entity to persist on
|
|
90
|
+
* @param q the criteria to look for the records
|
|
91
|
+
* @return the number of affected records
|
|
92
|
+
*/
|
|
93
|
+
deleteMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, opts?: DO): QuerierResult<W, number>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A `querier` allows to interact with the datasource to perform persistence operations on any entity.
|
|
97
|
+
*/
|
|
98
|
+
export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions> {
|
|
99
|
+
/**
|
|
100
|
+
* streams the records matching the given search parameters as an async iterable.
|
|
101
|
+
* Does not fill relations or fire lifecycle hooks - designed for high-performance
|
|
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
|
|
106
|
+
*/
|
|
107
|
+
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>(entity: Type<E>, q: QueryStreamProjected<E, S, V, X, P>, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P>>;
|
|
55
108
|
/**
|
|
56
109
|
* Insert a single record and return its ID (provided, `onInsert`-generated, or
|
|
57
110
|
* database-generated - see {@link UniversalQuerier.insertMany} for the exact semantics).
|
|
@@ -78,22 +131,6 @@ export interface UniversalQuerier {
|
|
|
78
131
|
* @return the IDs
|
|
79
132
|
*/
|
|
80
133
|
insertMany<E extends object>(entity: Type<E>, payload: EntityData<E>[]): Promise<IdValue<E>[]>;
|
|
81
|
-
/**
|
|
82
|
-
* updates a record partially.
|
|
83
|
-
* @param entity the entity to persist on
|
|
84
|
-
* @param id the primary key of the record to be updated
|
|
85
|
-
* @param payload the data to be persisted
|
|
86
|
-
* @return the number of affected records
|
|
87
|
-
*/
|
|
88
|
-
updateOneById<E extends object>(entity: Type<E>, id: IdValue<E>, payload: UpdatePayload<E>, opts?: QueryOptions): Promise<number>;
|
|
89
|
-
/**
|
|
90
|
-
* updates many records partially.
|
|
91
|
-
* @param entity the entity to persist on
|
|
92
|
-
* @param q the criteria to look for the records
|
|
93
|
-
* @param payload the data to be persisted
|
|
94
|
-
* @return the number of affected records
|
|
95
|
-
*/
|
|
96
|
-
updateMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, payload: UpdatePayload<E>, opts?: QueryOptions): Promise<number>;
|
|
97
134
|
/**
|
|
98
135
|
* Insert or update a record based on the conflict paths.
|
|
99
136
|
* @param entity the entity to persist on
|
|
@@ -124,20 +161,6 @@ export interface UniversalQuerier {
|
|
|
124
161
|
* @return the IDs
|
|
125
162
|
*/
|
|
126
163
|
saveMany<E extends object>(entity: Type<E>, payload: EntityData<E>[]): Promise<IdValue<E>[]>;
|
|
127
|
-
/**
|
|
128
|
-
* delete or SoftDelete a record.
|
|
129
|
-
* @param entity the entity to persist on
|
|
130
|
-
* @param id the primary key of the record
|
|
131
|
-
* @return the number of affected records
|
|
132
|
-
*/
|
|
133
|
-
deleteOneById<E extends object>(entity: Type<E>, id: IdValue<E>, opts?: QueryOptions): Promise<number>;
|
|
134
|
-
/**
|
|
135
|
-
* delete or SoftDelete records.
|
|
136
|
-
* @param entity the entity to persist on
|
|
137
|
-
* @param q the criteria to look for the records
|
|
138
|
-
* @return the number of affected records
|
|
139
|
-
*/
|
|
140
|
-
deleteMany<E extends object>(entity: Type<E>, q: QuerySearch<E>, opts?: QueryOptions): Promise<number>;
|
|
141
164
|
/**
|
|
142
165
|
* Restore soft-deleted records (sets the soft-delete field back to `null`). Throws if the
|
|
143
166
|
* entity has no soft-delete field.
|
|
@@ -151,4 +174,18 @@ export interface UniversalQuerier {
|
|
|
151
174
|
* @return the aggregate results
|
|
152
175
|
*/
|
|
153
176
|
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>[]>;
|
|
177
|
+
/**
|
|
178
|
+
* How many rows the engine's own statistics say the table holds, without reading one: Postgres'
|
|
179
|
+
* `pg_class.reltuples`, CockroachDB's table statistics, MySQL/MariaDB's `information_schema`,
|
|
180
|
+
* MongoDB's `estimatedDocumentCount`. For a table too big to {@link count} cheaply.
|
|
181
|
+
*
|
|
182
|
+
* The whole table, and only ever approximately. It takes no filter because none of those sources
|
|
183
|
+
* can answer one, which also puts soft-deleted rows and every entity `filters` inside the number.
|
|
184
|
+
* It is as stale as the last `ANALYZE`/autovacuum (Postgres reports nothing at all until the
|
|
185
|
+
* first one, which reads here as `0`), and a table SQLite can answer for does not exist - it
|
|
186
|
+
* throws there rather than quietly running the scan this exists to avoid.
|
|
187
|
+
* @param entity the target entity
|
|
188
|
+
* @return the estimated number of rows
|
|
189
|
+
*/
|
|
190
|
+
estimatedCount<E extends object>(entity: Type<E>): Promise<number>;
|
|
154
191
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The envelope a wire response wraps its result in.
|
|
3
|
+
*/
|
|
4
|
+
export type RequestSuccessResponse<E> = {
|
|
5
|
+
data: E;
|
|
6
|
+
count?: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* A {@link RequestSuccessResponse} whose `count` is always present - what `findManyAndCount` sends.
|
|
10
|
+
*/
|
|
11
|
+
export type RequestCountedSuccessResponse<E> = RequestSuccessResponse<E> & {
|
|
12
|
+
count: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Which side of the wire a querier sits on. A server querier hands the result back directly, a
|
|
16
|
+
* client one hands back the envelope its transport wrapped it in.
|
|
17
|
+
*/
|
|
18
|
+
export type QuerierTransport = 'server' | 'client';
|
|
19
|
+
/**
|
|
20
|
+
* A querier method's result on the given transport, so one signature serves both:
|
|
21
|
+
* `QuerierResult<'server', User[]>` is `Promise<User[]>` and `QuerierResult<'client', User[]>` is
|
|
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.
|
|
25
|
+
*/
|
|
26
|
+
export type QuerierResult<W extends QuerierTransport, T> = {
|
|
27
|
+
server: Promise<T>;
|
|
28
|
+
client: Promise<RequestSuccessResponse<T>>;
|
|
29
|
+
}[W];
|
|
30
|
+
/**
|
|
31
|
+
* `findManyAndCount`'s result: the one shape the transports disagree on past the envelope, a tuple
|
|
32
|
+
* on the server against a counted envelope on the client.
|
|
33
|
+
*/
|
|
34
|
+
export type QuerierCountedResult<W extends QuerierTransport, T> = {
|
|
35
|
+
server: Promise<[T[], number]>;
|
|
36
|
+
client: Promise<RequestCountedSuccessResponse<T[]>>;
|
|
37
|
+
}[W];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -108,6 +108,12 @@ export type ParsedGroupEntry = {
|
|
|
108
108
|
* through to field filtering and emit a condition on a `$size` *column*.
|
|
109
109
|
*/
|
|
110
110
|
export declare function parseRelationSize(val: unknown): number | QuerySizeComparisonOps | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* The direction a `$sort` orders a to-many relation by its size, or `undefined` when the value is a
|
|
113
|
+
* map of the relation's own fields (which only a to-one can be ordered by). Mirrors
|
|
114
|
+
* {@link parseRelationSize}, the same clause spelled for a filter rather than an ordering.
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseSortByCount(val: unknown): unknown;
|
|
111
117
|
/**
|
|
112
118
|
* Parse the `$group` (grouped columns) and `$agg` (computed aggregates) maps into structured
|
|
113
119
|
* entries consumable by any dialect. Grouped columns come first, then computed columns.
|
|
@@ -290,6 +290,21 @@ export function parseRelationSize(val) {
|
|
|
290
290
|
}
|
|
291
291
|
return val.$size;
|
|
292
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* The direction a `$sort` orders a to-many relation by its size, or `undefined` when the value is a
|
|
295
|
+
* map of the relation's own fields (which only a to-one can be ordered by). Mirrors
|
|
296
|
+
* {@link parseRelationSize}, the same clause spelled for a filter rather than an ordering.
|
|
297
|
+
*/
|
|
298
|
+
export function parseSortByCount(val) {
|
|
299
|
+
if (!val || typeof val !== 'object' || !('$count' in val)) {
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
const siblings = getKeys(val).filter((key) => key !== '$count');
|
|
303
|
+
if (siblings.length) {
|
|
304
|
+
throw new TypeError(`$count in a $sort cannot be combined with other keys: ${siblings.join(', ')}`);
|
|
305
|
+
}
|
|
306
|
+
return val.$count;
|
|
307
|
+
}
|
|
293
308
|
/**
|
|
294
309
|
* Parse the `$group` (grouped columns) and `$agg` (computed aggregates) maps into structured
|
|
295
310
|
* entries consumable by any dialect. Grouped columns come first, then computed columns.
|
|
@@ -9,6 +9,15 @@ export type RelationRequestSummary<E> = {
|
|
|
9
9
|
* the one field it reads, so it answers for a relation being declared as well as for a resolved one.
|
|
10
10
|
*/
|
|
11
11
|
export declare function isToManyRelation(relation: Pick<RelationMeta, 'cardinality'>): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* The column holding the parent's id: a junction's own for a relation that goes through one, the
|
|
14
|
+
* child's foreign key otherwise. The two are spelled from opposite ends - `local` names a column of
|
|
15
|
+
* the table the relation is declared to write, `foreign` a column of the other one - and getting
|
|
16
|
+
* that backwards reads a real column of the wrong table, so it is answered once here.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parentKeyColumn(relOpts: Pick<RelationMeta, 'references' | 'through'>): string;
|
|
19
|
+
/** The column on a junction table holding the target's id, the other half of {@link parentKeyColumn}. */
|
|
20
|
+
export declare function targetKeyColumn(relOpts: Pick<RelationMeta, 'references'>): string;
|
|
12
21
|
/**
|
|
13
22
|
* What a joined relation cannot carry, and why. A to-many is loaded by a query of its own, which is
|
|
14
23
|
* what gives these four a meaning there; a to-one is one row of the parent's, so every backend used
|
|
@@ -7,6 +7,19 @@ import { getKeys, someKey } from './object.util.js';
|
|
|
7
7
|
export function isToManyRelation(relation) {
|
|
8
8
|
return relation.cardinality === '1m' || relation.cardinality === 'mm';
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* The column holding the parent's id: a junction's own for a relation that goes through one, the
|
|
12
|
+
* child's foreign key otherwise. The two are spelled from opposite ends - `local` names a column of
|
|
13
|
+
* the table the relation is declared to write, `foreign` a column of the other one - and getting
|
|
14
|
+
* that backwards reads a real column of the wrong table, so it is answered once here.
|
|
15
|
+
*/
|
|
16
|
+
export function parentKeyColumn(relOpts) {
|
|
17
|
+
return relOpts.through ? relOpts.references[0].local : relOpts.references[0].foreign;
|
|
18
|
+
}
|
|
19
|
+
/** The column on a junction table holding the target's id, the other half of {@link parentKeyColumn}. */
|
|
20
|
+
export function targetKeyColumn(relOpts) {
|
|
21
|
+
return relOpts.references[1].local;
|
|
22
|
+
}
|
|
10
23
|
/**
|
|
11
24
|
* What a joined relation cannot carry, and why. A to-many is loaded by a query of its own, which is
|
|
12
25
|
* what gives these four a meaning there; a to-one is one row of the parent's, so every backend used
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"homepage": "https://uql-orm.dev",
|
|
4
4
|
"description": "JSON-native ORM for Node.js, Bun and Deno. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.37.1",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=24"
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"devDependencies": {
|
|
131
131
|
"@electric-sql/pglite": "0.5.8",
|
|
132
132
|
"@electric-sql/pglite-pgvector": "0.0.9",
|
|
133
|
-
"@libsql/client": "^0.
|
|
133
|
+
"@libsql/client": "^0.18.0",
|
|
134
134
|
"@neondatabase/serverless": "^1.1.0",
|
|
135
135
|
"@nestjs/common": "^12.0.1",
|
|
136
136
|
"@nestjs/core": "^12.0.1",
|
|
@@ -143,9 +143,9 @@
|
|
|
143
143
|
"@types/ws": "^8.18.1",
|
|
144
144
|
"better-sqlite3": "^13.0.3",
|
|
145
145
|
"express": "^5.2.1",
|
|
146
|
-
"mariadb": "^3.5.
|
|
146
|
+
"mariadb": "^3.5.4",
|
|
147
147
|
"mongodb": "^7.6.0",
|
|
148
|
-
"mysql2": "^3.24.
|
|
148
|
+
"mysql2": "^3.24.3",
|
|
149
149
|
"pg": "^8.23.0",
|
|
150
150
|
"pg-query-stream": "^4.17.0",
|
|
151
151
|
"rxjs": "^7.8.2",
|