@mikro-orm/core 7.2.0-dev.8 → 7.2.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/EntityManager.d.ts +41 -7
- package/EntityManager.js +225 -45
- package/MikroORM.d.ts +4 -0
- package/MikroORM.js +9 -0
- package/README.md +1 -0
- package/connections/Connection.d.ts +3 -1
- package/drivers/DatabaseDriver.d.ts +14 -5
- package/drivers/DatabaseDriver.js +151 -52
- package/drivers/IDatabaseDriver.d.ts +1 -0
- package/entity/Collection.js +4 -2
- package/entity/EntityFactory.js +6 -0
- package/entity/EntityLoader.d.ts +7 -1
- package/entity/EntityLoader.js +46 -11
- package/entity/EntityRepository.d.ts +4 -5
- package/entity/EntityRepository.js +7 -2
- package/entity/defineEntity.d.ts +48 -14
- package/entity/defineEntity.js +32 -1
- package/enums.d.ts +5 -1
- package/enums.js +2 -0
- package/errors.d.ts +36 -0
- package/errors.js +90 -0
- package/events/EventManager.js +6 -3
- package/exceptions.d.ts +5 -0
- package/exceptions.js +5 -0
- package/hydration/ObjectHydrator.d.ts +2 -0
- package/hydration/ObjectHydrator.js +12 -8
- package/index.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +3 -0
- package/metadata/MetadataDiscovery.js +133 -18
- package/metadata/MetadataStorage.js +17 -1
- package/metadata/types.d.ts +19 -3
- package/package.json +1 -1
- package/platforms/Platform.d.ts +22 -3
- package/platforms/Platform.js +59 -1
- package/types/BigIntType.d.ts +1 -0
- package/types/BigIntType.js +23 -0
- package/types/DateTimeType.d.ts +1 -0
- package/types/DateTimeType.js +8 -0
- package/types/StringType.d.ts +14 -3
- package/types/StringType.js +34 -4
- package/types/TextType.d.ts +2 -4
- package/types/TextType.js +2 -8
- package/types/Type.d.ts +11 -0
- package/types/Type.js +4 -4
- package/types/index.d.ts +2 -2
- package/typings.d.ts +56 -2
- package/typings.js +24 -1
- package/unit-of-work/ChangeSetPersister.js +17 -13
- package/unit-of-work/UnitOfWork.js +11 -4
- package/utils/Configuration.d.ts +15 -1
- package/utils/Configuration.js +11 -1
- package/utils/Cursor.d.ts +2 -0
- package/utils/Cursor.js +43 -33
- package/utils/DataloaderUtils.js +2 -1
- package/utils/EntityComparator.d.ts +2 -0
- package/utils/EntityComparator.js +7 -3
- package/utils/QueryHelper.d.ts +12 -0
- package/utils/QueryHelper.js +75 -4
- package/utils/RawQueryFragment.d.ts +6 -0
- package/utils/RawQueryFragment.js +15 -6
- package/utils/TransactionManager.js +1 -1
- package/utils/Utils.d.ts +14 -2
- package/utils/Utils.js +31 -4
- package/utils/env-vars.js +1 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/rls-utils.d.ts +35 -0
- package/utils/rls-utils.js +97 -0
- package/utils/upsert-utils.d.ts +9 -1
- package/utils/upsert-utils.js +26 -3
package/entity/defineEntity.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { EntityManager } from '../EntityManager.js';
|
|
2
2
|
import type { ColumnType, PropertyOptions, ReferenceOptions, EnumOptions, EmbeddedOptions, ManyToOneOptions, OneToManyOptions, OneToOneOptions, ManyToManyOptions, IndexColumnOptions } from '../metadata/types.js';
|
|
3
|
-
import type { AnyString, GeneratedColumnCallback, Constructor, CheckCallback, FilterQuery, EntityName, Dictionary, EntityMetadata, PrimaryKeyProp, EntityRepositoryType, Hidden, Opt, Primary, EntityClass, EntitySchemaWithMeta, InferEntity, MaybeReturnType, Ref, LazyRef, IndexCallback, TriggerCallback, FormulaCallback, EntityCtor, IsNever, IWrappedEntity, DefineConfig, Config, MaybePromise, IndexHints, ExtractDefineEntityProperties } from '../typings.js';
|
|
3
|
+
import type { AnyString, GeneratedColumnCallback, Constructor, CheckCallback, FilterQuery, EntityName, Dictionary, EntityMetadata, PrimaryKeyProp, EntityRepositoryType, Hidden, Opt, Primary, EntityClass, EntitySchemaWithMeta, InferEntity, MaybeReturnType, Ref, LazyRef, IndexCallback, TriggerCallback, FormulaCallback, EntityCtor, IsNever, IWrappedEntity, DefineConfig, Config, MaybePromise, IndexHints, OptionalProps, ExtractDefineEntityProperties } from '../typings.js';
|
|
4
4
|
import type { Raw } from '../utils/RawQueryFragment.js';
|
|
5
5
|
import type { ScalarReference } from './Reference.js';
|
|
6
6
|
import type { SerializeOptions } from '../serialization/EntitySerializer.js';
|
|
@@ -22,7 +22,7 @@ type HasKind<Options, K extends string> = Options extends {
|
|
|
22
22
|
kind: infer X extends string;
|
|
23
23
|
} ? X extends K ? true : false : false;
|
|
24
24
|
/** Lightweight chain result type for property builders - reduces type instantiation cost by avoiding full class resolution. */
|
|
25
|
-
export interface PropertyChain<Value, Options> {
|
|
25
|
+
export interface PropertyChain<in out Value, in out Options> {
|
|
26
26
|
'~type'?: {
|
|
27
27
|
value: Value;
|
|
28
28
|
};
|
|
@@ -112,7 +112,7 @@ export interface PropertyChain<Value, Options> {
|
|
|
112
112
|
getter(getter?: boolean): PropertyChain<Value, Options>;
|
|
113
113
|
getterName(getterName: string): PropertyChain<Value, Options>;
|
|
114
114
|
serializedPrimaryKey(serializedPrimaryKey?: boolean): PropertyChain<Value, Options>;
|
|
115
|
-
serializer(serializer: (value: Value, options?: SerializeOptions<any>) => any): PropertyChain<Value, Options>;
|
|
115
|
+
serializer(serializer: (value: SerializerValue<Value, Options>, options?: SerializeOptions<any>) => any): PropertyChain<Value, Options>;
|
|
116
116
|
serializedName(serializedName: string): PropertyChain<Value, Options>;
|
|
117
117
|
groups(...groups: string[]): PropertyChain<Value, Options>;
|
|
118
118
|
customOrder(...customOrder: string[] | number[] | boolean[]): PropertyChain<Value, Options>;
|
|
@@ -148,6 +148,8 @@ export interface PropertyChain<Value, Options> {
|
|
|
148
148
|
orphanRemoval(orphanRemoval?: boolean): HasKind<Options, '1:m' | '1:1'> extends true ? PropertyChain<Value, Options> : never;
|
|
149
149
|
discriminator(discriminator: string): HasKind<Options, 'm:1' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
150
150
|
discriminatorMap(discriminatorMap: Dictionary<string>): HasKind<Options, 'm:1' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
151
|
+
/** Resolve this read-only to-one relation via a subquery on another entity (see {@doclink relationships#to-one-relations-through-another-entity | To-one relations through another entity}). */
|
|
152
|
+
through(through: () => EntityName): HasKind<Options, 'm:1' | '1:1'> extends true ? PropertyChain<Value, Options> : never;
|
|
151
153
|
pivotTable(pivotTable: string): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
152
154
|
pivotEntity(pivotEntity: () => EntityName): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
153
155
|
fixedOrder(fixedOrder?: boolean): HasKind<Options, 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
@@ -180,7 +182,7 @@ export interface PropertyChain<Value, Options> {
|
|
|
180
182
|
foreignKeyName(foreignKeyName: string): HasKind<Options, 'm:1' | '1:m' | '1:1' | 'm:n'> extends true ? PropertyChain<Value, Options> : never;
|
|
181
183
|
}
|
|
182
184
|
/** @internal */
|
|
183
|
-
export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys extends BuilderKeys> implements Record<Exclude<UniversalPropertyKeys, ExcludeKeys>, any> {
|
|
185
|
+
export declare class UniversalPropertyOptionsBuilder<in out Value, in out Options, in out IncludeKeys extends BuilderKeys> implements Record<Exclude<UniversalPropertyKeys, ExcludeKeys>, any> {
|
|
184
186
|
'~options': Options;
|
|
185
187
|
'~type'?: {
|
|
186
188
|
value: Value;
|
|
@@ -528,6 +530,8 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
|
|
|
528
530
|
fixedOrderColumn(fixedOrderColumn: string): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
529
531
|
/** Override default name for pivot table (see {@doclink naming-strategy | Naming Strategy}). */
|
|
530
532
|
pivotTable(pivotTable: string): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
533
|
+
/** Resolve this read-only to-one relation via a subquery on another entity (see {@doclink relationships#to-one-relations-through-another-entity | To-one relations through another entity}). */
|
|
534
|
+
through(through: () => EntityName): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
531
535
|
/** Set pivot entity for this relation (see {@doclink collections#custom-pivot-table-entity | Custom pivot table entity}). */
|
|
532
536
|
pivotEntity(pivotEntity: () => EntityName): Pick<UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys>, IncludeKeys>;
|
|
533
537
|
/** Override the default database column name on the owning side (see {@doclink naming-strategy | Naming Strategy}). This option is only for simple properties represented by a single column. */
|
|
@@ -570,6 +574,13 @@ export declare class UniversalPropertyOptionsBuilder<Value, Options, IncludeKeys
|
|
|
570
574
|
export interface EmptyOptions extends Partial<Record<UniversalPropertyKeys, unknown>> {
|
|
571
575
|
}
|
|
572
576
|
/** @internal */
|
|
577
|
+
export declare class StringPropertyOptionsBuilder<Value, Options> extends UniversalPropertyOptionsBuilder<Value, Options, IncludeKeysForProperty> {
|
|
578
|
+
trim(): StringPropertyOptionsBuilder<Value, Options>;
|
|
579
|
+
lowercase(): StringPropertyOptionsBuilder<Value, Options>;
|
|
580
|
+
uppercase(): StringPropertyOptionsBuilder<Value, Options>;
|
|
581
|
+
private withOptions;
|
|
582
|
+
}
|
|
583
|
+
/** @internal */
|
|
573
584
|
export declare class OneToManyOptionsBuilderOnlyMappedBy<Value extends object> extends UniversalPropertyOptionsBuilder<Value, EmptyOptions & {
|
|
574
585
|
kind: '1:m';
|
|
575
586
|
}, IncludeKeysForOneToManyOptions> {
|
|
@@ -582,7 +593,7 @@ type EntityTarget = {
|
|
|
582
593
|
'~entity': any;
|
|
583
594
|
} | EntityClass;
|
|
584
595
|
declare const propertyBuilders: PropertyBuilders;
|
|
585
|
-
type PropertyBuildersOverrideKeys = 'bigint' | 'array' | 'decimal' | 'json' | 'datetime' | 'time' | 'enum';
|
|
596
|
+
type PropertyBuildersOverrideKeys = 'bigint' | 'array' | 'decimal' | 'json' | 'string' | 'text' | 'datetime' | 'time' | 'enum';
|
|
586
597
|
/** Map of factory functions for creating type-safe property builders (scalars, enums, embeddables, and relations). */
|
|
587
598
|
export type PropertyBuilders = {
|
|
588
599
|
[K in Exclude<keyof typeof types, PropertyBuildersOverrideKeys>]: () => UniversalPropertyOptionsBuilder<InferPropertyValueType<(typeof types)[K]>, EmptyOptions, IncludeKeysForProperty>;
|
|
@@ -591,6 +602,8 @@ export type PropertyBuilders = {
|
|
|
591
602
|
array: <T = string>(toJsValue?: (i: string) => T, toDbValue?: (i: T) => string) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.array<T>>, EmptyOptions, IncludeKeysForProperty>;
|
|
592
603
|
decimal: <Mode extends 'number' | 'string' = 'string'>(mode?: Mode) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.decimal<Mode>>, EmptyOptions, IncludeKeysForProperty>;
|
|
593
604
|
json: <T>() => UniversalPropertyOptionsBuilder<T, EmptyOptions, IncludeKeysForProperty>;
|
|
605
|
+
string: () => StringPropertyOptionsBuilder<InferPropertyValueType<typeof types.string>, EmptyOptions>;
|
|
606
|
+
text: () => StringPropertyOptionsBuilder<InferPropertyValueType<typeof types.text>, EmptyOptions>;
|
|
594
607
|
formula: <T>(formula: string | FormulaCallback<any>) => UniversalPropertyOptionsBuilder<T, EmptyOptions, IncludeKeysForProperty>;
|
|
595
608
|
datetime: (length?: number) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.datetime>, EmptyOptions, IncludeKeysForProperty>;
|
|
596
609
|
time: (length?: number) => UniversalPropertyOptionsBuilder<InferPropertyValueType<typeof types.time>, EmptyOptions, IncludeKeysForProperty>;
|
|
@@ -618,7 +631,7 @@ type PartialWhere<TProperties, TBase> = string | FilterQuery<{
|
|
|
618
631
|
[K in AllKeys<TProperties, TBase> & string]?: unknown;
|
|
619
632
|
}>;
|
|
620
633
|
/** Metadata descriptor for `defineEntity()`, combining entity options with property definitions. */
|
|
621
|
-
export interface EntityMetadataWithProperties<TName extends string, TTableName extends string, TProperties extends Record<string, any>, TPK extends (keyof TProperties)[] | undefined = undefined, TBase = never, TRepository = never, TForceObject extends boolean = false, TDiscriminatorColumn extends string | undefined = undefined, TDiscriminatorValue extends string | number | undefined = undefined, TBaseDiscriminatorColumn extends string | undefined = undefined> extends Omit<Partial<EntityMetadata<InferEntityFromProperties<TProperties, TPK, TBase, TRepository>>>, 'properties' | 'extends' | 'primaryKeys' | 'hooks' | 'discriminator' | 'discriminatorColumn' | 'discriminatorValue' | 'versionProperty' | 'concurrencyCheckKeys' | 'serializedPrimaryKey' | 'indexes' | 'uniques' | 'triggers' | 'repository' | 'filters' | 'orderBy'> {
|
|
634
|
+
export interface EntityMetadataWithProperties<TName extends string, TTableName extends string, TProperties extends Record<string, any>, TPK extends (keyof TProperties)[] | undefined = undefined, TBase = never, TRepository = never, TForceObject extends boolean = false, TDiscriminatorColumn extends string | undefined = undefined, TDiscriminatorValue extends string | number | undefined = undefined, TBaseDiscriminatorColumn extends string | undefined = undefined, TEmbeddable extends boolean = false> extends Omit<Partial<EntityMetadata<InferEntityFromProperties<TProperties, TPK, TBase, TRepository>>>, 'properties' | 'extends' | 'primaryKeys' | 'hooks' | 'discriminator' | 'discriminatorColumn' | 'discriminatorValue' | 'versionProperty' | 'concurrencyCheckKeys' | 'serializedPrimaryKey' | 'indexes' | 'uniques' | 'triggers' | 'repository' | 'filters' | 'orderBy'> {
|
|
622
635
|
name: TName;
|
|
623
636
|
tableName?: TTableName;
|
|
624
637
|
extends?: {
|
|
@@ -638,8 +651,12 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
|
|
|
638
651
|
entity?: EntityName<any> | EntityName<any>[];
|
|
639
652
|
args?: boolean;
|
|
640
653
|
strict?: boolean;
|
|
654
|
+
rls?: boolean | {
|
|
655
|
+
setting?: string;
|
|
656
|
+
};
|
|
641
657
|
}>;
|
|
642
658
|
forceObject?: TForceObject;
|
|
659
|
+
embeddable?: TEmbeddable;
|
|
643
660
|
inheritance?: 'tpt';
|
|
644
661
|
orderBy?: {
|
|
645
662
|
[K in Extract<AllKeys<TProperties, TBase>, string>]?: QueryOrderKeysFlat;
|
|
@@ -690,7 +707,7 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
|
|
|
690
707
|
}[];
|
|
691
708
|
}
|
|
692
709
|
/** Defines an entity schema using property builders, with full type inference from the property definitions. */
|
|
693
|
-
export declare function defineEntity<const TName extends string, const TTableName extends string, const TProperties extends Record<string, any>, const TPK extends (keyof TProperties)[] | undefined = undefined, const TBase = never, const TRepository = never, const TForceObject extends boolean = false, const TDiscriminatorColumn extends string | undefined = undefined, const TDiscriminatorValue extends string | number | undefined = undefined, const TBaseDiscriminatorColumn extends string | undefined = undefined>(meta: EntityMetadataWithProperties<TName, TTableName, TProperties, TPK, TBase, TRepository, TForceObject, TDiscriminatorColumn, TDiscriminatorValue, TBaseDiscriminatorColumn>): EntitySchemaWithMeta<TName, TTableName, InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue>, TBase, TProperties, EntityCtor<InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue>>, TDiscriminatorColumn>;
|
|
710
|
+
export declare function defineEntity<const TName extends string, const TTableName extends string, const TProperties extends Record<string, any>, const TPK extends (keyof TProperties)[] | undefined = undefined, const TBase = never, const TRepository = never, const TForceObject extends boolean = false, const TDiscriminatorColumn extends string | undefined = undefined, const TDiscriminatorValue extends string | number | undefined = undefined, const TBaseDiscriminatorColumn extends string | undefined = undefined, const TEmbeddable extends boolean = false>(meta: EntityMetadataWithProperties<TName, TTableName, TProperties, TPK, TBase, TRepository, TForceObject, TDiscriminatorColumn, TDiscriminatorValue, TBaseDiscriminatorColumn, TEmbeddable>): EntitySchemaWithMeta<TName, TTableName, InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue, TEmbeddable>, TBase, TProperties, EntityCtor<InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue, TEmbeddable>>, TDiscriminatorColumn>;
|
|
694
711
|
export declare namespace defineEntity {
|
|
695
712
|
export { propertyBuilders as properties };
|
|
696
713
|
}
|
|
@@ -725,22 +742,24 @@ type InferTypeByString<T extends string> = T extends keyof typeof types ? InferJ
|
|
|
725
742
|
type InferJSType<T> = T extends typeof Type<infer TValue, any> ? NonNullable<TValue> : never;
|
|
726
743
|
type InferColumnType<T extends string> = T extends 'int' | 'int4' | 'integer' | 'bigint' | 'int8' | 'int2' | 'tinyint' | 'smallint' | 'mediumint' ? number : T extends 'double' | 'double precision' | 'real' | 'float8' | 'decimal' | 'numeric' | 'float' | 'float4' ? number : T extends 'datetime' | 'time' | 'time with time zone' | 'timestamp' | 'timestamp with time zone' | 'timetz' | 'timestamptz' | 'date' | 'interval' ? Date : T extends 'ObjectId' | 'objectId' | 'character varying' | 'varchar' | 'char' | 'character' | 'uuid' | 'text' | 'tinytext' | 'mediumtext' | 'longtext' | 'enum' ? string : T extends 'boolean' | 'bool' | 'bit' ? boolean : T extends 'blob' | 'tinyblob' | 'mediumblob' | 'longblob' | 'bytea' ? Buffer : T extends 'point' | 'line' | 'lseg' | 'box' | 'circle' | 'path' | 'polygon' | 'geometry' ? number[] : T extends 'tsvector' | 'tsquery' ? string[] : T extends 'json' | 'jsonb' ? any : any;
|
|
727
744
|
type BaseEntityMethodKeys = 'toObject' | 'toPOJO' | 'serialize' | 'assign' | 'populate' | 'init' | 'toReference';
|
|
745
|
+
interface BaseEntityMethods<in out Entity extends object> extends Pick<IWrappedEntity<Entity>, BaseEntityMethodKeys> {
|
|
746
|
+
}
|
|
728
747
|
/** Infers the entity type from a `defineEntity()` properties map, resolving builders, base classes, and primary keys. */
|
|
729
|
-
export type InferEntityFromProperties<Properties extends Record<string, any>, PK extends (keyof Properties)[] | undefined = undefined, Base = never, Repository = never, ForceObject extends boolean = false, BaseDiscriminatorColumn extends string | undefined = undefined, DiscriminatorValue extends string | number | undefined = undefined> = (IsNever<Base> extends true ? {} : Base extends {
|
|
748
|
+
export type InferEntityFromProperties<Properties extends Record<string, any>, PK extends (keyof Properties)[] | undefined = undefined, Base = never, Repository = never, ForceObject extends boolean = false, BaseDiscriminatorColumn extends string | undefined = undefined, DiscriminatorValue extends string | number | undefined = undefined, Embeddable extends boolean = false> = (IsNever<Base> extends true ? {} : Base extends {
|
|
730
749
|
toObject(...args: any[]): any;
|
|
731
|
-
} ?
|
|
750
|
+
} ? BaseEntityMethods<{
|
|
732
751
|
-readonly [K in keyof Properties]: InferBuilderValue<MaybeReturnType<Properties[K]>>;
|
|
733
752
|
} & {
|
|
734
753
|
[PrimaryKeyProp]?: InferCombinedPrimaryKey<Properties, PK, Base>;
|
|
735
754
|
} & (IsNever<Repository> extends true ? {} : {
|
|
736
755
|
[EntityRepositoryType]?: Repository extends Constructor<infer R> ? R : Repository;
|
|
737
|
-
}) & NarrowDiscriminator<Omit<Base, typeof PrimaryKeyProp>, BaseDiscriminatorColumn, DiscriminatorValue
|
|
756
|
+
}) & NarrowDiscriminator<Omit<Base, typeof PrimaryKeyProp>, BaseDiscriminatorColumn, DiscriminatorValue, Embeddable>> : {}) & {
|
|
738
757
|
-readonly [K in keyof Properties]: InferBuilderValue<MaybeReturnType<Properties[K]>>;
|
|
739
758
|
} & {
|
|
740
759
|
[PrimaryKeyProp]?: InferCombinedPrimaryKey<Properties, PK, Base>;
|
|
741
760
|
} & (IsNever<Repository> extends true ? {} : {
|
|
742
761
|
[EntityRepositoryType]?: Repository extends Constructor<infer R> ? R : Repository;
|
|
743
|
-
}) & (IsNever<Base> extends true ? {} : NarrowDiscriminator<Omit<Base, typeof PrimaryKeyProp>, BaseDiscriminatorColumn, DiscriminatorValue>) & (ForceObject extends true ? {
|
|
762
|
+
}) & (IsNever<Base> extends true ? {} : NarrowDiscriminator<Omit<Base, typeof PrimaryKeyProp>, BaseDiscriminatorColumn, DiscriminatorValue, Embeddable>) & (ForceObject extends true ? {
|
|
744
763
|
[Config]?: DefineConfig<{
|
|
745
764
|
forceObject: true;
|
|
746
765
|
}>;
|
|
@@ -748,13 +767,26 @@ export type InferEntityFromProperties<Properties extends Record<string, any>, PK
|
|
|
748
767
|
[IndexHints]?: [Omit<ExtractBaseProperties<Base>, keyof Properties> & Properties];
|
|
749
768
|
};
|
|
750
769
|
type ExtractBaseProperties<Base> = [ExtractDefineEntityProperties<Base>] extends [infer P extends Record<string, any>] ? [P] extends [never] ? {} : P : {};
|
|
751
|
-
type
|
|
770
|
+
type ExtractOptionalProps<Base> = Base extends {
|
|
771
|
+
[OptionalProps]?: infer K;
|
|
772
|
+
} ? (K extends string ? K : never) : never;
|
|
773
|
+
type NarrowDiscriminator<Base, DiscColumn extends string | undefined, DiscValue, Embeddable extends boolean = false> = DiscColumn extends string ? DiscColumn extends keyof Base ? DiscValue extends string | number ? Embeddable extends true ? Omit<Base, DiscColumn> & {
|
|
774
|
+
[K in DiscColumn]: DiscValue;
|
|
775
|
+
} : Omit<Base, DiscColumn | typeof OptionalProps> & {
|
|
752
776
|
[K in DiscColumn]: DiscValue;
|
|
777
|
+
} & {
|
|
778
|
+
[OptionalProps]?: DiscColumn | ExtractOptionalProps<Base>;
|
|
753
779
|
} : Base : Base : Base;
|
|
754
780
|
type InferCombinedPrimaryKey<Properties extends Record<string, any>, PK, Base> = PK extends undefined ? CombinePrimaryKeys<InferPrimaryKey<Properties>, ExtractBasePrimaryKey<Base>> : PK;
|
|
755
|
-
type ExtractBasePrimaryKey<Base> = Base extends {
|
|
781
|
+
type ExtractBasePrimaryKey<Base> = typeof PrimaryKeyProp extends keyof Base ? Base extends {
|
|
756
782
|
[PrimaryKeyProp]?: infer BasePK;
|
|
757
|
-
} ? BasePK : never
|
|
783
|
+
} ? BasePK : never : [keyof Base] extends [never] ? never : Base extends {
|
|
784
|
+
_id?: any;
|
|
785
|
+
} ? '_id' : Base extends {
|
|
786
|
+
id?: any;
|
|
787
|
+
} ? 'id' : Base extends {
|
|
788
|
+
uuid?: any;
|
|
789
|
+
} ? 'uuid' : never;
|
|
758
790
|
type CombinePrimaryKeys<ChildPK, BasePK> = [ChildPK] extends [never] ? BasePK : [BasePK] extends [never] ? IsUnion<ChildPK> extends true ? ChildPK[] : ChildPK : ChildPK | BasePK;
|
|
759
791
|
/** Extracts the primary key property names from a properties map by finding builders with `primary: true`. */
|
|
760
792
|
export type InferPrimaryKey<Properties extends Record<string, any>> = {
|
|
@@ -781,6 +813,8 @@ type InferBuilderValue<Builder> = Builder extends {
|
|
|
781
813
|
type MaybeArray<Value, Options> = Options extends {
|
|
782
814
|
array: true;
|
|
783
815
|
} ? Value[] : Value;
|
|
816
|
+
/** The runtime value passed to a custom serializer — the property value as stored on the entity (e.g. `Collection`/`Ref` for relations). Skips `MaybeMapToPk`, as its `Primary<Value>` branch is too costly for the type checker. */
|
|
817
|
+
type SerializerValue<Value, Options> = MaybeNullable<MaybeRelationRef<MaybeArray<Value, Options>, Options>, Options>;
|
|
784
818
|
type MaybeMapToPk<Value, Options> = Options extends {
|
|
785
819
|
mapToPk: true;
|
|
786
820
|
} ? Primary<Value> : Value;
|
package/entity/defineEntity.js
CHANGED
|
@@ -403,6 +403,10 @@ export class UniversalPropertyOptionsBuilder {
|
|
|
403
403
|
pivotTable(pivotTable) {
|
|
404
404
|
return this.assignOptions({ pivotTable });
|
|
405
405
|
}
|
|
406
|
+
/** Resolve this read-only to-one relation via a subquery on another entity (see {@doclink relationships#to-one-relations-through-another-entity | To-one relations through another entity}). */
|
|
407
|
+
through(through) {
|
|
408
|
+
return this.assignOptions({ through });
|
|
409
|
+
}
|
|
406
410
|
/** Set pivot entity for this relation (see {@doclink collections#custom-pivot-table-entity | Custom pivot table entity}). */
|
|
407
411
|
pivotEntity(pivotEntity) {
|
|
408
412
|
return this.assignOptions({ pivotEntity });
|
|
@@ -472,10 +476,31 @@ export class UniversalPropertyOptionsBuilder {
|
|
|
472
476
|
}
|
|
473
477
|
}
|
|
474
478
|
/** @internal */
|
|
479
|
+
export class StringPropertyOptionsBuilder extends UniversalPropertyOptionsBuilder {
|
|
480
|
+
trim() {
|
|
481
|
+
return this.withOptions({ trim: true });
|
|
482
|
+
}
|
|
483
|
+
lowercase() {
|
|
484
|
+
return this.withOptions({ case: 'lower' });
|
|
485
|
+
}
|
|
486
|
+
uppercase() {
|
|
487
|
+
return this.withOptions({ case: 'upper' });
|
|
488
|
+
}
|
|
489
|
+
withOptions(options) {
|
|
490
|
+
const type = this['~options'].type;
|
|
491
|
+
const TypeClass = typeof type === 'function' ? type : type.constructor;
|
|
492
|
+
const currentOptions = typeof type === 'function' ? {} : type.options;
|
|
493
|
+
return new StringPropertyOptionsBuilder({
|
|
494
|
+
...this['~options'],
|
|
495
|
+
type: new TypeClass({ ...currentOptions, ...options }),
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/** @internal */
|
|
475
500
|
export class OneToManyOptionsBuilderOnlyMappedBy extends UniversalPropertyOptionsBuilder {
|
|
476
501
|
/** Point to the owning side property name. */
|
|
477
502
|
mappedBy(mappedBy) {
|
|
478
|
-
return
|
|
503
|
+
return this.assignOptions({ mappedBy });
|
|
479
504
|
}
|
|
480
505
|
}
|
|
481
506
|
function createPropertyBuilders(options) {
|
|
@@ -487,6 +512,12 @@ const propertyBuilders = {
|
|
|
487
512
|
array: (toJsValue = i => i, toDbValue = i => i) => new UniversalPropertyOptionsBuilder({ type: new types.array(toJsValue, toDbValue) }),
|
|
488
513
|
decimal: (mode) => new UniversalPropertyOptionsBuilder({ type: new types.decimal(mode) }),
|
|
489
514
|
json: () => new UniversalPropertyOptionsBuilder({ type: types.json }),
|
|
515
|
+
string: () => new StringPropertyOptionsBuilder({
|
|
516
|
+
type: types.string,
|
|
517
|
+
}),
|
|
518
|
+
text: () => new StringPropertyOptionsBuilder({
|
|
519
|
+
type: types.text,
|
|
520
|
+
}),
|
|
490
521
|
formula: (formula) => new UniversalPropertyOptionsBuilder({ formula }),
|
|
491
522
|
datetime: (length) => new UniversalPropertyOptionsBuilder({ type: types.datetime, length }),
|
|
492
523
|
time: (length) => new UniversalPropertyOptionsBuilder({ type: types.time, length }),
|
package/enums.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EntityKey, ExpandProperty } from './typings.js';
|
|
1
|
+
import type { EntityKey, ExpandProperty, SessionContext } from './typings.js';
|
|
2
2
|
import type { InflightQueryAbortStrategy, Transaction } from './connections/Connection.js';
|
|
3
3
|
import type { LogContext } from './logging/Logger.js';
|
|
4
4
|
/** Controls when the `EntityManager` flushes pending changes to the database. */
|
|
@@ -39,6 +39,8 @@ export declare enum QueryOperator {
|
|
|
39
39
|
$in = "in",
|
|
40
40
|
/** Not included in the given list. */
|
|
41
41
|
$nin = "not in",
|
|
42
|
+
/** Contains all of the given values, supported on collection properties and on mongo arrays. */
|
|
43
|
+
$all = "all",
|
|
42
44
|
/** Greater than. */
|
|
43
45
|
$gt = ">",
|
|
44
46
|
/** Greater than or equal to. */
|
|
@@ -307,6 +309,8 @@ export interface TransactionOptions {
|
|
|
307
309
|
flushMode?: FlushMode | `${FlushMode}`;
|
|
308
310
|
ignoreNestedTransactions?: boolean;
|
|
309
311
|
loggerContext?: LogContext;
|
|
312
|
+
/** @internal database session context applied on `begin()` (set via `em.setSessionContext()`). */
|
|
313
|
+
sessionContext?: SessionContext;
|
|
310
314
|
/**
|
|
311
315
|
* `AbortSignal` cancelling every query within the transaction (including the implicit flush).
|
|
312
316
|
* Cancelling mid-transaction triggers a rollback once the in-flight query settles.
|
package/enums.js
CHANGED
|
@@ -41,6 +41,8 @@ export var QueryOperator;
|
|
|
41
41
|
QueryOperator["$in"] = "in";
|
|
42
42
|
/** Not included in the given list. */
|
|
43
43
|
QueryOperator["$nin"] = "not in";
|
|
44
|
+
/** Contains all of the given values, supported on collection properties and on mongo arrays. */
|
|
45
|
+
QueryOperator["$all"] = "all";
|
|
44
46
|
/** Greater than. */
|
|
45
47
|
QueryOperator["$gt"] = ">";
|
|
46
48
|
/** Greater than or equal to. */
|
package/errors.d.ts
CHANGED
|
@@ -25,6 +25,13 @@ export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Er
|
|
|
25
25
|
static invalidCompositeIdentifier(meta: EntityMetadata): ValidationError;
|
|
26
26
|
static cannotCommit(): ValidationError;
|
|
27
27
|
static cannotUseGlobalContext(): ValidationError;
|
|
28
|
+
static sessionContextNotSupported(): ValidationError;
|
|
29
|
+
static sessionContextRequiresImplicitTransactions(): ValidationError;
|
|
30
|
+
static sessionContextWithDisabledTransactions(): ValidationError;
|
|
31
|
+
static sessionContextInsideTransaction(action?: 'set' | 'clear'): ValidationError;
|
|
32
|
+
static cannotStageNonScalarSessionVariable(filterName: string, argName: string): ValidationError;
|
|
33
|
+
static sessionContextStreamRequiresTransaction(): ValidationError;
|
|
34
|
+
static connectionSessionContextNotSupported(): ValidationError;
|
|
28
35
|
static cannotUseOperatorsInsideEmbeddables(entityName: EntityName, propName: string, payload: unknown): ValidationError;
|
|
29
36
|
static cannotUseGroupOperatorsInsideScalars(entityName: EntityName, propName: string, payload: unknown): ValidationError;
|
|
30
37
|
static invalidEmbeddableQuery(entityName: EntityName, propName: string, embeddableType: string): ValidationError;
|
|
@@ -34,6 +41,7 @@ export declare class ValidationError<T extends AnyEntity = AnyEntity> extends Er
|
|
|
34
41
|
export declare class CursorError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
|
35
42
|
static entityNotPopulated(entity: AnyEntity, prop: string): ValidationError;
|
|
36
43
|
static missingValue(entityName: string, prop: string): ValidationError;
|
|
44
|
+
static invalidCursor(entityName: string, cause: Error): CursorError;
|
|
37
45
|
}
|
|
38
46
|
/** Error thrown when an optimistic lock conflict is detected during entity persistence. */
|
|
39
47
|
export declare class OptimisticLockError<T extends AnyEntity = AnyEntity> extends ValidationError<T> {
|
|
@@ -60,11 +68,15 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
|
|
|
60
68
|
static duplicateFieldName(entityName: EntityName, names: [string, string][]): MetadataError;
|
|
61
69
|
static multipleDecorators(entityName: string, propertyName: string): MetadataError;
|
|
62
70
|
static missingMetadata(entity: string): MetadataError;
|
|
71
|
+
static ambiguousEntityName(className: string): MetadataError;
|
|
63
72
|
static invalidPrimaryKey(meta: EntityMetadata, prop: EntityProperty, requiredName: string): MetadataError;
|
|
64
73
|
static invalidManyToManyWithPivotEntity(meta1: EntityMetadata, prop1: EntityProperty, meta2: EntityMetadata, prop2: EntityProperty): MetadataError;
|
|
65
74
|
static targetIsAbstract(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
|
66
75
|
static nonPersistentCompositeProp(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
|
67
76
|
static propertyTargetsEntityType(meta: EntityMetadata, prop: EntityProperty, target: EntityMetadata): MetadataError;
|
|
77
|
+
static throughRelationMissingProperty(meta: EntityMetadata, prop: EntityProperty, through: EntityMetadata, side: 'owner' | 'target'): MetadataError;
|
|
78
|
+
static throughRelationCompositeTarget(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
|
79
|
+
static throughRelationInvalidKind(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
|
68
80
|
static fromMissingOption(meta: EntityMetadata, prop: EntityProperty, option: string): MetadataError;
|
|
69
81
|
static targetKeyOnManyToMany(meta: EntityMetadata, prop: EntityProperty): MetadataError;
|
|
70
82
|
static targetKeyNotUnique(meta: EntityMetadata, prop: EntityProperty, target?: EntityMetadata): MetadataError;
|
|
@@ -76,6 +88,30 @@ export declare class MetadataError<T extends AnyEntity = AnyEntity> extends Vali
|
|
|
76
88
|
static tptNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
|
77
89
|
/** Thrown when database triggers are defined on an entity using a driver that does not support them. */
|
|
78
90
|
static triggersNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
|
91
|
+
/** Thrown when row level security is declared on an entity using a driver that does not support it. */
|
|
92
|
+
static rowLevelSecurityNotSupportedByDriver(meta: EntityMetadata): MetadataError;
|
|
93
|
+
/** Thrown when row level security is declared on a non-root entity of an STI hierarchy. */
|
|
94
|
+
static rowLevelSecurityOnNonRootStiEntity(meta: EntityMetadata): MetadataError;
|
|
95
|
+
/** Thrown when two policies on the same entity are given the same explicit name. */
|
|
96
|
+
static duplicatePolicyName(meta: EntityMetadata, name: string): MetadataError;
|
|
97
|
+
/** Thrown when a filter flagged with `rls` is declared on a driver that does not support row level security. */
|
|
98
|
+
static rlsFilterNotSupportedByDriver(meta: EntityMetadata, filterName: string): MetadataError;
|
|
99
|
+
/** Thrown when a filter flagged with `rls` is declared on a non-root entity of an STI hierarchy. */
|
|
100
|
+
static rlsFilterOnNonRootStiEntity(meta: EntityMetadata, filterName: string): MetadataError;
|
|
101
|
+
/** Thrown when a global (config or EM registered) filter is flagged with `rls`; RLS filters must be entity scoped. */
|
|
102
|
+
static rlsFilterMustBeEntityScoped(filterName: string): MetadataError;
|
|
103
|
+
/** Thrown when an entity-scoped `rls` filter is registered at runtime via `em.addFilter()` instead of in metadata. */
|
|
104
|
+
static rlsFilterCannotBeRegisteredAtRuntime(filterName: string): MetadataError;
|
|
105
|
+
/** Thrown when a filter's custom `setting` is used with more than one argument. */
|
|
106
|
+
static rlsFilterMultiArgSetting(filterName: string, args: string[]): MetadataError;
|
|
107
|
+
/** Thrown when an `rls` filter's condition depends on runtime state and cannot be compiled to a static policy. */
|
|
108
|
+
static rlsFilterDependsOnRuntimeState(filterName: string): MetadataError;
|
|
109
|
+
/** Thrown when an `rls` filter compares against a column whose type has no automatic session-variable cast. */
|
|
110
|
+
static rlsFilterUncastableType(filterName: string, columnType: string): MetadataError;
|
|
111
|
+
/** Thrown when an `rls` filter references an argument outside of a direct comparison, which cannot be compiled. */
|
|
112
|
+
static rlsFilterUnsupportedCond(filterName: string): MetadataError;
|
|
113
|
+
/** Thrown when an `rls` filter compares against a column the schema generator does not manage. */
|
|
114
|
+
static rlsFilterUnmanagedColumn(filterName: string, column: string): MetadataError;
|
|
79
115
|
private static fromMessage;
|
|
80
116
|
}
|
|
81
117
|
/** Error thrown when an entity lookup fails to find the expected result. */
|
package/errors.js
CHANGED
|
@@ -94,6 +94,30 @@ export class ValidationError extends Error {
|
|
|
94
94
|
static cannotUseGlobalContext() {
|
|
95
95
|
return new ValidationError("Using global EntityManager instance methods for context specific actions is disallowed. If you need to work with the global instance's identity map, use `allowGlobalContext` configuration option or `fork()` instead.");
|
|
96
96
|
}
|
|
97
|
+
static sessionContextNotSupported() {
|
|
98
|
+
return new ValidationError('Database session context (row level security) is only supported by the PostgreSQL driver. To test a PostgreSQL app without a server, use the `@mikro-orm/pglite` driver instead of sqlite.');
|
|
99
|
+
}
|
|
100
|
+
static sessionContextRequiresImplicitTransactions() {
|
|
101
|
+
return new ValidationError("Cannot set a database session context (row level security) with the 'transaction' strategy while 'implicitTransactions' is disabled. The context is applied on transaction begin, but writes would run without a transaction and silently bypass the policies. Enable 'implicitTransactions', wrap the work in 'em.transactional()', or use the 'connection' session context strategy.");
|
|
102
|
+
}
|
|
103
|
+
static sessionContextWithDisabledTransactions() {
|
|
104
|
+
return new ValidationError("Cannot set a database session context (row level security) with the 'transaction' strategy while transactions are disabled via 'disableTransactions'. The context is applied on transaction begin, so flushes would run without it and silently bypass the policies. Enable transactions, or use the 'connection' session context strategy.");
|
|
105
|
+
}
|
|
106
|
+
static sessionContextInsideTransaction(action = 'set') {
|
|
107
|
+
const advice = action === 'set'
|
|
108
|
+
? "Set the session context before starting the transaction (e.g. via 'em.fork({ session })')."
|
|
109
|
+
: 'Clear the session context outside the transaction.';
|
|
110
|
+
return new ValidationError(`Cannot ${action} a database session context (row level security) inside an active transaction. The context is applied when the transaction begins or the connection is reserved, so the change would never reach an already-open transaction (with the 'connection' strategy the pinned connection was reserved with the previous context). ${advice}`);
|
|
111
|
+
}
|
|
112
|
+
static cannotStageNonScalarSessionVariable(filterName, argName) {
|
|
113
|
+
return new ValidationError(`Cannot stage the '${argName}' argument of filter '${filterName}' as a session variable (row level security) — only scalar values (string, number, boolean, Date) can be mirrored to the database policy backing the filter.`);
|
|
114
|
+
}
|
|
115
|
+
static sessionContextStreamRequiresTransaction() {
|
|
116
|
+
return new ValidationError("Cannot stream under a database session context (row level security) with the 'transaction' strategy outside a transaction. Streaming never opens the implicit transaction that applies the context, so the streamed rows would not be scoped by it (other tenants' rows would leak). Wrap the stream in 'em.transactional()', or use the 'connection' session context strategy.");
|
|
117
|
+
}
|
|
118
|
+
static connectionSessionContextNotSupported() {
|
|
119
|
+
return new ValidationError("The 'connection' session context strategy requires a driver that supports per-acquire connection hooks (the `postgresql` driver). Use the default 'transaction' strategy instead.");
|
|
120
|
+
}
|
|
97
121
|
static cannotUseOperatorsInsideEmbeddables(entityName, propName, payload) {
|
|
98
122
|
return new ValidationError(`Using operators inside embeddables is not allowed, move the operator above. (property: ${Utils.className(entityName)}.${propName}, payload: ${inspect(payload)})`);
|
|
99
123
|
}
|
|
@@ -116,6 +140,11 @@ export class CursorError extends ValidationError {
|
|
|
116
140
|
static missingValue(entityName, prop) {
|
|
117
141
|
return new CursorError(`Invalid cursor condition, value for '${entityName}.${prop}' is missing.`);
|
|
118
142
|
}
|
|
143
|
+
static invalidCursor(entityName, cause) {
|
|
144
|
+
const error = new CursorError(`Invalid cursor for entity ${entityName}: ${cause.message}`);
|
|
145
|
+
error.cause = cause;
|
|
146
|
+
return error;
|
|
147
|
+
}
|
|
119
148
|
}
|
|
120
149
|
/** Error thrown when an optimistic lock conflict is detected during entity persistence. */
|
|
121
150
|
export class OptimisticLockError extends ValidationError {
|
|
@@ -195,6 +224,9 @@ export class MetadataError extends ValidationError {
|
|
|
195
224
|
static missingMetadata(entity) {
|
|
196
225
|
return new MetadataError(`Metadata for entity ${entity} not found`);
|
|
197
226
|
}
|
|
227
|
+
static ambiguousEntityName(className) {
|
|
228
|
+
return new MetadataError(`Entity name '${className}' is ambiguous, multiple discovered entity classes share it (possibly due to a minifier mangling class names). Use a class reference instead of a string name.`);
|
|
229
|
+
}
|
|
198
230
|
static invalidPrimaryKey(meta, prop, requiredName) {
|
|
199
231
|
return this.fromMessage(meta, prop, `has wrong field name, '${requiredName}' is required in current driver`);
|
|
200
232
|
}
|
|
@@ -214,6 +246,16 @@ export class MetadataError extends ValidationError {
|
|
|
214
246
|
const suggestion = target.embeddable ? 'Embedded' : 'ManyToOne';
|
|
215
247
|
return this.fromMessage(meta, prop, `is defined as scalar @Property(), but its type is a discovered entity ${target.className}. Maybe you want to use @${suggestion}() decorator instead?`);
|
|
216
248
|
}
|
|
249
|
+
static throughRelationMissingProperty(meta, prop, through, side) {
|
|
250
|
+
const target = side === 'owner' ? meta.className : prop.targetMeta.className;
|
|
251
|
+
return this.fromMessage(meta, prop, `uses 'through' entity ${through.className} which has no ManyToOne property pointing to ${target}`);
|
|
252
|
+
}
|
|
253
|
+
static throughRelationCompositeTarget(meta, prop) {
|
|
254
|
+
return this.fromMessage(meta, prop, `uses 'through' option which is not supported for targets with composite primary key`);
|
|
255
|
+
}
|
|
256
|
+
static throughRelationInvalidKind(meta, prop) {
|
|
257
|
+
return this.fromMessage(meta, prop, `uses 'through' option which is only supported for ManyToOne and OneToOne relations`);
|
|
258
|
+
}
|
|
217
259
|
static fromMissingOption(meta, prop, option) {
|
|
218
260
|
return this.fromMessage(meta, prop, `is missing '${option}' option`);
|
|
219
261
|
}
|
|
@@ -247,6 +289,54 @@ export class MetadataError extends ValidationError {
|
|
|
247
289
|
static triggersNotSupportedByDriver(meta) {
|
|
248
290
|
return new MetadataError(`Entity ${meta.className} defines database triggers which are not supported by the current driver. Triggers are only available with SQL drivers.`);
|
|
249
291
|
}
|
|
292
|
+
/** Thrown when row level security is declared on an entity using a driver that does not support it. */
|
|
293
|
+
static rowLevelSecurityNotSupportedByDriver(meta) {
|
|
294
|
+
return new MetadataError(`Entity ${meta.className} declares row level security which is not supported by the current driver. Row level security is only available with the PostgreSQL driver. To test a PostgreSQL app without a server, use the \`@mikro-orm/pglite\` driver instead of sqlite.`);
|
|
295
|
+
}
|
|
296
|
+
/** Thrown when row level security is declared on a non-root entity of an STI hierarchy. */
|
|
297
|
+
static rowLevelSecurityOnNonRootStiEntity(meta) {
|
|
298
|
+
return new MetadataError(`Entity ${meta.className} declares row level security, but it is part of a single table inheritance hierarchy. Declare policies on the root entity ${meta.root.className} instead, as the whole hierarchy shares a single table.`);
|
|
299
|
+
}
|
|
300
|
+
/** Thrown when two policies on the same entity are given the same explicit name. */
|
|
301
|
+
static duplicatePolicyName(meta, name) {
|
|
302
|
+
return new MetadataError(`Entity ${meta.className} declares multiple row level security policies named '${name}'. Policy names must be unique per table; rename one of them or omit the name to use an auto-generated one.`);
|
|
303
|
+
}
|
|
304
|
+
/** Thrown when a filter flagged with `rls` is declared on a driver that does not support row level security. */
|
|
305
|
+
static rlsFilterNotSupportedByDriver(meta, filterName) {
|
|
306
|
+
return new MetadataError(`Filter '${filterName}' on entity ${meta.className} is flagged with 'rls', which is only supported by the PostgreSQL driver. To test a PostgreSQL app without a server, use the \`@mikro-orm/pglite\` driver instead of sqlite.`);
|
|
307
|
+
}
|
|
308
|
+
/** Thrown when a filter flagged with `rls` is declared on a non-root entity of an STI hierarchy. */
|
|
309
|
+
static rlsFilterOnNonRootStiEntity(meta, filterName) {
|
|
310
|
+
return new MetadataError(`Filter '${filterName}' on entity ${meta.className} is flagged with 'rls', but the entity is part of a single table inheritance hierarchy. Declare the filter on the root entity ${meta.root.className} instead, as the whole hierarchy shares a single table and the policy would never be created otherwise.`);
|
|
311
|
+
}
|
|
312
|
+
/** Thrown when a global (config or EM registered) filter is flagged with `rls`; RLS filters must be entity scoped. */
|
|
313
|
+
static rlsFilterMustBeEntityScoped(filterName) {
|
|
314
|
+
return new MetadataError(`Filter '${filterName}' is a global filter and cannot be flagged with 'rls'. RLS filters must be declared on an entity via @Filter() so a policy can be attached to its table.`);
|
|
315
|
+
}
|
|
316
|
+
/** Thrown when an entity-scoped `rls` filter is registered at runtime via `em.addFilter()` instead of in metadata. */
|
|
317
|
+
static rlsFilterCannotBeRegisteredAtRuntime(filterName) {
|
|
318
|
+
return new MetadataError(`Filter '${filterName}' cannot be flagged with 'rls' when registered at runtime via 'em.addFilter()'. RLS filters must be declared in entity metadata via the @Filter() decorator (or the entity 'filters' option) so a policy can be attached to the table.`);
|
|
319
|
+
}
|
|
320
|
+
/** Thrown when a filter's custom `setting` is used with more than one argument. */
|
|
321
|
+
static rlsFilterMultiArgSetting(filterName, args) {
|
|
322
|
+
return new MetadataError(`Filter '${filterName}' sets a custom 'setting' but references multiple arguments (${args.join(', ')}). A custom 'setting' is only allowed for single-argument RLS filters; remove it to use the default 'mikro.${filterName}.<arg>' names.`);
|
|
323
|
+
}
|
|
324
|
+
/** Thrown when an `rls` filter's condition depends on runtime state and cannot be compiled to a static policy. */
|
|
325
|
+
static rlsFilterDependsOnRuntimeState(filterName) {
|
|
326
|
+
return new MetadataError(`Filter '${filterName}' cannot be compiled to an RLS policy because its condition depends on runtime state (it accesses 'em', 'type', 'options' or 'entityName', or resolves asynchronously). Declare an explicit policy instead.`);
|
|
327
|
+
}
|
|
328
|
+
/** Thrown when an `rls` filter compares against a column whose type has no automatic session-variable cast. */
|
|
329
|
+
static rlsFilterUncastableType(filterName, columnType) {
|
|
330
|
+
return new MetadataError(`Filter '${filterName}' cannot be compiled to an RLS policy because the column type '${columnType}' has no automatic session-variable cast. Declare an explicit policy instead.`);
|
|
331
|
+
}
|
|
332
|
+
/** Thrown when an `rls` filter references an argument outside of a direct comparison, which cannot be compiled. */
|
|
333
|
+
static rlsFilterUnsupportedCond(filterName) {
|
|
334
|
+
return new MetadataError(`Filter '${filterName}' cannot be compiled to an RLS policy because it references an argument outside of a direct comparison (only expressions like { prop: args.x } are supported). Declare an explicit policy instead.`);
|
|
335
|
+
}
|
|
336
|
+
/** Thrown when an `rls` filter compares against a column the schema generator does not manage. */
|
|
337
|
+
static rlsFilterUnmanagedColumn(filterName, column) {
|
|
338
|
+
return new MetadataError(`Filter '${filterName}' cannot be compiled to an RLS policy because column '${column}' is not part of the managed schema (e.g. the property is marked 'persist: false' or the column is excluded via 'skipColumns'). Declare an explicit policy instead.`);
|
|
339
|
+
}
|
|
250
340
|
static fromMessage(meta, prop, message) {
|
|
251
341
|
return new MetadataError(`${meta.className}.${prop.name} ${message}`);
|
|
252
342
|
}
|
package/events/EventManager.js
CHANGED
|
@@ -43,7 +43,10 @@ export class EventManager {
|
|
|
43
43
|
}));
|
|
44
44
|
for (const listener of this.#listeners[event] ?? new Set()) {
|
|
45
45
|
const entities = this.#entities.get(listener);
|
|
46
|
-
if (entities.size === 0 ||
|
|
46
|
+
if (entities.size === 0 ||
|
|
47
|
+
!entity ||
|
|
48
|
+
entities.has(entity.constructor) ||
|
|
49
|
+
entities.has(entity.constructor.name)) {
|
|
47
50
|
listeners.push(listener[event].bind(listener));
|
|
48
51
|
}
|
|
49
52
|
}
|
|
@@ -68,7 +71,7 @@ export class EventManager {
|
|
|
68
71
|
}
|
|
69
72
|
for (const listener of this.#listeners[event] ?? new Set()) {
|
|
70
73
|
const entities = this.#entities.get(listener);
|
|
71
|
-
if (entities.size === 0 || entities.has(meta.className)) {
|
|
74
|
+
if (entities.size === 0 || entities.has(meta.class) || entities.has(meta.className)) {
|
|
72
75
|
this.#cache.set(cacheKey, true);
|
|
73
76
|
return true;
|
|
74
77
|
}
|
|
@@ -84,6 +87,6 @@ export class EventManager {
|
|
|
84
87
|
if (!listener.getSubscribedEntities) {
|
|
85
88
|
return new Set();
|
|
86
89
|
}
|
|
87
|
-
return new Set(listener.getSubscribedEntities().map(name => Utils.
|
|
90
|
+
return new Set(listener.getSubscribedEntities().map(name => Utils.classOrName(name)));
|
|
88
91
|
}
|
|
89
92
|
}
|
package/exceptions.d.ts
CHANGED
|
@@ -102,3 +102,8 @@ export declare class TableNotFoundException extends DatabaseObjectNotFoundExcept
|
|
|
102
102
|
*/
|
|
103
103
|
export declare class UniqueConstraintViolationException extends ConstraintViolationException {
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Exception for a row-level security policy violation (failed `WITH CHECK`) detected in the driver.
|
|
107
|
+
*/
|
|
108
|
+
export declare class RowLevelSecurityViolationException extends ConstraintViolationException {
|
|
109
|
+
}
|
package/exceptions.js
CHANGED
|
@@ -115,3 +115,8 @@ export class TableNotFoundException extends DatabaseObjectNotFoundException {
|
|
|
115
115
|
*/
|
|
116
116
|
export class UniqueConstraintViolationException extends ConstraintViolationException {
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Exception for a row-level security policy violation (failed `WITH CHECK`) detected in the driver.
|
|
120
|
+
*/
|
|
121
|
+
export class RowLevelSecurityViolationException extends ConstraintViolationException {
|
|
122
|
+
}
|
|
@@ -19,6 +19,8 @@ export declare class ObjectHydrator extends Hydrator {
|
|
|
19
19
|
getEntityHydrator<T extends object>(meta: EntityMetadata<T>, type: 'full' | 'reference', normalizeAccessors?: boolean): EntityHydrator<T>;
|
|
20
20
|
private createCollectionItemMapper;
|
|
21
21
|
private wrap;
|
|
22
|
+
/** Renders a key as a single-quoted JS string literal, safe to embed in generated code. */
|
|
23
|
+
private quote;
|
|
22
24
|
private safeKey;
|
|
23
25
|
}
|
|
24
26
|
export {};
|
|
@@ -87,7 +87,7 @@ export class ObjectHydrator extends Hydrator {
|
|
|
87
87
|
ret.push(` if (data${dataKey} === null) {`);
|
|
88
88
|
if (prop.ref) {
|
|
89
89
|
ret.push(` entity${entityKey} = new ScalarReference();`);
|
|
90
|
-
ret.push(` entity${entityKey}.bind(entity,
|
|
90
|
+
ret.push(` entity${entityKey}.bind(entity, ${this.quote(prop.name)});`);
|
|
91
91
|
ret.push(` entity${entityKey}.set(${nullVal});`);
|
|
92
92
|
}
|
|
93
93
|
else {
|
|
@@ -127,14 +127,14 @@ export class ObjectHydrator extends Hydrator {
|
|
|
127
127
|
if (prop.ref) {
|
|
128
128
|
ret.push(` const value = isScalarReference(entity${entityKey}) ? entity${entityKey}.unwrap() : entity${entityKey};`);
|
|
129
129
|
ret.push(` entity${entityKey} = oldValue_${idx} ?? new ScalarReference(value);`);
|
|
130
|
-
ret.push(` entity${entityKey}.bind(entity,
|
|
130
|
+
ret.push(` entity${entityKey}.bind(entity, ${this.quote(prop.name)});`);
|
|
131
131
|
ret.push(` entity${entityKey}.set(value);`);
|
|
132
132
|
}
|
|
133
133
|
ret.push(` }`);
|
|
134
134
|
if (prop.ref) {
|
|
135
135
|
ret.push(` if (!entity${entityKey}) {`);
|
|
136
136
|
ret.push(` entity${entityKey} = new ScalarReference();`);
|
|
137
|
-
ret.push(` entity${entityKey}.bind(entity,
|
|
137
|
+
ret.push(` entity${entityKey}.bind(entity, ${this.quote(prop.name)});`);
|
|
138
138
|
ret.push(` }`);
|
|
139
139
|
}
|
|
140
140
|
return ret;
|
|
@@ -220,7 +220,7 @@ export class ObjectHydrator extends Hydrator {
|
|
|
220
220
|
ret.push(` }`);
|
|
221
221
|
ret.push(` if (Array.isArray(data${dataKey})) {`);
|
|
222
222
|
ret.push(` const items = data${dataKey}.map(value => createCollectionItem_${this.safeKey(prop.name)}(value, entity));`);
|
|
223
|
-
ret.push(` const coll = Collection.create(entity,
|
|
223
|
+
ret.push(` const coll = Collection.create(entity, ${this.quote(prop.name)}, items, newEntity);`);
|
|
224
224
|
ret.push(` if (newEntity) {`);
|
|
225
225
|
ret.push(` coll.setDirty();`);
|
|
226
226
|
ret.push(` } else {`);
|
|
@@ -231,11 +231,11 @@ export class ObjectHydrator extends Hydrator {
|
|
|
231
231
|
if (!this.platform.usesPivotTable() && prop.owner && prop.kind === ReferenceKind.MANY_TO_MANY) {
|
|
232
232
|
ret.push(` } else if (!entity${entityKey} && Array.isArray(data${dataKey})) {`);
|
|
233
233
|
const items = this.platform.usesPivotTable() || !prop.owner ? 'undefined' : '[]';
|
|
234
|
-
ret.push(` const coll = Collection.create(entity,
|
|
234
|
+
ret.push(` const coll = Collection.create(entity, ${this.quote(prop.name)}, ${items}, !!data${dataKey} || newEntity);`);
|
|
235
235
|
ret.push(` coll.setDirty(false);`);
|
|
236
236
|
}
|
|
237
237
|
ret.push(` } else if (!entity${entityKey}) {`);
|
|
238
|
-
ret.push(` const coll = Collection.create(entity,
|
|
238
|
+
ret.push(` const coll = Collection.create(entity, ${this.quote(prop.name)}, undefined, newEntity);`);
|
|
239
239
|
ret.push(` coll.setDirty(false);`);
|
|
240
240
|
ret.push(` }`);
|
|
241
241
|
return ret;
|
|
@@ -431,10 +431,14 @@ export class ObjectHydrator extends Hydrator {
|
|
|
431
431
|
return lines;
|
|
432
432
|
}
|
|
433
433
|
wrap(key) {
|
|
434
|
-
if (/^\[
|
|
434
|
+
if (/^\[idx_\d+]$/.exec(key)) {
|
|
435
435
|
return key;
|
|
436
436
|
}
|
|
437
|
-
return /^\w+$/.exec(key) ? `.${key}` : `[
|
|
437
|
+
return /^\w+$/.exec(key) ? `.${key}` : `[${this.quote(key)}]`;
|
|
438
|
+
}
|
|
439
|
+
/** Renders a key as a single-quoted JS string literal, safe to embed in generated code. */
|
|
440
|
+
quote(key) {
|
|
441
|
+
return `'${key.replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`;
|
|
438
442
|
}
|
|
439
443
|
safeKey(key) {
|
|
440
444
|
return key.replace(/\W/g, '_');
|
package/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @module core
|
|
4
4
|
*/
|
|
5
5
|
export { EntityMetadata, PrimaryKeyProp, EntityRepositoryType, OptionalProps, EagerProps, HiddenProps, Config, EntityName, IndexHints, } from './typings.js';
|
|
6
|
-
export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IndexFilterQuery, ExtractIndexHints, ExtractDefineEntityProperties, IndexName, IndexColumns, WithUsingOptions, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, TriggerCallback, IndexCallback, FormulaCallback, FormulaColumns, FormulaTable, SchemaTable, SchemaColumns, SchemaColumnRef, EntityDataPropValue, SimpleColumnMeta, Rel, Ref, LazyRef, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, TriggerDef, RoutineReturns, RoutineBodyCallback, RoutineJsBody, RoutineIgnoreField, RoutineParamConfig, RoutineConfig, RoutineRuntimeType, RoutineArgs, RoutineReturn, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
|
|
6
|
+
export type { CompiledFunctions, Constructor, ConnectionType, Dictionary, Primary, IPrimaryKey, ObjectQuery, FilterQuery, IWrappedEntity, InferEntityName, EntityData, Highlighter, MaybePromise, AnyEntity, EntityClass, EntityProperty, PopulateOptions, Populate, Loaded, New, LoadedReference, LoadedCollection, IMigrator, IMigrationGenerator, MigratorEvent, GetRepository, MigrationObject, DeepPartial, PrimaryProperty, Cast, IsUnknown, EntityDictionary, EntityDTO, EntityDTOFlat, EntityDTOProp, SerializeDTO, MigrationDiff, GenerateOptions, FilterObject, IndexFilterQuery, ExtractIndexHints, ExtractDefineEntityProperties, IndexName, IndexColumns, WithUsingOptions, IMigrationRunner, IEntityGenerator, ISeedManager, SeederObject, IMigratorStorage, RequiredEntityData, CheckCallback, TriggerCallback, IndexCallback, FormulaCallback, FormulaColumns, FormulaTable, SchemaTable, SchemaColumns, SchemaColumnRef, EntityDataPropValue, SimpleColumnMeta, Rel, Ref, LazyRef, ScalarRef, EntityRef, ISchemaGenerator, MigrationInfo, MigrateOptions, MigrationResult, MigrationRow, EntityKey, EntityValue, EntityDataValue, FilterKey, EntityType, FromEntityType, Selected, IsSubset, EntityProps, ExpandProperty, ExpandScalar, FilterItemValue, ExpandQuery, Scalar, ExpandHint, FilterValue, MergeLoaded, MergeSelected, TypeConfig, AnyString, ClearDatabaseOptions, CreateSchemaOptions, EnsureDatabaseOptions, UpdateSchemaOptions, DropSchemaOptions, RefreshDatabaseOptions, AutoPath, UnboxArray, MetadataProcessor, ImportsResolver, RequiredNullable, DefineConfig, Opt, Hidden, EntitySchemaWithMeta, InferEntity, CheckConstraint, TriggerDef, PolicyDef, PolicyCallback, SessionContext, RoutineReturns, RoutineBodyCallback, RoutineJsBody, RoutineIgnoreField, RoutineParamConfig, RoutineConfig, RoutineRuntimeType, RoutineArgs, RoutineReturn, GeneratedColumnCallback, FilterDef, EntityCtor, Subquery, PopulateHintOptions, Prefixes, } from './typings.js';
|
|
7
7
|
export * from './enums.js';
|
|
8
8
|
export * from './errors.js';
|
|
9
9
|
export * from './exceptions.js';
|