uql-orm 0.26.3 → 0.28.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/README.md +4 -4
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +3 -3
- package/dist/cockroachdb/cockroachDialect.d.ts +5 -0
- package/dist/cockroachdb/cockroachDialect.js +5 -0
- package/dist/dialect/abstractSqlDialect.d.ts +81 -40
- package/dist/dialect/abstractSqlDialect.js +317 -305
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +4 -1
- package/dist/dialect/mysqlLikeSqlDialect.js +4 -3
- package/dist/dialect/pgLikeSqlDialect.d.ts +1 -1
- package/dist/dialect/pgLikeSqlDialect.js +1 -3
- package/dist/dialect/queryContext.d.ts +7 -5
- package/dist/dialect/queryContext.js +11 -6
- package/dist/dialect/queryJoins.d.ts +44 -0
- package/dist/dialect/queryJoins.js +73 -0
- package/dist/dialect/vectorSqlDialect.d.ts +1 -1
- package/dist/http/query.js +10 -0
- package/dist/maria/mariaDialect.d.ts +2 -0
- package/dist/maria/mariaDialect.js +2 -0
- package/dist/mongo/mongoDialect.d.ts +14 -2
- package/dist/mongo/mongoDialect.js +56 -18
- package/dist/mongo/mongodbQuerier.js +6 -2
- package/dist/querier/abstractSqlQuerier.d.ts +11 -0
- package/dist/querier/abstractSqlQuerier.js +21 -0
- package/dist/sqlite/sqliteDialect.d.ts +3 -1
- package/dist/sqlite/sqliteDialect.js +5 -3
- package/dist/type/dialect.d.ts +11 -3
- package/dist/type/entity.d.ts +4 -4
- package/dist/type/index.d.ts +1 -0
- package/dist/type/index.js +1 -0
- package/dist/type/query.d.ts +15 -4
- package/dist/type/queryLock.d.ts +21 -0
- package/dist/type/queryLock.js +19 -0
- package/dist/type/utility.d.ts +9 -5
- package/dist/util/dialect.util.d.ts +1 -2
- package/dist/util/dialect.util.js +0 -3
- package/dist/util/relationQuery.util.d.ts +15 -3
- package/dist/util/relationQuery.util.js +37 -2
- package/dist/util/sql.util.d.ts +1 -2
- package/dist/util/sql.util.js +1 -12
- package/package.json +4 -4
package/dist/type/entity.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ForeignKeyAction, IndexType } from '../schema/types.js';
|
|
2
2
|
import type { FilterOptions } from './query.js';
|
|
3
3
|
import type { QueryRaw } from './queryRaw.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { Except, Json, Scalar, Type, Unpacked } from './utility.js';
|
|
5
5
|
import type { VectorDistance, VectorIndexOptions, VectorIndexType } from './vector.js';
|
|
6
6
|
/**
|
|
7
7
|
* Allow to customize the name of the property that identifies an entity
|
|
@@ -579,10 +579,10 @@ export type EntityOptions<E = unknown> = {
|
|
|
579
579
|
};
|
|
580
580
|
/**
|
|
581
581
|
* Everything an index carries beyond its columns, shared by `@Index`, `defineEntity` and the
|
|
582
|
-
* migration builder's `table.index(...)`. `
|
|
583
|
-
*
|
|
582
|
+
* migration builder's `table.index(...)`. `Except` (not plain `Omit`) keeps `type`/`distance` a
|
|
583
|
+
* discriminated pair: omitting `distance` on a vector index type is a compile error.
|
|
584
584
|
*/
|
|
585
|
-
export type IndexOptions =
|
|
585
|
+
export type IndexOptions = Except<EntityIndexMeta, 'columns'>;
|
|
586
586
|
/**
|
|
587
587
|
* An index as authored, before `defineIndex` normalizes its columns.
|
|
588
588
|
*/
|
package/dist/type/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './querier.js';
|
|
|
9
9
|
export * from './querierPool.js';
|
|
10
10
|
export * from './query.js';
|
|
11
11
|
export * from './queryAggregate.js';
|
|
12
|
+
export * from './queryLock.js';
|
|
12
13
|
export * from './queryRaw.js';
|
|
13
14
|
export * from './queryWhere.js';
|
|
14
15
|
export * from './universalQuerier.js';
|
package/dist/type/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from './querier.js';
|
|
|
9
9
|
export * from './querierPool.js';
|
|
10
10
|
export * from './query.js';
|
|
11
11
|
export * from './queryAggregate.js';
|
|
12
|
+
export * from './queryLock.js';
|
|
12
13
|
export * from './queryRaw.js';
|
|
13
14
|
export * from './queryWhere.js';
|
|
14
15
|
export * from './universalQuerier.js';
|
package/dist/type/query.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { FieldKey, JsonFieldPaths, RelationKey } from './entity.js';
|
|
2
|
+
import type { QueryLock } from './queryLock.js';
|
|
2
3
|
import type { QueryRaw } from './queryRaw.js';
|
|
3
4
|
import type { QueryWhere } from './queryWhere.js';
|
|
4
|
-
import type { BooleanLike, PrimaryKey, Unpacked } from './utility.js';
|
|
5
|
+
import type { BooleanLike, Except, PrimaryKey, Unpacked } from './utility.js';
|
|
5
6
|
import type { QueryVectorSearch } from './vector.js';
|
|
6
7
|
export type QueryOptions = {
|
|
7
8
|
/**
|
|
@@ -65,7 +66,7 @@ export type QueryConflictPaths<E> = {
|
|
|
65
66
|
/**
|
|
66
67
|
* options to populate a relation.
|
|
67
68
|
*/
|
|
68
|
-
export type QueryPopulateRelationOptions<E> = (E extends unknown[] ? Query<Unpacked<E
|
|
69
|
+
export type QueryPopulateRelationOptions<E> = (E extends unknown[] ? Except<Query<Unpacked<E>>, '$lock'> : QueryUnique<Unpacked<E>>) & {
|
|
69
70
|
$required?: boolean;
|
|
70
71
|
};
|
|
71
72
|
/**
|
|
@@ -125,7 +126,7 @@ export type QuerySortMap<E> = {
|
|
|
125
126
|
} & {
|
|
126
127
|
[P in JsonFieldPaths<E>]?: QuerySortDirection;
|
|
127
128
|
} & {
|
|
128
|
-
[K in RelationKey<E>]?: QuerySortMap<NonNullable<
|
|
129
|
+
[K in RelationKey<E> as NonNullable<E[K]> extends readonly unknown[] ? never : K]?: QuerySortMap<NonNullable<E[K]>>;
|
|
129
130
|
};
|
|
130
131
|
/**
|
|
131
132
|
* pager options.
|
|
@@ -180,11 +181,21 @@ export type Query<E> = {
|
|
|
180
181
|
* whether to return only distinct rows.
|
|
181
182
|
*/
|
|
182
183
|
$distinct?: boolean;
|
|
184
|
+
/**
|
|
185
|
+
* take a row-level lock on the rows this query returns (`SELECT ... FOR UPDATE`). Needs an open
|
|
186
|
+
* transaction: outside one the statement commits and drops the lock before the caller can act on
|
|
187
|
+
* the rows, so it is rejected rather than emitted. Locks only the queried entity, never anything
|
|
188
|
+
* reached through `$populate`. SQL only; MongoDB and the SQLite family reject it.
|
|
189
|
+
*
|
|
190
|
+
* Deliberately declared here rather than on `QuerySearch`, which `count`/`update`/`delete` take:
|
|
191
|
+
* that placement is what keeps the clause off those statements at the type level.
|
|
192
|
+
*/
|
|
193
|
+
$lock?: QueryLock;
|
|
183
194
|
} & QuerySearch<E>;
|
|
184
195
|
/**
|
|
185
196
|
* options to get a single record.
|
|
186
197
|
*/
|
|
187
|
-
export type QueryOne<E> =
|
|
198
|
+
export type QueryOne<E> = Except<Query<E>, '$limit'>;
|
|
188
199
|
/**
|
|
189
200
|
* options to get an unique record.
|
|
190
201
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
declare const QUERY_LOCK_WAITS: readonly ['block', 'nowait', 'skip'];
|
|
2
|
+
/**
|
|
3
|
+
* What to do about a row someone else already holds. `block` (the default) waits for them; `nowait`
|
|
4
|
+
* fails the statement at once; `skip` leaves the row out of the result, which is what makes a
|
|
5
|
+
* work-queue possible: each worker takes rows nobody else has.
|
|
6
|
+
*/
|
|
7
|
+
export type QueryLockWait = (typeof QUERY_LOCK_WAITS)[number];
|
|
8
|
+
/**
|
|
9
|
+
* `true` takes the lock and waits for anyone holding the rows; the object form chooses what to do
|
|
10
|
+
* instead of waiting. `false` takes none, so a query built conditionally needs no branch.
|
|
11
|
+
*/
|
|
12
|
+
export type QueryLock = boolean | {
|
|
13
|
+
readonly wait?: QueryLockWait;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The wait policy this lock resolves to, or `undefined` when there is no lock. An unknown policy
|
|
17
|
+
* throws here rather than reaching a dialect, so the message names what the caller wrote instead of
|
|
18
|
+
* the SQL it would have produced.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseQueryLock(lock: QueryLock | undefined): QueryLockWait | undefined;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const QUERY_LOCK_WAITS = ['block', 'nowait', 'skip'];
|
|
2
|
+
function isOneOf(vals, val) {
|
|
3
|
+
return vals.includes(val);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* The wait policy this lock resolves to, or `undefined` when there is no lock. An unknown policy
|
|
7
|
+
* throws here rather than reaching a dialect, so the message names what the caller wrote instead of
|
|
8
|
+
* the SQL it would have produced.
|
|
9
|
+
*/
|
|
10
|
+
export function parseQueryLock(lock) {
|
|
11
|
+
if (lock === undefined || lock === false) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const wait = lock === true ? 'block' : (lock?.wait ?? 'block');
|
|
15
|
+
if (!isOneOf(QUERY_LOCK_WAITS, wait)) {
|
|
16
|
+
throw new TypeError(`unknown $lock wait policy: ${String(wait)}`);
|
|
17
|
+
}
|
|
18
|
+
return wait;
|
|
19
|
+
}
|
package/dist/type/utility.d.ts
CHANGED
|
@@ -47,10 +47,14 @@ export type Writable<T> = {
|
|
|
47
47
|
-readonly [K in keyof T]: T[K];
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
|
-
* `Omit`,
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* `type`/`distance` pairing) into
|
|
50
|
+
* `Omit`, fixed on three counts. Its key has to exist, where `Omit<T, K extends keyof any>` lets a
|
|
51
|
+
* typo or a renamed property silently omit nothing. Being a homomorphic mapped type it distributes
|
|
52
|
+
* over unions, where `Omit` intersects each member's keys and flattens a discriminated union (e.g.
|
|
53
|
+
* `EntityIndexMeta`'s `type`/`distance` pairing) into one non-discriminated shape. And it removes
|
|
54
|
+
* the key from types carrying an index signature, where `Exclude<keyof T, K>` widens back to
|
|
55
|
+
* `string | number` and leaves the key in place.
|
|
54
56
|
*/
|
|
55
|
-
export type
|
|
57
|
+
export type Except<T, K extends keyof T> = {
|
|
58
|
+
[P in keyof T as P extends K ? never : P]: T[P];
|
|
59
|
+
};
|
|
56
60
|
export type Unpacked<T> = T extends readonly (infer U)[] ? U : T extends (...args: unknown[]) => infer U ? U : T extends Promise<infer U> ? U : T;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CascadeType, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type
|
|
1
|
+
import { type CascadeType, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QueryVectorSearch, type QueryWhere, type QueryWhereMap, type RelationKey } from '../type/index.js';
|
|
2
2
|
export type CallbackKey = keyof Pick<FieldOptions, 'onInsert' | 'onUpdate'>;
|
|
3
3
|
export declare function filterFieldKeys<E>(meta: EntityMeta<E>, payload: E, callbackKey: CallbackKey): FieldKey<E>[];
|
|
4
4
|
/**
|
|
@@ -47,7 +47,6 @@ export declare function isCascadable(action: CascadeType, configuration?: boolea
|
|
|
47
47
|
*/
|
|
48
48
|
export declare function asSelectMap<E>(select: QuerySelectValue<E> | undefined): QuerySelect<E> | undefined;
|
|
49
49
|
export declare function normalizeScalarFieldSelection<E>(meta: EntityMeta<E>, select?: QuerySelect<E>, exclude?: QueryExclude<E>): FieldKey<E>[];
|
|
50
|
-
export declare function buildSortMap<E>(sort: QuerySortMap<E> | undefined): QuerySortMap<E>;
|
|
51
50
|
/** Type guard: checks whether a sort value is a vector similarity search. */
|
|
52
51
|
export declare function isVectorSearch(value: unknown): value is QueryVectorSearch;
|
|
53
52
|
/** Type guard: checks whether an update payload value is a JSON operator object. */
|
|
@@ -141,9 +141,6 @@ export function normalizeScalarFieldSelection(meta, select, exclude) {
|
|
|
141
141
|
const excluded = excludedFields;
|
|
142
142
|
return allFields.filter((it) => !excluded.has(it));
|
|
143
143
|
}
|
|
144
|
-
export function buildSortMap(sort) {
|
|
145
|
-
return (sort ?? {});
|
|
146
|
-
}
|
|
147
144
|
/** Type guard: checks whether a sort value is a vector similarity search. */
|
|
148
145
|
export function isVectorSearch(value) {
|
|
149
146
|
return value !== null && typeof value === 'object' && '$vector' in value;
|
|
@@ -1,13 +1,24 @@
|
|
|
1
|
-
import type { EntityMeta, Query, QueryPopulate, RelationKey } from '../type/index.js';
|
|
1
|
+
import type { EntityMeta, Except, Query, QueryPopulate, RelationKey, RelationMeta } from '../type/index.js';
|
|
2
2
|
export type RelationRequestSummary<E> = {
|
|
3
3
|
readonly requestedKeys: RelationKey<E>[];
|
|
4
4
|
readonly joinableKeys: RelationKey<E>[];
|
|
5
5
|
readonly toManyKeys: RelationKey<E>[];
|
|
6
6
|
};
|
|
7
|
+
/** Whether a relation holds many rows per parent, so it cannot be joined into the parent's row. */
|
|
8
|
+
export declare function isToManyRelation(relation: RelationMeta): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* What a joined relation cannot carry, and why. A to-many is loaded by a query of its own, which is
|
|
11
|
+
* what gives these four a meaning there; a to-one is one row of the parent's, so every backend used
|
|
12
|
+
* to drop them without a word. `satisfies` ties each key to {@link RelationQuery}, so renaming one
|
|
13
|
+
* breaks this list at compile time rather than quietly stopping the check.
|
|
14
|
+
*/
|
|
15
|
+
declare const JOINED_RELATION_REJECTIONS: readonly [readonly ["$sort", "a join brings one row per parent, so there is nothing to order"], readonly ["$limit", "a join brings one row per parent, so there is nothing to page"], readonly ["$skip", "a join brings one row per parent, so there is nothing to page"], readonly ["$distinct", "it applies to the whole statement, not to one of its joins"]];
|
|
16
|
+
/** A key only a to-many's own query can carry, and that a joined relation therefore rejects. */
|
|
17
|
+
export type JoinedRelationRejectedKey = (typeof JOINED_RELATION_REJECTIONS)[number][0];
|
|
7
18
|
export declare function getRelationRequestSummary<E>(meta: EntityMeta<E>, populate?: QueryPopulate<E>): RelationRequestSummary<E>;
|
|
8
19
|
/** True when `$populate` includes at least one relation key. */
|
|
9
|
-
export declare function
|
|
10
|
-
export type RelationQuery<E extends object = object> = Query<E> & {
|
|
20
|
+
export declare function populatesRelations<E>(meta: EntityMeta<E>, populate?: QueryPopulate<E>): boolean;
|
|
21
|
+
export type RelationQuery<E extends object = object> = Except<Query<E>, '$lock'> & {
|
|
11
22
|
$required?: boolean;
|
|
12
23
|
};
|
|
13
24
|
export type ParsedRelationQuery<E extends object = object> = {
|
|
@@ -20,3 +31,4 @@ export declare function parseRelationQueryValue<E extends object = object>(value
|
|
|
20
31
|
/** Parses the relation payload for `relKey` */
|
|
21
32
|
export declare function parseRelationAtKey<E>(relKey: RelationKey<E>, populate?: QueryPopulate<E>): ParsedRelationQuery;
|
|
22
33
|
export declare function forEachRequestedRelation<E extends object>(meta: EntityMeta<E>, populate: QueryPopulate<E> | undefined, fn: (relKey: RelationKey<E>, rawValue: unknown) => void): void;
|
|
34
|
+
export {};
|
|
@@ -1,4 +1,31 @@
|
|
|
1
1
|
import { getKeys } from './object.util.js';
|
|
2
|
+
/** Whether a relation holds many rows per parent, so it cannot be joined into the parent's row. */
|
|
3
|
+
export function isToManyRelation(relation) {
|
|
4
|
+
return relation.cardinality === '1m' || relation.cardinality === 'mm';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* What a joined relation cannot carry, and why. A to-many is loaded by a query of its own, which is
|
|
8
|
+
* what gives these four a meaning there; a to-one is one row of the parent's, so every backend used
|
|
9
|
+
* to drop them without a word. `satisfies` ties each key to {@link RelationQuery}, so renaming one
|
|
10
|
+
* breaks this list at compile time rather than quietly stopping the check.
|
|
11
|
+
*/
|
|
12
|
+
const JOINED_RELATION_REJECTIONS = [
|
|
13
|
+
['$sort', 'a join brings one row per parent, so there is nothing to order'],
|
|
14
|
+
['$limit', 'a join brings one row per parent, so there is nothing to page'],
|
|
15
|
+
['$skip', 'a join brings one row per parent, so there is nothing to page'],
|
|
16
|
+
['$distinct', 'it applies to the whole statement, not to one of its joins'],
|
|
17
|
+
];
|
|
18
|
+
const JOINED_RELATION_REJECTED_KEYS = new Map(JOINED_RELATION_REJECTIONS);
|
|
19
|
+
function assertJoinableRelationQuery(relKey, value) {
|
|
20
|
+
if (!value || typeof value !== 'object') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const [key, reason] of JOINED_RELATION_REJECTED_KEYS) {
|
|
24
|
+
if (key in value) {
|
|
25
|
+
throw new TypeError(`'${key}' is not supported inside $populate of the to-one relation '${relKey}': ${reason}.`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
2
29
|
export function getRelationRequestSummary(meta, populate) {
|
|
3
30
|
const requestedKeys = [];
|
|
4
31
|
const joinableKeys = [];
|
|
@@ -12,17 +39,20 @@ export function getRelationRequestSummary(meta, populate) {
|
|
|
12
39
|
if (!relOpts)
|
|
13
40
|
continue;
|
|
14
41
|
requestedKeys.push(key);
|
|
15
|
-
if (relOpts
|
|
42
|
+
if (isToManyRelation(relOpts)) {
|
|
16
43
|
toManyKeys.push(key);
|
|
17
44
|
}
|
|
18
45
|
else {
|
|
46
|
+
// Validated where the cardinality is decided, so every backend and every nesting level rejects
|
|
47
|
+
// the same shapes - the SQL dialects, MongoDB's lookups, and whatever reads this summary next.
|
|
48
|
+
assertJoinableRelationQuery(key, populate[key]);
|
|
19
49
|
joinableKeys.push(key);
|
|
20
50
|
}
|
|
21
51
|
}
|
|
22
52
|
return { requestedKeys, joinableKeys, toManyKeys };
|
|
23
53
|
}
|
|
24
54
|
/** True when `$populate` includes at least one relation key. */
|
|
25
|
-
export function
|
|
55
|
+
export function populatesRelations(meta, populate) {
|
|
26
56
|
if (!populate)
|
|
27
57
|
return false;
|
|
28
58
|
return getKeys(populate).some((key) => populate[key] && key in meta.relations);
|
|
@@ -41,6 +71,11 @@ function isRelationQueryObject(value) {
|
|
|
41
71
|
return isRecord(value) && isValidRelationQueryShape(value);
|
|
42
72
|
}
|
|
43
73
|
export function parseRelationQueryValue(value) {
|
|
74
|
+
// Caught before the shape check so the message names the key, rather than reporting the whole
|
|
75
|
+
// object as an unrecognized relation query value.
|
|
76
|
+
if (isRecord(value) && '$lock' in value) {
|
|
77
|
+
throw new TypeError("'$lock' applies to the whole statement, not to a populated relation. Move it to the top level of the query.");
|
|
78
|
+
}
|
|
44
79
|
if (isRelationQueryObject(value)) {
|
|
45
80
|
return { query: value, required: value.$required === true, nested: true };
|
|
46
81
|
}
|
package/dist/util/sql.util.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { InsertIdSource, QueryUpdateResult, RawRow } from '../type/index.js';
|
|
2
2
|
import type { PrimaryKey } from '../type/utility.js';
|
|
3
|
-
export declare function flatObject<E extends object>(obj: E, pre?: string): E;
|
|
4
3
|
export declare function unflatObjects<T extends object>(objects: RawRow[]): T[];
|
|
5
4
|
/**
|
|
6
5
|
* Unflattens a single raw row using pre-computed attribute paths.
|
|
@@ -17,7 +16,7 @@ export declare function obtainAttrsPaths<T extends object>(row: T): {
|
|
|
17
16
|
* @param forbidQualified whether to forbid qualified identifiers (containing dots)
|
|
18
17
|
* @param addDot whether to add a dot suffix
|
|
19
18
|
*/
|
|
20
|
-
export declare function escapeSqlId(val: string, escapeIdChar?: '`' | '"', forbidQualified?: boolean, addDot?: boolean): string;
|
|
19
|
+
export declare function escapeSqlId(val: string | undefined, escapeIdChar?: '`' | '"', forbidQualified?: boolean, addDot?: boolean): string;
|
|
21
20
|
/**
|
|
22
21
|
* Payload for building a QueryUpdateResult.
|
|
23
22
|
*/
|
package/dist/util/sql.util.js
CHANGED
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hasKeys } from './object.util.js';
|
|
2
2
|
/** Pre-computed regex for each SQL identifier escape character to avoid per-call allocation. */
|
|
3
3
|
const escapeIdRegexCache = { '`': /`/g, '"': /"/g };
|
|
4
|
-
export function flatObject(obj, pre) {
|
|
5
|
-
return getKeys(obj).reduce((acc, key) => flatObjectEntry(acc, key, obj[key], typeof obj[key] === 'object' ? '' : pre), {});
|
|
6
|
-
}
|
|
7
|
-
function flatObjectEntry(map, key, val, pre) {
|
|
8
|
-
const prefix = pre ? `${pre}.${key}` : key;
|
|
9
|
-
if (typeof val === 'object' && val !== null) {
|
|
10
|
-
return getKeys(val).reduce((acc, prop) => flatObjectEntry(acc, prop, val[prop], prefix), map);
|
|
11
|
-
}
|
|
12
|
-
map[prefix] = val;
|
|
13
|
-
return map;
|
|
14
|
-
}
|
|
15
4
|
export function unflatObjects(objects) {
|
|
16
5
|
if (!Array.isArray(objects) || !objects.length) {
|
|
17
6
|
return objects;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"homepage": "https://uql-orm.dev",
|
|
4
4
|
"description": "Extremely fast, type-safe TypeScript ORM - one API for every database",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.28.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=24"
|
|
@@ -127,9 +127,9 @@
|
|
|
127
127
|
"devDependencies": {
|
|
128
128
|
"@libsql/client": "^0.17.4",
|
|
129
129
|
"@neondatabase/serverless": "^1.1.0",
|
|
130
|
-
"@nestjs/common": "^11.1
|
|
131
|
-
"@nestjs/core": "^11.1
|
|
132
|
-
"@nestjs/testing": "^11.1
|
|
130
|
+
"@nestjs/common": "^11.2.1",
|
|
131
|
+
"@nestjs/core": "^11.2.1",
|
|
132
|
+
"@nestjs/testing": "^11.2.1",
|
|
133
133
|
"@tursodatabase/database": "^0.7.2",
|
|
134
134
|
"@tursodatabase/serverless": "^1.4.0",
|
|
135
135
|
"@types/better-sqlite3": "^9.6.0",
|