@mikro-orm/core 7.3.0-dev.0 → 7.3.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/entity/EntityFactory.js +2 -2
- package/entity/EntityLoader.js +2 -1
- package/entity/defineEntity.d.ts +18 -3
- package/hydration/ObjectHydrator.js +4 -7
- package/metadata/MetadataDiscovery.js +1 -0
- package/metadata/types.d.ts +2 -0
- package/package.json +1 -1
- package/typings.d.ts +4 -0
- package/unit-of-work/UnitOfWork.js +1 -1
- package/utils/Utils.js +1 -1
package/entity/EntityFactory.js
CHANGED
|
@@ -190,7 +190,7 @@ export class EntityFactory {
|
|
|
190
190
|
const initialized = options.initialized || helper(entity).__initialized;
|
|
191
191
|
this.hydrate(entity, meta, diff2, initialized ? { ...options, initialized } : options);
|
|
192
192
|
// we need to update the entity data only with keys that were not present before
|
|
193
|
-
const nullVal = this.#config.get('forceUndefined') ? undefined : null;
|
|
193
|
+
const nullVal = (meta.forceUndefined ?? this.#config.get('forceUndefined')) ? undefined : null;
|
|
194
194
|
Utils.keys(diff2).forEach(key => {
|
|
195
195
|
const prop = meta.properties[key];
|
|
196
196
|
if ([ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind) &&
|
|
@@ -336,7 +336,7 @@ export class EntityFactory {
|
|
|
336
336
|
prop.default == null &&
|
|
337
337
|
!prop.defaultRaw &&
|
|
338
338
|
entity[prop.name] === undefined) {
|
|
339
|
-
entity[prop.name] = (this.#config.get('forceUndefined') ? undefined : null);
|
|
339
|
+
entity[prop.name] = ((meta.forceUndefined ?? this.#config.get('forceUndefined')) ? undefined : null);
|
|
340
340
|
}
|
|
341
341
|
if (prop.kind === ReferenceKind.EMBEDDED && entity[prop.name]) {
|
|
342
342
|
const items = prop.array ? entity[prop.name] : [entity[prop.name]];
|
package/entity/EntityLoader.js
CHANGED
|
@@ -458,7 +458,8 @@ export class EntityLoader {
|
|
|
458
458
|
if ([ReferenceKind.ONE_TO_ONE, ReferenceKind.MANY_TO_ONE].includes(prop.kind) &&
|
|
459
459
|
items.length !== children.length &&
|
|
460
460
|
Utils.isEmpty(options.where)) {
|
|
461
|
-
const
|
|
461
|
+
const ownerMeta = this.#metadata.find(prop.entity());
|
|
462
|
+
const nullVal = (ownerMeta.forceUndefined ?? this.#em.config.get('forceUndefined')) ? undefined : null;
|
|
462
463
|
const itemsMap = new Set();
|
|
463
464
|
const childrenMap = new Set();
|
|
464
465
|
// `e` may be an unresolved reference here, so read the targetKey value directly instead of
|
package/entity/defineEntity.d.ts
CHANGED
|
@@ -631,7 +631,7 @@ type PartialWhere<TProperties, TBase> = string | FilterQuery<{
|
|
|
631
631
|
[K in AllKeys<TProperties, TBase> & string]?: unknown;
|
|
632
632
|
}>;
|
|
633
633
|
/** Metadata descriptor for `defineEntity()`, combining entity options with property definitions. */
|
|
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'> {
|
|
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, TForceUndefined 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'> {
|
|
635
635
|
name: TName;
|
|
636
636
|
tableName?: TTableName;
|
|
637
637
|
extends?: {
|
|
@@ -656,6 +656,8 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
|
|
|
656
656
|
};
|
|
657
657
|
}>;
|
|
658
658
|
forceObject?: TForceObject;
|
|
659
|
+
/** Hydrate `null` as `undefined` for this entity and infer nullable properties as `T | undefined`. */
|
|
660
|
+
forceUndefined?: TForceUndefined;
|
|
659
661
|
embeddable?: TEmbeddable;
|
|
660
662
|
inheritance?: 'tpt';
|
|
661
663
|
orderBy?: {
|
|
@@ -707,7 +709,7 @@ export interface EntityMetadataWithProperties<TName extends string, TTableName e
|
|
|
707
709
|
}[];
|
|
708
710
|
}
|
|
709
711
|
/** Defines an entity schema using property builders, with full type inference from the property definitions. */
|
|
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
|
|
712
|
+
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, const TForceUndefined extends boolean = false>(meta: EntityMetadataWithProperties<TName, TTableName, TProperties, TPK, TBase, TRepository, TForceObject, TDiscriminatorColumn, TDiscriminatorValue, TBaseDiscriminatorColumn, TEmbeddable, TForceUndefined>): EntitySchemaWithMeta<TName, TTableName, MaybeForceUndefined<InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue, TEmbeddable, TForceUndefined>, EffectiveForceUndefined<TForceUndefined, TBase>>, TBase, TProperties, EntityCtor<MaybeForceUndefined<InferEntityFromProperties<TProperties, TPK, TBase, TRepository, TForceObject, TBaseDiscriminatorColumn, TDiscriminatorValue, TEmbeddable, TForceUndefined>, EffectiveForceUndefined<TForceUndefined, TBase>>>, TDiscriminatorColumn>;
|
|
711
713
|
export declare namespace defineEntity {
|
|
712
714
|
export { propertyBuilders as properties };
|
|
713
715
|
}
|
|
@@ -744,8 +746,17 @@ type InferColumnType<T extends string> = T extends 'int' | 'int4' | 'integer' |
|
|
|
744
746
|
type BaseEntityMethodKeys = 'toObject' | 'toPOJO' | 'serialize' | 'assign' | 'populate' | 'init' | 'toReference';
|
|
745
747
|
interface BaseEntityMethods<in out Entity extends object> extends Pick<IWrappedEntity<Entity>, BaseEntityMethodKeys> {
|
|
746
748
|
}
|
|
749
|
+
type MaybeForceUndefined<Entity, ForceUndefined> = [ForceUndefined] extends [true] ? {
|
|
750
|
+
[K in keyof Entity]: SwapNull<Entity[K]>;
|
|
751
|
+
} : Entity;
|
|
752
|
+
type SwapNull<Value> = [Value] extends [ScalarReference<infer Inner>] ? [Extract<keyof Value, symbol>] extends [never] ? ScalarReference<SwapNull<Inner>> : ScalarReference<SwapNull<Inner>> & Pick<Value, Extract<keyof Value, symbol>> : null extends Value ? Exclude<Value, null> | undefined : Value;
|
|
753
|
+
type EffectiveForceUndefined<Flag, Base> = [Flag] extends [true] ? true : IsNever<Base> extends true ? false : [Base] extends [{
|
|
754
|
+
[Config]?: infer C;
|
|
755
|
+
}] ? [NonNullable<C>] extends [{
|
|
756
|
+
forceUndefined: true;
|
|
757
|
+
}] ? true : false : false;
|
|
747
758
|
/** Infers the entity type from a `defineEntity()` properties map, resolving builders, base classes, and primary keys. */
|
|
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 {
|
|
759
|
+
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, ForceUndefined extends boolean = false> = (IsNever<Base> extends true ? {} : Base extends {
|
|
749
760
|
toObject(...args: any[]): any;
|
|
750
761
|
} ? BaseEntityMethods<{
|
|
751
762
|
-readonly [K in keyof Properties]: InferBuilderValue<MaybeReturnType<Properties[K]>>;
|
|
@@ -763,6 +774,10 @@ export type InferEntityFromProperties<Properties extends Record<string, any>, PK
|
|
|
763
774
|
[Config]?: DefineConfig<{
|
|
764
775
|
forceObject: true;
|
|
765
776
|
}>;
|
|
777
|
+
} : {}) & (ForceUndefined extends true ? {
|
|
778
|
+
[Config]?: DefineConfig<{
|
|
779
|
+
forceUndefined: true;
|
|
780
|
+
}>;
|
|
766
781
|
} : {}) & {
|
|
767
782
|
[IndexHints]?: [Omit<ExtractBaseProperties<Base>, keyof Properties> & Properties];
|
|
768
783
|
};
|
|
@@ -50,6 +50,8 @@ export class ObjectHydrator extends Hydrator {
|
|
|
50
50
|
const lines = [];
|
|
51
51
|
const context = new Map();
|
|
52
52
|
const props = this.getProperties(meta, type);
|
|
53
|
+
const forceUndefined = meta.forceUndefined ?? this.config.get('forceUndefined');
|
|
54
|
+
const nullVal = forceUndefined ? 'undefined' : 'null';
|
|
53
55
|
context.set('isPrimaryKey', Utils.isPrimaryKey);
|
|
54
56
|
context.set('isEntity', EntityHelper.isEntity);
|
|
55
57
|
context.set('isScalarReference', ScalarReference.isScalarReference);
|
|
@@ -76,7 +78,6 @@ export class ObjectHydrator extends Hydrator {
|
|
|
76
78
|
.join('_');
|
|
77
79
|
const ret = [];
|
|
78
80
|
const idx = this.#tmpIndex++;
|
|
79
|
-
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
|
80
81
|
if (prop.getter && !prop.setter && prop.persist === false) {
|
|
81
82
|
return [];
|
|
82
83
|
}
|
|
@@ -142,7 +143,6 @@ export class ObjectHydrator extends Hydrator {
|
|
|
142
143
|
const hydrateToOne = (prop, dataKey, entityKey) => {
|
|
143
144
|
const ret = [];
|
|
144
145
|
const method = type === 'reference' ? 'createReference' : 'create';
|
|
145
|
-
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
|
146
146
|
ret.push(` if (data${dataKey} === null) {\n entity${entityKey} = ${nullVal};`);
|
|
147
147
|
ret.push(` } else if (typeof data${dataKey} !== 'undefined') {`);
|
|
148
148
|
// For polymorphic: instanceof check; for regular: isPrimaryKey() check
|
|
@@ -341,8 +341,6 @@ export class ObjectHydrator extends Hydrator {
|
|
|
341
341
|
...hydrateProperty(childProp, prop.object, [...path, childProp.embedded[1]], childDataKey).map(l => ' ' + l));
|
|
342
342
|
});
|
|
343
343
|
}
|
|
344
|
-
/* v8 ignore next */
|
|
345
|
-
const nullVal = this.config.get('forceUndefined') ? 'undefined' : 'null';
|
|
346
344
|
if (prop.object) {
|
|
347
345
|
ret.push(` } else if (data${dataKey} === null) {`);
|
|
348
346
|
}
|
|
@@ -365,8 +363,7 @@ export class ObjectHydrator extends Hydrator {
|
|
|
365
363
|
ret.push(...hydrateEmbedded(prop, [...path, `[idx_${idx}]`], `${dataKey}[idx_${idx}]`).map(l => ' ' + l));
|
|
366
364
|
ret.push(` });`);
|
|
367
365
|
ret.push(` } else if (data${dataKey} === null) {`);
|
|
368
|
-
|
|
369
|
-
ret.push(` entity${entityKey} = ${this.config.get('forceUndefined') ? 'undefined' : 'null'};`);
|
|
366
|
+
ret.push(` entity${entityKey} = ${nullVal};`);
|
|
370
367
|
ret.push(` }`);
|
|
371
368
|
return ret;
|
|
372
369
|
};
|
|
@@ -396,7 +393,7 @@ export class ObjectHydrator extends Hydrator {
|
|
|
396
393
|
// ReferenceKind.SCALAR
|
|
397
394
|
ret.push(...hydrateScalar(prop, path, dataKey));
|
|
398
395
|
}
|
|
399
|
-
if (
|
|
396
|
+
if (forceUndefined) {
|
|
400
397
|
ret.push(` if (data${dataKey} === null) entity${entityKey} = undefined;`);
|
|
401
398
|
}
|
|
402
399
|
return ret;
|
|
@@ -1062,6 +1062,7 @@ export class MetadataDiscovery {
|
|
|
1062
1062
|
});
|
|
1063
1063
|
ownProps.forEach(prop => (meta.properties[prop.name] = prop));
|
|
1064
1064
|
meta.filters = { ...base.filters, ...meta.filters };
|
|
1065
|
+
meta.forceUndefined ??= base.forceUndefined;
|
|
1065
1066
|
if (!meta.discriminatorValue) {
|
|
1066
1067
|
Object.values(base.properties)
|
|
1067
1068
|
.filter(prop => !old.includes(prop.name))
|
package/metadata/types.d.ts
CHANGED
|
@@ -85,6 +85,8 @@ export type EntityOptions<T, E = T extends EntityClass<infer P> ? P : T> = {
|
|
|
85
85
|
abstract?: boolean;
|
|
86
86
|
/** Disables change tracking - such entities are ignored during flush. */
|
|
87
87
|
readonly?: boolean;
|
|
88
|
+
/** Hydrate `null` values as `undefined` for this entity, overriding the global `forceUndefined` option. */
|
|
89
|
+
forceUndefined?: boolean;
|
|
88
90
|
/** Marks entity as {@doclink virtual-entities | virtual}. This is set automatically when you use `expression` option (unless `view` is set). */
|
|
89
91
|
virtual?: boolean;
|
|
90
92
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.3.0-dev.
|
|
3
|
+
"version": "7.3.0-dev.1",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
package/typings.d.ts
CHANGED
|
@@ -246,6 +246,8 @@ export type CleanTypeConfig<T> = Compute<Pick<T, Extract<keyof T, keyof TypeConf
|
|
|
246
246
|
/** Configuration options that can be set on an entity via the `[Config]` symbol. */
|
|
247
247
|
export interface TypeConfig {
|
|
248
248
|
forceObject?: boolean;
|
|
249
|
+
/** Type-level marker of the `forceUndefined` entity option: `defineEntity` infers nullable properties as `T | undefined` instead of `T | null | undefined`. */
|
|
250
|
+
forceUndefined?: boolean;
|
|
249
251
|
}
|
|
250
252
|
declare const __selectedType: unique symbol;
|
|
251
253
|
declare const __loadedType: unique symbol;
|
|
@@ -1223,6 +1225,8 @@ export interface EntityMetadata<Entity = any, Class extends EntityCtor<Entity> =
|
|
|
1223
1225
|
selfReferencing?: boolean;
|
|
1224
1226
|
hasUniqueProps?: boolean;
|
|
1225
1227
|
readonly?: boolean;
|
|
1228
|
+
/** Per-entity override of the global `forceUndefined` option. */
|
|
1229
|
+
forceUndefined?: boolean;
|
|
1226
1230
|
polymorphs?: EntityMetadata[];
|
|
1227
1231
|
root: EntityMetadata<Entity>;
|
|
1228
1232
|
definedProperties: Dictionary;
|
|
@@ -79,7 +79,7 @@ export class UnitOfWork {
|
|
|
79
79
|
* @internal
|
|
80
80
|
*/
|
|
81
81
|
normalizeEntityData(meta, data) {
|
|
82
|
-
const forceUndefined = this.#em.config.get('forceUndefined');
|
|
82
|
+
const forceUndefined = meta.forceUndefined ?? this.#em.config.get('forceUndefined');
|
|
83
83
|
for (const key of Utils.keys(data)) {
|
|
84
84
|
const prop = meta.properties[key];
|
|
85
85
|
if (!prop) {
|
package/utils/Utils.js
CHANGED
|
@@ -153,7 +153,7 @@ export function parseJsonSafe(value) {
|
|
|
153
153
|
/** Collection of general-purpose utility methods used throughout the ORM. */
|
|
154
154
|
export class Utils {
|
|
155
155
|
static PK_SEPARATOR = '~~~';
|
|
156
|
-
static #ORM_VERSION = '7.3.0-dev.
|
|
156
|
+
static #ORM_VERSION = '7.3.0-dev.1';
|
|
157
157
|
/** Default session variable name backing an RLS filter argument (`current_setting('mikro.<filter>.<arg>')`). */
|
|
158
158
|
static getRlsSettingName(filterName, argName) {
|
|
159
159
|
return `mikro.${filterName}.${argName}`;
|