uql-orm 0.24.0 → 0.24.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/README.md +1 -1
- package/dist/entity/metadata/definition.js +14 -6
- package/dist/type/entity.d.ts +16 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ from the browser to the server. The same object runs on every supported database
|
|
|
50
50
|
|
|
51
51
|
## Why UQL?
|
|
52
52
|
|
|
53
|
-
- **The fastest.** Wins [all 8 categories](https://uql-orm.dev/benchmark) of our [open benchmark](https://github.com/rogerpadilla/ts-orm-benchmark), beating even query builders like Knex and Kysely: ~2.
|
|
53
|
+
- **The fastest.** Wins [all 8 categories](https://uql-orm.dev/benchmark) of our [open benchmark](https://github.com/rogerpadilla/ts-orm-benchmark), beating even query builders like Knex and Kysely: ~2.4× faster than the runner-up on average, over 4.6M ops/s on simple SELECTs.
|
|
54
54
|
- **Light.** Zero dependencies, under 1 MB installed, every dialect included.
|
|
55
55
|
- **Queries are data, not method chains.** Plain JSON in, typed rows out. There's no DSL to learn and nothing to compile.
|
|
56
56
|
- **Type-safe to the leaf.** Operators are gated per field type, and JSON/JSONB dot-paths resolve each path's value type, so `{ age: { $like: 'x' } }` or a typo'd path is a compile error instead of a runtime surprise.
|
|
@@ -227,7 +227,14 @@ function fillRelations(meta) {
|
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
229
|
if (relOpts.through) {
|
|
230
|
-
|
|
230
|
+
const throughEntity = relOpts.through();
|
|
231
|
+
const throughMeta = fillThroughRelations(throughEntity);
|
|
232
|
+
for (const { local } of relOpts.references) {
|
|
233
|
+
if (throughMeta.fields[local])
|
|
234
|
+
continue;
|
|
235
|
+
throw new TypeError(`'${meta.entity.name}.${relKey}' joins through '${throughEntity.name}', which has no '${local}' ` +
|
|
236
|
+
"field. Declare it, or name the join columns yourself with 'references'.");
|
|
237
|
+
}
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
return meta;
|
|
@@ -254,8 +261,11 @@ function fillInverseSideRelations(relOpts) {
|
|
|
254
261
|
foreign: local,
|
|
255
262
|
}));
|
|
256
263
|
}
|
|
264
|
+
// `getMeta` rather than `ensureMeta`: a pivot that declares its sides as relations rather than as
|
|
265
|
+
// `@Field({ references })` columns gets those foreign-key columns auto-created there, and the caller
|
|
266
|
+
// checks its own derived join columns against them.
|
|
257
267
|
function fillThroughRelations(entity) {
|
|
258
|
-
const meta =
|
|
268
|
+
const meta = getMeta(entity);
|
|
259
269
|
meta.relations = getKeys(meta.fields).reduce((relations, key) => {
|
|
260
270
|
const field = meta.fields[key];
|
|
261
271
|
if (!field)
|
|
@@ -274,6 +284,7 @@ function fillThroughRelations(entity) {
|
|
|
274
284
|
}
|
|
275
285
|
return relations;
|
|
276
286
|
}, {});
|
|
287
|
+
return meta;
|
|
277
288
|
}
|
|
278
289
|
function getMappedByRelationKey(relOpts) {
|
|
279
290
|
if (typeof relOpts.mappedBy === 'function') {
|
|
@@ -286,10 +297,7 @@ function getMappedByRelationKey(relOpts) {
|
|
|
286
297
|
}
|
|
287
298
|
function getRelationKeyMap(meta) {
|
|
288
299
|
const keys = [...getKeys(meta.fields), ...getKeys(meta.relations)];
|
|
289
|
-
return keys.
|
|
290
|
-
acc[key] = key;
|
|
291
|
-
return acc;
|
|
292
|
-
}, {});
|
|
300
|
+
return Object.fromEntries(keys.map((key) => [key, key]));
|
|
293
301
|
}
|
|
294
302
|
function getIdKey(meta) {
|
|
295
303
|
const id = getKeys(meta.fields).find((key) => meta.fields[key]?.isId);
|
package/dist/type/entity.d.ts
CHANGED
|
@@ -350,16 +350,28 @@ export type RelationOptions<E = any> = {
|
|
|
350
350
|
cardinality: RelationCardinality;
|
|
351
351
|
readonly cascade?: boolean | CascadeType;
|
|
352
352
|
mappedBy?: RelationMappedBy<E>;
|
|
353
|
-
|
|
353
|
+
/**
|
|
354
|
+
* The pivot entity of a many-to-many. Unconstrained by `E`: a pivot holds foreign keys to both
|
|
355
|
+
* sides and is not a relation value of the target, so nothing about it is derivable from `E`.
|
|
356
|
+
*/
|
|
357
|
+
through?: EntityGetter;
|
|
354
358
|
references?: RelationReferences;
|
|
355
359
|
};
|
|
356
360
|
type RelationOptionsOwner<E> = Pick<RelationOptions<E>, 'entity' | 'references' | 'cascade'>;
|
|
357
361
|
type RelationOptionsInverseSide<E> = Required<Pick<RelationOptions<E>, 'entity' | 'mappedBy'>> & Pick<RelationOptions<E>, 'cascade'>;
|
|
358
362
|
type RelationOptionsThroughOwner<E> = Required<Pick<RelationOptions<E>, 'entity'>> & Pick<RelationOptions<E>, 'through' | 'references' | 'cascade'>;
|
|
363
|
+
/**
|
|
364
|
+
* The key names of `E` as values, so `mappedBy` can be written as `(user) => user.company` instead of
|
|
365
|
+
* a string literal and survive a rename.
|
|
366
|
+
*
|
|
367
|
+
* Mapping over `Key<E>` rather than `keyof E` is what makes the callback usable: a homomorphic
|
|
368
|
+
* `[K in keyof E]` inherits the entity's optional modifiers, so `user.company` is
|
|
369
|
+
* `'company' | undefined` and {@link RelationKeyMapper} rejects it - every callback needed a `!`. The
|
|
370
|
+
* map is built from the target's metadata (see `getRelationKeyMap`), where every key is present and
|
|
371
|
+
* every key is a string.
|
|
372
|
+
*/
|
|
359
373
|
export type RelationKeyMap<E> = {
|
|
360
|
-
readonly [K in
|
|
361
|
-
} & {
|
|
362
|
-
readonly [key: string]: string;
|
|
374
|
+
readonly [K in Key<E>]: K;
|
|
363
375
|
};
|
|
364
376
|
export type RelationKeyMapper<E> = (keyMap: RelationKeyMap<E>) => Key<E>;
|
|
365
377
|
export type RelationReferences = {
|
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.24.
|
|
6
|
+
"version": "0.24.1",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=24"
|
|
@@ -198,5 +198,5 @@
|
|
|
198
198
|
"publishConfig": {
|
|
199
199
|
"access": "public"
|
|
200
200
|
},
|
|
201
|
-
"gitHead": "
|
|
201
|
+
"gitHead": "7f11b72301d647853c7a2778daaa09af8f4d5695"
|
|
202
202
|
}
|