uql-orm 0.56.0 → 0.58.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 +7 -9
- package/dist/browser/uql-browser.min.js +2 -2
- package/dist/browser/uql-browser.min.js.map +4 -4
- package/dist/cockroachdb/cockroachDialect.d.ts +5 -2
- package/dist/cockroachdb/cockroachDialect.js +2 -10
- package/dist/d1/d1SqliteDialect.d.ts +1 -0
- package/dist/d1/d1SqliteDialect.js +2 -0
- package/dist/dialect/abstractSqlDialect.d.ts +196 -33
- package/dist/dialect/abstractSqlDialect.js +410 -203
- package/dist/dialect/aliases.d.ts +10 -7
- package/dist/dialect/aliases.js +12 -7
- package/dist/dialect/hydrateColumn.d.ts +8 -2
- package/dist/dialect/hydrateColumn.js +33 -1
- package/dist/dialect/jsonSql.d.ts +13 -5
- package/dist/dialect/jsonSql.js +24 -7
- package/dist/dialect/mysqlLikeSqlDialect.d.ts +31 -3
- package/dist/dialect/mysqlLikeSqlDialect.js +57 -5
- package/dist/dialect/pgLikeSqlDialect.d.ts +20 -20
- package/dist/dialect/pgLikeSqlDialect.js +23 -48
- package/dist/dialect/pgVectorMetrics.d.ts +13 -0
- package/dist/dialect/pgVectorMetrics.js +17 -0
- package/dist/dialect/queryContext.d.ts +3 -7
- package/dist/dialect/queryContext.js +13 -8
- package/dist/dialect/queryJoins.d.ts +8 -4
- package/dist/dialect/queryJoins.js +26 -11
- package/dist/dialect/vectorSqlDialect.d.ts +2 -2
- package/dist/dialect/vectorSqlDialect.js +2 -3
- package/dist/entity/decorator/bag.d.ts +2 -2
- package/dist/entity/decorator/entity.d.ts +8 -9
- package/dist/entity/decorator/entity.js +6 -7
- package/dist/entity/decorator/members.d.ts +7 -6
- package/dist/entity/decorator/members.js +2 -1
- package/dist/entity/metadata/definition.d.ts +16 -11
- package/dist/entity/metadata/definition.js +54 -42
- package/dist/http/handler.d.ts +2 -2
- package/dist/http/handler.js +0 -1
- package/dist/maria/mariaDialect.d.ts +13 -6
- package/dist/maria/mariaDialect.js +29 -9
- package/dist/migrate/cli.d.ts +2 -3
- package/dist/migrate/cli.js +2 -2
- package/dist/migrate/codegen/entityCodeGenerator.js +6 -4
- package/dist/migrate/codegen/entityTypes.d.ts +1 -1
- package/dist/migrate/codegen/entityTypes.js +4 -3
- package/dist/migrate/codegen/indexDecoratorSource.d.ts +5 -4
- package/dist/migrate/codegen/indexDecoratorSource.js +17 -13
- package/dist/migrate/codegen/sourceLiteral.d.ts +2 -0
- package/dist/migrate/codegen/sourceLiteral.js +4 -0
- package/dist/migrate/ddl/index.d.ts +1 -5
- package/dist/migrate/ddl/index.js +14 -25
- package/dist/migrate/ddl/indexDdl.d.ts +11 -2
- package/dist/migrate/ddl/indexDdl.js +17 -1
- package/dist/migrate/ddl/mssqlIndexDdl.d.ts +10 -0
- package/dist/migrate/ddl/mssqlIndexDdl.js +10 -0
- package/dist/migrate/ddl/mysqlIndexDdl.d.ts +10 -17
- package/dist/migrate/ddl/mysqlIndexDdl.js +16 -27
- package/dist/migrate/ddl/pgIndexDdl.d.ts +18 -8
- package/dist/migrate/ddl/pgIndexDdl.js +29 -12
- package/dist/migrate/generator/mongoSchemaGenerator.d.ts +3 -3
- package/dist/migrate/migrator.d.ts +4 -4
- package/dist/migrate/schemaGenerator.d.ts +8 -8
- package/dist/migrate/schemaGenerator.js +5 -7
- package/dist/migrate/schemaGeneratorAsync.d.ts +2 -3
- package/dist/mongo/mongoDialect.d.ts +31 -18
- package/dist/mongo/mongoDialect.js +146 -104
- package/dist/mongo/mongodbQuerier.d.ts +10 -17
- package/dist/mongo/mongodbQuerier.js +31 -106
- package/dist/mssql/mssqlDialect.d.ts +16 -0
- package/dist/mssql/mssqlDialect.js +26 -4
- package/dist/mysql/mysqlDialect.d.ts +2 -0
- package/dist/mysql/mysqlDialect.js +4 -0
- package/dist/querier/abstractQuerier.d.ts +20 -36
- package/dist/querier/abstractQuerier.js +35 -129
- package/dist/querier/abstractQuerierPool.d.ts +2 -2
- package/dist/querier/abstractSqlQuerier.d.ts +4 -17
- package/dist/querier/abstractSqlQuerier.js +40 -50
- package/dist/schema/canonicalType.js +4 -4
- package/dist/schema/indexDifferences.js +4 -4
- package/dist/schema/schemaASTBuilder.d.ts +3 -3
- package/dist/schema/schemaASTBuilder.js +32 -3
- package/dist/schema/schemaASTDiffer.js +5 -5
- package/dist/sqlite/sqliteDialect.d.ts +20 -1
- package/dist/sqlite/sqliteDialect.js +38 -7
- package/dist/turso/tursoDialect.d.ts +2 -0
- package/dist/turso/tursoDialect.js +2 -0
- package/dist/type/config.d.ts +3 -3
- package/dist/type/dialect.d.ts +4 -5
- package/dist/type/entity.d.ts +110 -69
- package/dist/type/migration.d.ts +7 -7
- package/dist/type/migratorDialect.d.ts +4 -0
- package/dist/type/querier.d.ts +6 -6
- package/dist/type/querierPool.d.ts +2 -2
- package/dist/type/query.d.ts +41 -72
- package/dist/type/query.js +10 -5
- package/dist/type/queryAggregate.d.ts +43 -34
- package/dist/type/queryAggregate.js +1 -1
- package/dist/type/queryWhere.d.ts +12 -9
- package/dist/type/universalQuerier.d.ts +4 -4
- package/dist/util/dialect.util.d.ts +4 -4
- package/dist/util/dialect.util.js +24 -15
- package/dist/util/field.util.d.ts +5 -0
- package/dist/util/field.util.js +19 -0
- package/dist/util/object.util.d.ts +2 -0
- package/dist/util/object.util.js +4 -0
- package/dist/util/relationQuery.util.d.ts +12 -65
- package/dist/util/relationQuery.util.js +27 -81
- package/dist/util/rowKey.util.d.ts +1 -11
- package/dist/util/rowKey.util.js +1 -13
- package/package.json +1 -1
- package/dist/querier/relationCount.d.ts +0 -16
- package/dist/querier/relationCount.js +0 -121
package/dist/type/entity.d.ts
CHANGED
|
@@ -172,10 +172,10 @@ export type EntityData<E> = Pick<E, FieldKey<E> | RelationKey<E>>;
|
|
|
172
172
|
* accept `QueryRaw` or `JsonUpdateOp` (for JSON fields), which gives IDE autocomplete for
|
|
173
173
|
* `$set`/`$push`/`$pull` keys via `Json<infer T>`.
|
|
174
174
|
*/
|
|
175
|
-
export type UpdatePayload<E
|
|
176
|
-
[K in
|
|
175
|
+
export type UpdatePayload<E, F extends keyof E = FieldKey<E>, R extends keyof E = RelationKey<E>> = {
|
|
176
|
+
[K in F]?: UpdateFieldValue<E[K]>;
|
|
177
177
|
} & {
|
|
178
|
-
[K in
|
|
178
|
+
[K in R]?: E[K];
|
|
179
179
|
};
|
|
180
180
|
/**
|
|
181
181
|
* Infers the field values of an entity
|
|
@@ -212,9 +212,7 @@ export type IdKey<E> = ([NamedIdKey<E>] extends [never] ? FieldKey<E> : NamedIdK
|
|
|
212
212
|
*/
|
|
213
213
|
export type IdValue<E> = E[IdKey<E>];
|
|
214
214
|
/** Every column of a key, which is how a composite row is named and what a `$where` reduces to. */
|
|
215
|
-
type IdMap<E> =
|
|
216
|
-
[K in IdKey<E>]?: E[K];
|
|
217
|
-
};
|
|
215
|
+
type IdMap<E> = Partial<Pick<E, IdKey<E>>>;
|
|
218
216
|
/**
|
|
219
217
|
* How a row is addressed by its primary key: the value for a single key, an object carrying every
|
|
220
218
|
* key for a composite - which is also the `$where` map it reduces to, so both spellings are one type.
|
|
@@ -425,7 +423,8 @@ export type FieldOptions<V = TsTypeOf<FieldType>> = {
|
|
|
425
423
|
*/
|
|
426
424
|
readonly autoIncrement?: boolean;
|
|
427
425
|
/**
|
|
428
|
-
*
|
|
426
|
+
* `true` for an index over the column, a string to name it. A foreign key column is indexed unless
|
|
427
|
+
* this is `false`.
|
|
429
428
|
*/
|
|
430
429
|
readonly index?: boolean | string;
|
|
431
430
|
/**
|
|
@@ -477,17 +476,25 @@ export type FieldOptionsFor<V> = (FieldOptions<NonNullable<V>> & {
|
|
|
477
476
|
* The entity a relation field points at: `Company` for both `company?: Company` and
|
|
478
477
|
* `companies?: Company[]`.
|
|
479
478
|
*/
|
|
480
|
-
export type RelationTarget<V> =
|
|
479
|
+
export type RelationTarget<V> = Extract<Unpacked<V>, object>;
|
|
481
480
|
/**
|
|
482
481
|
* {@link RelationOptions} for a relation field declared as `V`, with `entity` required and pinned to
|
|
483
482
|
* `V`'s own type, and the cardinality restricted to the ones that field shape can hold. Together those
|
|
484
483
|
* reject `@ManyToOne({ entity: () => Other })` on a `Company` field, and any to-many cardinality on a
|
|
485
|
-
* field that is not an array.
|
|
484
|
+
* field that is not an array. A to-many additionally needs a {@link RelationJoin}.
|
|
485
|
+
*
|
|
486
|
+
* The join is required through the `cardinality` written rather than through `IsMany<V>`: a conditional
|
|
487
|
+
* member of the intersection leaves a `mappedBy` callback without a contextual type inside a generic
|
|
488
|
+
* call (`defineEntity`), where a union keyed on a property does not.
|
|
486
489
|
*/
|
|
487
|
-
export type RelationOptionsFor<V> = Omit<RelationOptions<RelationTarget<V
|
|
490
|
+
export type RelationOptionsFor<V, O = unknown> = Omit<RelationOptions<RelationTarget<V>, O>, 'entity' | 'cardinality'> & {
|
|
488
491
|
readonly entity: EntityGetter<RelationTarget<V>>;
|
|
489
492
|
readonly cardinality: IsMany<V> extends true ? '1m' | 'mm' : '11' | 'm1';
|
|
490
|
-
} & (
|
|
493
|
+
} & (({
|
|
494
|
+
readonly cardinality: '1m' | 'mm';
|
|
495
|
+
} & RelationJoin<RelationTarget<V>, O>) | {
|
|
496
|
+
readonly cardinality: '11' | 'm1';
|
|
497
|
+
});
|
|
491
498
|
/**
|
|
492
499
|
* The method names of an entity, so hook registrations name a method that exists.
|
|
493
500
|
*/
|
|
@@ -503,9 +510,13 @@ export type MethodKey<E> = {
|
|
|
503
510
|
* entity graph almost always has. Nothing about the standard decorator spec changes that; it only removed
|
|
504
511
|
* the reflected `design:type` that used to make `entity` optional.
|
|
505
512
|
*/
|
|
506
|
-
export type EntityGetter<E =
|
|
513
|
+
export type EntityGetter<E = object> = () => Type<E>;
|
|
507
514
|
export type CascadeType = 'persist' | 'delete';
|
|
508
|
-
|
|
515
|
+
/**
|
|
516
|
+
* `E` is the relation's target and `O` the entity declaring it, whose fields `references` names on its
|
|
517
|
+
* `local` side; the relation decorators infer `O` from the class they sit on.
|
|
518
|
+
*/
|
|
519
|
+
export type RelationOptions<E, O = unknown> = {
|
|
509
520
|
entity: EntityGetter<E>;
|
|
510
521
|
cardinality: RelationCardinality;
|
|
511
522
|
readonly cascade?: boolean | CascadeType;
|
|
@@ -518,13 +529,24 @@ export type RelationOptions<E = any> = {
|
|
|
518
529
|
*/
|
|
519
530
|
readonly onDelete?: ForeignKeyAction;
|
|
520
531
|
readonly onUpdate?: ForeignKeyAction;
|
|
521
|
-
|
|
532
|
+
/** The inverse side: the member of the target holding the foreign key or the owning relation, `(post) => post.author`. */
|
|
533
|
+
mappedBy?: (keys: KeyMap<E>) => Key<E>;
|
|
522
534
|
/**
|
|
523
535
|
* The pivot entity of a many-to-many. Unconstrained by `E`: a pivot holds foreign keys to both
|
|
524
536
|
* sides and is not a relation value of the target, so nothing about it is derivable from `E`.
|
|
525
537
|
*/
|
|
526
538
|
through?: EntityGetter;
|
|
527
|
-
|
|
539
|
+
/**
|
|
540
|
+
* The join columns where no convention fits: each pairs a field of the declaring entity with one of
|
|
541
|
+
* the target, `(order, customer) => [{ local: order.customerCode, foreign: customer.code }]`. A
|
|
542
|
+
* `through` relation takes none: its junction's columns follow the convention.
|
|
543
|
+
*/
|
|
544
|
+
references?: (local: KeyMap<O>, foreign: KeyMap<E>) => readonly RelationReference<O, E>[];
|
|
545
|
+
};
|
|
546
|
+
/** One pair of join columns, each a field read off its entity's key map. */
|
|
547
|
+
export type RelationReference<O, E> = {
|
|
548
|
+
readonly local: FieldKey<O>;
|
|
549
|
+
readonly foreign: FieldKey<E>;
|
|
528
550
|
};
|
|
529
551
|
/**
|
|
530
552
|
* A relation once `getMeta` has resolved it: `references` is filled in and `mappedBy` is the key its
|
|
@@ -537,46 +559,48 @@ export type RelationOptions<E = any> = {
|
|
|
537
559
|
* from "declared, but an inverse side too, so neither owns the foreign key" needs the unresolved shape
|
|
538
560
|
* still there to find. A phase-split metadata map costs more than the call parentheses it saves.
|
|
539
561
|
*/
|
|
540
|
-
export type RelationMeta
|
|
541
|
-
mappedBy?: Key<E>;
|
|
562
|
+
export type RelationMeta = RelationRegistration & {
|
|
542
563
|
references: RelationReferences;
|
|
543
564
|
};
|
|
544
|
-
/**
|
|
545
|
-
|
|
565
|
+
/**
|
|
566
|
+
* A relation as the registry takes it, whichever entity it targets: `mappedBy` and `references` read
|
|
567
|
+
* off their key maps down to the names they give, `references` unset until `getMeta` settles it.
|
|
568
|
+
*/
|
|
569
|
+
export type RelationRegistration = Omit<RelationOptions<object>, 'mappedBy' | 'references'> & {
|
|
570
|
+
mappedBy?: string;
|
|
571
|
+
references?: RelationReferences;
|
|
572
|
+
};
|
|
573
|
+
/** How a to-many owner reaches its children: a junction entity or the join columns, never both. */
|
|
574
|
+
type RelationOwnerJoin<E, O> = (Required<Pick<RelationOptions<E, O>, 'through'>> & {
|
|
575
|
+
readonly references?: never;
|
|
576
|
+
}) | (Required<Pick<RelationOptions<E, O>, 'references'>> & {
|
|
577
|
+
readonly through?: never;
|
|
578
|
+
});
|
|
546
579
|
/**
|
|
547
580
|
* Every way a to-many can say where its rows are. Required because nothing about the field implies it:
|
|
548
581
|
* without one of the three, resolution has no columns to join on and throws.
|
|
549
582
|
*/
|
|
550
|
-
type RelationJoin<E> = RelationOwnerJoin<E> | Required<Pick<RelationOptions<E>, 'mappedBy'>>;
|
|
551
|
-
type RelationOptionsOwner<E> = Pick<RelationOptions<E>, 'entity' | 'references' | 'cascade' | 'onDelete' | 'onUpdate'>;
|
|
583
|
+
type RelationJoin<E, O> = RelationOwnerJoin<E, O> | Required<Pick<RelationOptions<E>, 'mappedBy'>>;
|
|
584
|
+
type RelationOptionsOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'references' | 'cascade' | 'onDelete' | 'onUpdate'>;
|
|
552
585
|
type RelationOptionsInverseSide<E> = Pick<RelationOptions<E>, 'entity' | 'cascade'> & Required<Pick<RelationOptions<E>, 'mappedBy'>>;
|
|
553
|
-
type RelationOptionsThroughOwner<E> = Pick<RelationOptions<E>, 'entity' | 'cascade'> & RelationOwnerJoin<E>;
|
|
586
|
+
type RelationOptionsThroughOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' | 'cascade'> & RelationOwnerJoin<E, O>;
|
|
554
587
|
/**
|
|
555
|
-
* The key names of `E` as values, so
|
|
556
|
-
* a
|
|
557
|
-
*
|
|
558
|
-
* Mapping over `Key<E>` rather than `keyof E` is what makes the callback usable: a homomorphic
|
|
559
|
-
* `[K in keyof E]` inherits the entity's optional modifiers, so `user.company` is
|
|
560
|
-
* `'company' | undefined` and {@link RelationKeyMapper} rejects it - every callback needed a `!`.
|
|
561
|
-
*
|
|
562
|
-
* At runtime a callback only ever reads one property off the map, so a single `Proxy` returning its
|
|
563
|
-
* own key stands in for every entity's: see `RELATION_KEY_MAP`. A key that names neither a field nor
|
|
564
|
-
* a relation of the target is rejected when the entity resolves.
|
|
588
|
+
* The key names of `E` as values, so a definition reads a member off it - `(post) => post.author` -
|
|
589
|
+
* and follows a rename. Homomorphic in `E`, which is what keeps that link, and `-?` so an optional
|
|
590
|
+
* member still names itself. At runtime one `Proxy` answering its own key serves every entity.
|
|
565
591
|
*/
|
|
566
|
-
export type
|
|
567
|
-
readonly [K in
|
|
592
|
+
export type KeyMap<E> = {
|
|
593
|
+
readonly [K in keyof E]-?: K;
|
|
568
594
|
};
|
|
569
|
-
export type RelationKeyMapper<E> = (keyMap: RelationKeyMap<E>) => Key<E>;
|
|
570
595
|
export type RelationReferences = {
|
|
571
596
|
readonly local: string;
|
|
572
597
|
readonly foreign: string;
|
|
573
598
|
}[];
|
|
574
|
-
export type RelationMappedBy<E> = Key<E> | RelationKeyMapper<E>;
|
|
575
599
|
export type RelationCardinality = '11' | 'm1' | '1m' | 'mm';
|
|
576
|
-
export type RelationOneToOneOptions<E> = RelationOptionsOwner<E> | RelationOptionsInverseSide<E>;
|
|
577
|
-
export type RelationOneToManyOptions<E> = RelationOptionsInverseSide<E> | RelationOptionsThroughOwner<E>;
|
|
578
|
-
export type RelationManyToOneOptions<E> = RelationOptionsOwner<E>;
|
|
579
|
-
export type RelationManyToManyOptions<E> = RelationOptionsThroughOwner<E> | RelationOptionsInverseSide<E>;
|
|
600
|
+
export type RelationOneToOneOptions<E, O = unknown> = RelationOptionsOwner<E, O> | RelationOptionsInverseSide<E>;
|
|
601
|
+
export type RelationOneToManyOptions<E, O = unknown> = RelationOptionsInverseSide<E> | RelationOptionsThroughOwner<E, O>;
|
|
602
|
+
export type RelationManyToOneOptions<E, O = unknown> = RelationOptionsOwner<E, O>;
|
|
603
|
+
export type RelationManyToManyOptions<E, O = unknown> = RelationOptionsThroughOwner<E, O> | RelationOptionsInverseSide<E>;
|
|
580
604
|
/**
|
|
581
605
|
* Lifecycle hook event names.
|
|
582
606
|
*/
|
|
@@ -613,10 +637,10 @@ export type IndexTypeOptions = {
|
|
|
613
637
|
*
|
|
614
638
|
* @example
|
|
615
639
|
* ```ts
|
|
616
|
-
* @Index([
|
|
617
|
-
* @Index([raw`lower("email")`], { unique: true })
|
|
618
|
-
* @Index([{ column:
|
|
619
|
-
* @Index([
|
|
640
|
+
* @Index((post) => [post.tenantId, { column: post.createdAt, order: 'desc' }]) // keyset pagination
|
|
641
|
+
* @Index(() => [raw`lower("email")`], { unique: true }) // case-insensitive uniqueness
|
|
642
|
+
* @Index((post) => [{ column: post.body, length: 64 }]) // MySQL needs a prefix on TEXT
|
|
643
|
+
* @Index((post) => [post.data], { type: 'gin' }) // JSONB containment
|
|
620
644
|
* ```
|
|
621
645
|
*
|
|
622
646
|
* `C` is the entity's `FieldKey` on the `@Index`/`defineEntity` paths, where the decorated class says
|
|
@@ -704,8 +728,8 @@ export type IndexColumnModifiers = {
|
|
|
704
728
|
*
|
|
705
729
|
* @example
|
|
706
730
|
* ```ts
|
|
707
|
-
* @Index([{ column:
|
|
708
|
-
* @Index([{ column:
|
|
731
|
+
* @Index((user) => [{ column: user.kind, jsonPath: { path: 'theme.color', type: String } }]) // 'kind.theme.color': 'red'
|
|
732
|
+
* @Index((user) => [{ column: user.kind, jsonPath: { path: 'rating', type: Number } }]) // 'kind.rating': { $gte: 4 }
|
|
709
733
|
* ```
|
|
710
734
|
*/
|
|
711
735
|
export type IndexJsonPath = {
|
|
@@ -724,8 +748,8 @@ export type IndexJsonPath = {
|
|
|
724
748
|
*
|
|
725
749
|
* @example
|
|
726
750
|
* ```ts
|
|
727
|
-
* @Index([{ column:
|
|
728
|
-
* @Index([{ column:
|
|
751
|
+
* @Index((user) => [{ column: user.tags, jsonArray: { type: String, length: 64 } }]) // tags: { $all: [...] }
|
|
752
|
+
* @Index((user) => [{ column: user.kind, jsonArray: { path: 'ids', type: Number } }]) // 'kind.ids': { $all: [...] }
|
|
729
753
|
* ```
|
|
730
754
|
*/
|
|
731
755
|
export type IndexJsonArray = {
|
|
@@ -741,6 +765,8 @@ type IndexColumnPlainModifiers = Except<IndexColumnModifiers, 'jsonPath' | 'json
|
|
|
741
765
|
export type IndexColumnOptions<C extends string = string> = IndexColumnPlainModifiers & {
|
|
742
766
|
/** The column to index, or `raw(...)` for an expression. */
|
|
743
767
|
readonly column: C | QueryRaw;
|
|
768
|
+
readonly jsonPath?: never;
|
|
769
|
+
readonly jsonArray?: never;
|
|
744
770
|
};
|
|
745
771
|
/**
|
|
746
772
|
* One index entry, normalized: {@link IndexColumnInput}'s three authored shapes all reduce to this
|
|
@@ -829,9 +855,21 @@ export type CheckOptions = {
|
|
|
829
855
|
*/
|
|
830
856
|
export type EntityMembers = {
|
|
831
857
|
readonly fields?: Readonly<Record<string, FieldOptions | undefined>>;
|
|
832
|
-
readonly relations?: Readonly<Record<string,
|
|
858
|
+
readonly relations?: Readonly<Record<string, RelationRegistration | undefined>>;
|
|
833
859
|
readonly hooks?: Readonly<Partial<Record<HookEvent, readonly string[]>>>;
|
|
834
860
|
};
|
|
861
|
+
/** An entity's fields as `defineEntity` takes them, keyed like every entity map (see `QuerySelect`). */
|
|
862
|
+
type EntityFieldOptions<E, F extends keyof E = FieldKey<E>> = {
|
|
863
|
+
readonly [K in F]?: FieldOptionsFor<E[K]>;
|
|
864
|
+
};
|
|
865
|
+
/**
|
|
866
|
+
* An entity's relations as `defineEntity` takes them. Keyed over every member rather than `RelationKey<E>`:
|
|
867
|
+
* inside the generic call, only a map over `keyof E` gives a `mappedBy` callback its contextual type. A
|
|
868
|
+
* field named here still fails, on its options, since its value is no entity.
|
|
869
|
+
*/
|
|
870
|
+
type EntityRelationOptions<E> = {
|
|
871
|
+
readonly [K in keyof E]?: RelationOptionsFor<E[K], E>;
|
|
872
|
+
};
|
|
835
873
|
/**
|
|
836
874
|
* Configurable options for an entity (`@Entity()` / `defineEntity`).
|
|
837
875
|
*
|
|
@@ -848,38 +886,41 @@ export type EntityOptions<E = unknown> = {
|
|
|
848
886
|
/** Named, default-on `$where` filters (soft-delete is auto-registered from `@Field({ softDelete })`). */
|
|
849
887
|
readonly filters?: Record<string, FilterOptions<E>>;
|
|
850
888
|
/** Scalar fields; use `isId: true` on exactly one field for the primary key. */
|
|
851
|
-
readonly fields?:
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
readonly relations?: {
|
|
855
|
-
readonly [K in RelationKey<E>]?: RelationOptionsFor<E[K]>;
|
|
856
|
-
};
|
|
857
|
-
readonly indexes?: readonly EntityIndexInput<FieldKey<E>, E>[];
|
|
889
|
+
readonly fields?: EntityFieldOptions<E>;
|
|
890
|
+
readonly relations?: EntityRelationOptions<E>;
|
|
891
|
+
readonly indexes?: readonly EntityIndexInput<E>[];
|
|
858
892
|
/** Table-level `CHECK` constraints. See {@link CheckOptions}. */
|
|
859
893
|
readonly checks?: readonly CheckOptions[];
|
|
860
|
-
/**
|
|
861
|
-
readonly hooks?: Partial<Record<HookEvent, readonly MethodKey<E>[]>>;
|
|
894
|
+
/** Each lifecycle event and the methods it runs, read off the key map: `{ beforeInsert: (post) => [post.stamp] }`. */
|
|
895
|
+
readonly hooks?: Partial<Record<HookEvent, (keys: KeyMap<E>) => readonly MethodKey<E>[]>>;
|
|
862
896
|
};
|
|
863
897
|
/**
|
|
864
|
-
* Everything an index carries beyond its columns,
|
|
865
|
-
*
|
|
866
|
-
* discriminated pair: omitting `distance` on a vector index type is a compile error.
|
|
898
|
+
* Everything an index carries beyond its columns, as the migration builder's `table.index(...)` takes it,
|
|
899
|
+
* and through {@link EntityIndexOptions} `@Index` and `defineEntity`. `Except` (not plain `Omit`) keeps
|
|
900
|
+
* `type`/`distance` a discriminated pair: omitting `distance` on a vector index type is a compile error.
|
|
867
901
|
*/
|
|
868
|
-
export type IndexOptions
|
|
869
|
-
/** Non-key columns stored in the index; a typo builds nothing, the server refusing
|
|
870
|
-
readonly include?: readonly
|
|
902
|
+
export type IndexOptions = Except<EntityIndexMeta, 'columns' | 'include' | 'where'> & {
|
|
903
|
+
/** Non-key columns stored in the index, by column name; a typo builds nothing, the server refusing it. */
|
|
904
|
+
readonly include?: readonly string[];
|
|
871
905
|
/**
|
|
872
906
|
* Partial-index predicate. `raw` with no interpolation, like an index expression: this is DDL, so
|
|
873
907
|
* there is no placeholder for a bound value. A bare string is the older spelling and still works.
|
|
874
908
|
*/
|
|
875
909
|
readonly where?: string | QueryRaw;
|
|
876
910
|
};
|
|
877
|
-
/** A field of `E`, or any name where there is no entity to check it against - the migration builder. */
|
|
878
|
-
type IndexFieldKey<E> = unknown extends E ? string : FieldKey<E>;
|
|
879
911
|
/**
|
|
880
|
-
*
|
|
912
|
+
* {@link IndexOptions} on an entity, whose stored columns are read off its key map, `(post) => [post.slug]`,
|
|
913
|
+
* so they are checked against it and follow a rename. The migration builder names raw columns instead.
|
|
914
|
+
*/
|
|
915
|
+
export type EntityIndexOptions<E> = Except<IndexOptions, 'include'> & {
|
|
916
|
+
readonly include?: (keys: KeyMap<E>) => readonly FieldKey<E>[];
|
|
917
|
+
};
|
|
918
|
+
/**
|
|
919
|
+
* An index as authored on an entity, before `defineIndex` reads its columns off the key map. Only the
|
|
920
|
+
* member lists are callbacks: TypeScript never checks a callback's returned literal for excess properties,
|
|
921
|
+
* so the options stay a literal of their own, where `uniqe: true` is a compile error.
|
|
881
922
|
*/
|
|
882
|
-
export type EntityIndexInput<
|
|
883
|
-
readonly columns: readonly IndexColumnInput<
|
|
923
|
+
export type EntityIndexInput<E> = EntityIndexOptions<E> & {
|
|
924
|
+
readonly columns: (keys: KeyMap<E>) => readonly IndexColumnInput<FieldKey<E>, E>[];
|
|
884
925
|
};
|
|
885
926
|
export {};
|
package/dist/type/migration.d.ts
CHANGED
|
@@ -73,7 +73,7 @@ export interface MigratorOptions {
|
|
|
73
73
|
/**
|
|
74
74
|
* Entities to use for schema generation
|
|
75
75
|
*/
|
|
76
|
-
readonly entities?: Type<
|
|
76
|
+
readonly entities?: Type<object>[];
|
|
77
77
|
/**
|
|
78
78
|
* Default action for foreign key ON DELETE and ON UPDATE clauses.
|
|
79
79
|
*/
|
|
@@ -141,7 +141,7 @@ export interface IndexSchema extends VectorIndexOptions {
|
|
|
141
141
|
/**
|
|
142
142
|
* What the index is over, in order. Named `entries` and not `columns` because an entry need not be
|
|
143
143
|
* a column at all: ``raw`lower(email)` `` is one, and so is a column carrying a prefix length or a
|
|
144
|
-
* stored order. The authored form, `@Index
|
|
144
|
+
* stored order. The authored form, `@Index`, still spells this `columns`, since that is what
|
|
145
145
|
* it reads like at the call site.
|
|
146
146
|
*/
|
|
147
147
|
readonly entries: readonly IndexColumnSchema[];
|
|
@@ -234,7 +234,7 @@ export interface SyncOptions {
|
|
|
234
234
|
readonly drop?: boolean;
|
|
235
235
|
readonly logging?: boolean;
|
|
236
236
|
/** One entity instead of every registered one, for a schema that grows while the process runs. */
|
|
237
|
-
readonly entity?: Type<
|
|
237
|
+
readonly entity?: Type<object>;
|
|
238
238
|
/** Drop every table and recreate it. Development only: it is the one option that loses data. */
|
|
239
239
|
readonly force?: boolean;
|
|
240
240
|
}
|
|
@@ -266,13 +266,13 @@ export interface SchemaGenerator {
|
|
|
266
266
|
* cross-entity foreign key has nothing to resolve against and is dropped: all three call sites that
|
|
267
267
|
* used to work that way emitted schemas with no referential integrity.
|
|
268
268
|
*/
|
|
269
|
-
generateCreateSchema(entities: readonly Type<
|
|
269
|
+
generateCreateSchema(entities: readonly Type<object>[], options?: CreateSchemaOptions): string[];
|
|
270
270
|
/**
|
|
271
271
|
* Every `DROP TABLE` for `entities`, dependents first. The inverse of {@link generateCreateSchema},
|
|
272
272
|
* and the reason it takes the whole set: dropping in any order that ignores the relation graph is
|
|
273
273
|
* rejected once the foreign keys are really there.
|
|
274
274
|
*/
|
|
275
|
-
generateDropSchema(entities: readonly Type<
|
|
275
|
+
generateDropSchema(entities: readonly Type<object>[], options?: DropSchemaOptions): string[];
|
|
276
276
|
/** Generate DROP TABLE statement. */
|
|
277
277
|
generateDropTable(tableName: string, options?: DropSchemaOptions): string;
|
|
278
278
|
/**
|
|
@@ -303,7 +303,7 @@ export interface SchemaGenerator {
|
|
|
303
303
|
* reads as missing from both sides, which is a match and no statement. Defaults to this entity
|
|
304
304
|
* alone, which is right only where it has no relations.
|
|
305
305
|
*/
|
|
306
|
-
diffSchema
|
|
306
|
+
diffSchema(entity: Type<object>, currentTable: TableNode | undefined, desiredAst?: SchemaAST): SchemaDiff | undefined;
|
|
307
307
|
/**
|
|
308
308
|
* The entity side as an AST, to hand to every {@link diffSchema} of one run - building it per
|
|
309
309
|
* entity instead is quadratic in the number of entities.
|
|
@@ -311,7 +311,7 @@ export interface SchemaGenerator {
|
|
|
311
311
|
* Optional because not every generator compares one: MongoDB has no foreign keys and diffs only
|
|
312
312
|
* indexes, so it neither implements this nor reads the argument.
|
|
313
313
|
*/
|
|
314
|
-
buildAST?(entities: readonly Type<
|
|
314
|
+
buildAST?(entities: readonly Type<object>[]): SchemaAST;
|
|
315
315
|
/**
|
|
316
316
|
* The table's key: {@link resolveTableAlias} behind {@link resolveSchema}, which is how a
|
|
317
317
|
* `SchemaAST` stores it and how a diff finds it again.
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import type { AbstractSqlDialect } from '../dialect/abstractSqlDialect.js';
|
|
2
|
+
import type { MongoDialect } from '../mongo/mongoDialect.js';
|
|
1
3
|
import type { DialectName } from './querier.js';
|
|
4
|
+
/** The dialects the migrator runs on, which `dialectName` tells apart: every SQL engine, and MongoDB. */
|
|
5
|
+
export type MigratorDialect = AbstractSqlDialect | MongoDialect;
|
|
2
6
|
declare const KNOWN_MIGRATOR_DIALECTS: readonly ["postgres", "cockroachdb", "mysql", "mariadb", "sqlite", "mssql", "mongodb"];
|
|
3
7
|
export type KnownMigratorDialect = (typeof KNOWN_MIGRATOR_DIALECTS)[number];
|
|
4
8
|
/**
|
package/dist/type/querier.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { SqlDialectName } from './dialect.js';
|
|
|
4
4
|
import type { FieldKey, HookEvent, RelationKey } from './entity.js';
|
|
5
5
|
import type { LoggingOptions } from './logger.js';
|
|
6
6
|
import type { NamingStrategy } from './namingStrategy.js';
|
|
7
|
-
import type { QueryFilter, QueryFindResult, QueryOneProjected, QueryOptions, QueryPage, QueryProjected, QuerySearch,
|
|
7
|
+
import type { QueryFilter, QueryFindResult, QueryOneProjected, QueryOptions, QueryPage, QueryProjected, QuerySearch, QueryUpdateResult } from './query.js';
|
|
8
8
|
import type { UniversalQuerier } from './universalQuerier.js';
|
|
9
9
|
import type { Type } from './utility.js';
|
|
10
10
|
/**
|
|
@@ -47,13 +47,13 @@ export interface Querier extends UniversalQuerier {
|
|
|
47
47
|
}, opts?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C>[]>;
|
|
48
48
|
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?: QueryOptions): Promise<QueryFindResult<E, S, V, X, P, C>[]>;
|
|
49
49
|
/**
|
|
50
|
-
* Stream records as an async iterable
|
|
51
|
-
*
|
|
50
|
+
* Stream records as an async iterable, in both patterns, each with the relations and counts
|
|
51
|
+
* `findMany` reads. Fires no lifecycle hooks.
|
|
52
52
|
*/
|
|
53
|
-
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>(q:
|
|
53
|
+
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>(q: QueryProjected<E, S, V, X, P, C> & {
|
|
54
54
|
$entity: Type<E>;
|
|
55
|
-
}, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P>>;
|
|
56
|
-
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:
|
|
55
|
+
}, opts?: QueryOptions): AsyncIterable<QueryFindResult<E, S, V, X, P, C>>;
|
|
56
|
+
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>>;
|
|
57
57
|
/**
|
|
58
58
|
* Find many records and count. Supports both patterns.
|
|
59
59
|
*/
|
|
@@ -76,9 +76,9 @@ export interface QuerierPool<Q extends Querier = Querier, D extends AbstractDial
|
|
|
76
76
|
export interface SqlQuerierPool<Q extends SqlQuerier = SqlQuerier, D extends AbstractSqlDialect = AbstractSqlDialect> extends QuerierPool<Q, D>, Pick<SqlQuerier, 'all' | 'run'> {
|
|
77
77
|
}
|
|
78
78
|
/** Dialect class used by pool `P` (when `P` is a {@link QuerierPool}). */
|
|
79
|
-
export type QuerierPoolDialect<P> = P extends QuerierPool<
|
|
79
|
+
export type QuerierPoolDialect<P> = P extends QuerierPool<infer _Q, infer D> ? D : never;
|
|
80
80
|
/** Querier type produced by pool `P`. */
|
|
81
|
-
export type QuerierPoolQuerier<P> = P extends QuerierPool<infer Q,
|
|
81
|
+
export type QuerierPoolQuerier<P> = P extends QuerierPool<infer Q, infer _D> ? Q : never;
|
|
82
82
|
/**
|
|
83
83
|
* Represents a high-compatibility SQL pool shim for Node.js integrations (e.g., express-session).
|
|
84
84
|
*/
|
package/dist/type/query.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FieldKey,
|
|
1
|
+
import type { FieldKey, JsonFieldPaths, RelationKey, RelationTarget, WrittenId } from './entity.js';
|
|
2
2
|
import type { QueryLock } from './queryLock.js';
|
|
3
3
|
import type { QueryRaw } from './queryRaw.js';
|
|
4
4
|
import type { QueryWhere } from './queryWhere.js';
|
|
@@ -25,23 +25,13 @@ export type QueryOptions = {
|
|
|
25
25
|
*/
|
|
26
26
|
autoPrefix?: boolean;
|
|
27
27
|
};
|
|
28
|
-
export type QuerySelectOptions = {
|
|
29
|
-
/**
|
|
30
|
-
* prefix the query with this.
|
|
31
|
-
*/
|
|
32
|
-
prefix?: string;
|
|
33
|
-
/**
|
|
34
|
-
* automatically add the prefix for the alias.
|
|
35
|
-
*/
|
|
36
|
-
autoPrefixAlias?: boolean;
|
|
37
|
-
};
|
|
38
28
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
29
|
+
* Field selection - `{ name: true }` whitelists fields; relations go in `$populate`. Declared over
|
|
30
|
+
* `F extends keyof E`, like every map keyed by an entity's members, so each key stays linked to its
|
|
31
|
+
* property and an editor rename reaches it. `F` is also how a projection passes its captured key set.
|
|
42
32
|
*/
|
|
43
|
-
export type QuerySelect<E> = {
|
|
44
|
-
[K in
|
|
33
|
+
export type QuerySelect<E, F extends keyof E = FieldKey<E>, V = BooleanLike> = {
|
|
34
|
+
[K in F]?: V;
|
|
45
35
|
};
|
|
46
36
|
/**
|
|
47
37
|
* Accepted `$select` value: a field map, or raw SQL projections built with `raw()`
|
|
@@ -56,8 +46,8 @@ export type QueryExclude<E> = QuerySelect<E>;
|
|
|
56
46
|
/**
|
|
57
47
|
* relation population map.
|
|
58
48
|
*/
|
|
59
|
-
export type QueryPopulate<E
|
|
60
|
-
[K in
|
|
49
|
+
export type QueryPopulate<E, R extends keyof E = RelationKey<E>> = {
|
|
50
|
+
[K in R]?: BooleanLike | QueryPopulateRelationOptions<E[K]>;
|
|
61
51
|
};
|
|
62
52
|
/**
|
|
63
53
|
* The key a read carries its relation tallies under. One spelling for the type and the runtime that
|
|
@@ -66,23 +56,20 @@ export type QueryPopulate<E> = {
|
|
|
66
56
|
export declare const COUNT_RESULT_KEY = "_count";
|
|
67
57
|
/**
|
|
68
58
|
* How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
|
|
69
|
-
* which ones count
|
|
70
|
-
*
|
|
71
|
-
* a relation of the same name that `$populate` filled with rows.
|
|
59
|
+
* which ones count: a correlated count in the read's own statement, so no related row is loaded. Comes
|
|
60
|
+
* back under `_count`, which keeps it clear of a relation of the same name `$populate` filled.
|
|
72
61
|
*/
|
|
73
|
-
export type QueryCount<E
|
|
74
|
-
[K in
|
|
62
|
+
export type QueryCount<E, R extends keyof E = ToManyRelationKey<E>> = {
|
|
63
|
+
[K in R]?: BooleanLike | QueryFilter<RelationTarget<E[K]>>;
|
|
75
64
|
};
|
|
76
65
|
/**
|
|
77
66
|
* query conflict paths - subset of field keys used to detect upsert conflicts.
|
|
78
67
|
*/
|
|
79
|
-
export type QueryConflictPaths<E> =
|
|
80
|
-
[K in FieldKey<E>]?: true;
|
|
81
|
-
};
|
|
68
|
+
export type QueryConflictPaths<E> = QuerySelect<E, FieldKey<E>, true>;
|
|
82
69
|
/**
|
|
83
70
|
* Options to populate a relation declared as `V`, by its cardinality.
|
|
84
71
|
*/
|
|
85
|
-
export type QueryPopulateRelationOptions<V> =
|
|
72
|
+
export type QueryPopulateRelationOptions<V> = IsMany<V> extends true ? RelationQuery<RelationTarget<V>> : QueryUnique<RelationTarget<V>> & {
|
|
86
73
|
$required?: boolean;
|
|
87
74
|
};
|
|
88
75
|
/**
|
|
@@ -160,9 +147,11 @@ export type QuerySortByCount = {
|
|
|
160
147
|
* against an intersection is repeated per constituent, which made this the single most expensive
|
|
161
148
|
* type in the package to check.
|
|
162
149
|
*/
|
|
163
|
-
export type QuerySortMap<E, Vector extends boolean = true> = {
|
|
164
|
-
[
|
|
165
|
-
}
|
|
150
|
+
export type QuerySortMap<E, Vector extends boolean = true, K extends keyof E = FieldKey<E> | RelationKey<E>> = {
|
|
151
|
+
[P in K]?: P extends RelationKey<E> ? IsMany<E[P]> extends true ? QuerySortByCount : QuerySortMap<RelationTarget<E[P]>, false> : Vector extends true ? NonNullable<E[P]> extends readonly number[] ? QuerySortValue : QuerySortDirection : QuerySortDirection;
|
|
152
|
+
} & ([JsonFieldPaths<E>] extends [never] ? unknown : {
|
|
153
|
+
[P in JsonFieldPaths<E>]?: QuerySortDirection;
|
|
154
|
+
});
|
|
166
155
|
/**
|
|
167
156
|
* pager options.
|
|
168
157
|
*/
|
|
@@ -276,14 +265,13 @@ export type Query<E> = {
|
|
|
276
265
|
* Declared beside the type they describe so the two cannot drift, and `satisfies` fails the build
|
|
277
266
|
* rather than the runtime if a clause is ever renamed.
|
|
278
267
|
*
|
|
279
|
-
* `$lock`
|
|
280
|
-
*
|
|
268
|
+
* `$lock` is only in {@link QUERY_STATEMENT_CLAUSES}: neither a wire query nor a relation's query
|
|
269
|
+
* accepts it.
|
|
281
270
|
*/
|
|
282
271
|
export declare const QUERY_OBJECT_CLAUSES: readonly ["$select", "$populate", "$exclude", "$where", "$sort"];
|
|
283
272
|
/**
|
|
284
|
-
* Object clauses only the statement itself takes
|
|
285
|
-
*
|
|
286
|
-
* populated relation's rows are assembled after that, so there is nothing for a nested one to count.
|
|
273
|
+
* Object clauses only the statement itself takes: a populated relation's rows keep their declared type,
|
|
274
|
+
* so a `$count` inside one would have no `_count` to land in.
|
|
287
275
|
*/
|
|
288
276
|
export declare const QUERY_ROOT_OBJECT_CLAUSES: readonly ["$count"];
|
|
289
277
|
export declare const QUERY_NUMBER_CLAUSES: readonly ["$skip", "$limit"];
|
|
@@ -294,6 +282,16 @@ export declare const QUERY_NUMBER_CLAUSES: readonly ["$skip", "$limit"];
|
|
|
294
282
|
*/
|
|
295
283
|
export declare const QUERY_ROOT_NUMBER_CLAUSES: readonly ["$candidates"];
|
|
296
284
|
export declare const QUERY_BOOLEAN_CLAUSES: readonly ["$distinct"];
|
|
285
|
+
/** The clauses that describe the statement, which a populated relation's own query refuses by name. */
|
|
286
|
+
export declare const QUERY_STATEMENT_CLAUSES: readonly ["$lock", "$count", "$candidates"];
|
|
287
|
+
type RelationClause = (typeof QUERY_OBJECT_CLAUSES | typeof QUERY_NUMBER_CLAUSES | typeof QUERY_BOOLEAN_CLAUSES)[number];
|
|
288
|
+
/**
|
|
289
|
+
* A populated relation's own query: the clause groups its runtime check accepts, so the two cannot
|
|
290
|
+
* drift, and a clause added to {@link Query} stays off it until it joins one of them.
|
|
291
|
+
*/
|
|
292
|
+
export type RelationQuery<E = object> = Pick<Query<E>, RelationClause> & {
|
|
293
|
+
$required?: boolean;
|
|
294
|
+
};
|
|
297
295
|
/**
|
|
298
296
|
* options to get a single record.
|
|
299
297
|
*/
|
|
@@ -315,33 +313,12 @@ export type QueryUnique<E> = Pick<QueryOne<E>, '$select' | '$exclude' | '$popula
|
|
|
315
313
|
* populated relation's own query - stays the concrete {@link Query} it is today.
|
|
316
314
|
* @internal
|
|
317
315
|
*/
|
|
318
|
-
type QueryProjection<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E>> =
|
|
319
|
-
$
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* {@link QueryProjection} without `$count`, which a stream cannot honor. Split out rather than
|
|
325
|
-
* subtracted afterwards: an optional key is a *known* key even when its value maps over `never`, so
|
|
326
|
-
* a statement that must not take the clause has to be built without it in the first place.
|
|
327
|
-
* @internal
|
|
328
|
-
*/
|
|
329
|
-
type QueryStreamProjection<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>> = {
|
|
330
|
-
$select?: {
|
|
331
|
-
[K in S]?: V;
|
|
332
|
-
} | readonly QueryRaw[];
|
|
333
|
-
$exclude?: {
|
|
334
|
-
[K in X]?: V;
|
|
335
|
-
};
|
|
336
|
-
$populate?: {
|
|
337
|
-
[K in P]?: QueryPopulate<E>[K];
|
|
338
|
-
};
|
|
316
|
+
type QueryProjection<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E>> = {
|
|
317
|
+
$select?: QuerySelect<E, S, V> | readonly QueryRaw[];
|
|
318
|
+
$exclude?: QuerySelect<E, X, V>;
|
|
319
|
+
$populate?: QueryPopulate<E, P>;
|
|
320
|
+
$count?: QueryCount<E, C & ToManyRelationKey<E>>;
|
|
339
321
|
};
|
|
340
|
-
/**
|
|
341
|
-
* A {@link QueryProjected} a stream can honor: no `$count`, which is batched over a result set a
|
|
342
|
-
* stream never holds all of.
|
|
343
|
-
*/
|
|
344
|
-
export type QueryStreamProjected<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>> = Except<Query<E>, '$count'> & QueryStreamProjection<E, S, V, X, P>;
|
|
345
322
|
/**
|
|
346
323
|
* A {@link Query} whose projection is captured, so {@link QueryFindResult} can shape the row.
|
|
347
324
|
*/
|
|
@@ -357,15 +334,7 @@ export type QueryOneProjected<E, S extends FieldKey<E>, V, X extends FieldKey<E>
|
|
|
357
334
|
* why `$exclude` is only read on the branch where there is none.
|
|
358
335
|
* @internal
|
|
359
336
|
*/
|
|
360
|
-
type ProjectedKeys<E, S, V, X, P
|
|
361
|
-
/**
|
|
362
|
-
* The id key when it can be named, and nothing when it cannot: {@link IdKey} widens to *every* field
|
|
363
|
-
* for an entity whose id is neither branded nor called `id`/`_id`/`uuid`, and adding that back would
|
|
364
|
-
* hand the caller a row claiming fields the query never fetched. Missing an id costs a `$select`
|
|
365
|
-
* entry; promising absent fields is the bug this type exists to prevent.
|
|
366
|
-
* @internal
|
|
367
|
-
*/
|
|
368
|
-
type NamedIdKey<E> = [FieldKey<E>] extends [IdKey<E>] ? never : IdKey<E>;
|
|
337
|
+
type ProjectedKeys<E, S, V, X, P> = ([V] extends [false | 0] ? Exclude<FieldKey<E>, S> : [S] extends [never] ? Exclude<FieldKey<E>, X> : S) | P;
|
|
369
338
|
/**
|
|
370
339
|
* Whether every entry of the captured map says the same thing: all selected, or all subtracted.
|
|
371
340
|
* @internal
|
|
@@ -394,8 +363,8 @@ type CountedRelations<C extends PropertyKey> = [C] extends [never] ? unknown : {
|
|
|
394
363
|
};
|
|
395
364
|
};
|
|
396
365
|
/** @internal */
|
|
397
|
-
type QueryProjectedRow<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E>> = [S | X] extends [never] ? E : IsUniform<V> extends true ? [PopulatedToMany<E, P>] extends [never] ? Pick<E, ProjectedKeys<E, S, V, X, P
|
|
398
|
-
Pick<E, Exclude<ProjectedKeys<E, S, V, X, P
|
|
366
|
+
type QueryProjectedRow<E, S extends FieldKey<E>, V, X extends FieldKey<E>, P extends RelationKey<E>, C extends RelationKey<E>> = [S | X] extends [never] ? E : IsUniform<V> extends true ? [PopulatedToMany<E, P>] extends [never] ? Pick<E, ProjectedKeys<E, S, V, X, P> & keyof E> : // A populated to-many is always a list, empty where the parent has no children, so it maps
|
|
367
|
+
Pick<E, Exclude<ProjectedKeys<E, S, V, X, P>, PopulatedToMany<E, P>> & keyof E> & {
|
|
399
368
|
[K in PopulatedToMany<E, P>]-?: NonNullable<E[K]>;
|
|
400
369
|
} : E;
|
|
401
370
|
/** The to-many relations a query populated, which come back as lists rather than as optional ones. */
|