@mikro-orm/core 7.0.0-dev.33 → 7.0.0-dev.35
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 +19 -1
- package/EntityManager.js +64 -40
- package/decorators/Entity.d.ts +1 -1
- package/drivers/DatabaseDriver.d.ts +4 -3
- package/drivers/IDatabaseDriver.d.ts +14 -1
- package/entity/EntityFactory.js +4 -0
- package/entity/defineEntity.d.ts +305 -291
- package/entity/defineEntity.js +105 -268
- package/package.json +2 -2
- package/platforms/Platform.d.ts +2 -2
- package/platforms/Platform.js +3 -7
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/Type.d.ts +2 -1
- package/types/Type.js +1 -1
- package/typings.d.ts +2 -2
- package/unit-of-work/UnitOfWork.js +7 -0
- package/utils/Configuration.d.ts +2 -0
- package/utils/Configuration.js +4 -0
- package/utils/EntityComparator.js +1 -4
- package/utils/Utils.d.ts +2 -0
- package/utils/Utils.js +7 -1
- package/utils/upsert-utils.d.ts +7 -2
- package/utils/upsert-utils.js +43 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.35",
|
|
5
5
|
"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.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dataloader": "2.2.3",
|
|
55
55
|
"dotenv": "17.2.3",
|
|
56
56
|
"esprima": "4.0.1",
|
|
57
|
-
"mikro-orm": "7.0.0-dev.
|
|
57
|
+
"mikro-orm": "7.0.0-dev.35",
|
|
58
58
|
"reflect-metadata": "0.2.2",
|
|
59
59
|
"tinyglobby": "0.2.13"
|
|
60
60
|
}
|
package/platforms/Platform.d.ts
CHANGED
|
@@ -158,7 +158,7 @@ export declare abstract class Platform {
|
|
|
158
158
|
getFullTextIndexExpression(indexName: string, schemaName: string | undefined, tableName: string, columns: SimpleColumnMeta[]): string;
|
|
159
159
|
convertsJsonAutomatically(): boolean;
|
|
160
160
|
convertJsonToDatabaseValue(value: unknown, context?: TransformContext): unknown;
|
|
161
|
-
convertJsonToJSValue(value: unknown,
|
|
161
|
+
convertJsonToJSValue(value: unknown, context?: TransformContext): unknown;
|
|
162
162
|
convertDateToJSValue(value: string | Date): string;
|
|
163
163
|
convertIntervalToJSValue(value: string): unknown;
|
|
164
164
|
convertIntervalToDatabaseValue(value: unknown): unknown;
|
|
@@ -195,7 +195,7 @@ export declare abstract class Platform {
|
|
|
195
195
|
getDefaultPrimaryName(tableName: string, columns: string[]): string;
|
|
196
196
|
supportsCustomPrimaryKeyNames(): boolean;
|
|
197
197
|
isPopulated<T>(key: string, populate: readonly PopulateOptions<T>[] | boolean): boolean;
|
|
198
|
-
shouldHaveColumn<T>(prop: EntityProperty<T>, populate: readonly PopulateOptions<T>[] | boolean, exclude?: string[], includeFormulas?: boolean): boolean;
|
|
198
|
+
shouldHaveColumn<T>(prop: EntityProperty<T>, populate: readonly PopulateOptions<T>[] | boolean, exclude?: string[], includeFormulas?: boolean, ignoreInlineEmbeddables?: boolean): boolean;
|
|
199
199
|
/**
|
|
200
200
|
* Currently not supported due to how knex does complex sqlite diffing (always based on current schema)
|
|
201
201
|
*/
|
package/platforms/Platform.js
CHANGED
|
@@ -288,11 +288,7 @@ export class Platform {
|
|
|
288
288
|
convertJsonToDatabaseValue(value, context) {
|
|
289
289
|
return JSON.stringify(value);
|
|
290
290
|
}
|
|
291
|
-
convertJsonToJSValue(value,
|
|
292
|
-
const isObjectEmbedded = prop.embedded && prop.object;
|
|
293
|
-
if ((this.convertsJsonAutomatically() || isObjectEmbedded) && ['json', 'jsonb', this.getJsonDeclarationSQL()].includes(prop.columnTypes[0])) {
|
|
294
|
-
return value;
|
|
295
|
-
}
|
|
291
|
+
convertJsonToJSValue(value, context) {
|
|
296
292
|
return parseJsonSafe(value);
|
|
297
293
|
}
|
|
298
294
|
convertDateToJSValue(value) {
|
|
@@ -455,7 +451,7 @@ export class Platform {
|
|
|
455
451
|
isPopulated(key, populate) {
|
|
456
452
|
return populate === true || (populate !== false && populate.some(p => p.field === key || p.all));
|
|
457
453
|
}
|
|
458
|
-
shouldHaveColumn(prop, populate, exclude, includeFormulas = true) {
|
|
454
|
+
shouldHaveColumn(prop, populate, exclude, includeFormulas = true, ignoreInlineEmbeddables = true) {
|
|
459
455
|
if (exclude?.includes(prop.name)) {
|
|
460
456
|
return false;
|
|
461
457
|
}
|
|
@@ -475,7 +471,7 @@ export class Platform {
|
|
|
475
471
|
return true;
|
|
476
472
|
}
|
|
477
473
|
if (prop.kind === ReferenceKind.EMBEDDED) {
|
|
478
|
-
return
|
|
474
|
+
return prop.object || ignoreInlineEmbeddables;
|
|
479
475
|
}
|
|
480
476
|
return prop.kind === ReferenceKind.ONE_TO_ONE && prop.owner;
|
|
481
477
|
}
|
package/types/JsonType.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare class JsonType extends Type<unknown, string | null> {
|
|
|
5
5
|
convertToDatabaseValue(value: unknown, platform: Platform, context?: TransformContext): string | null;
|
|
6
6
|
convertToJSValueSQL(key: string, platform: Platform): string;
|
|
7
7
|
convertToDatabaseValueSQL(key: string, platform: Platform): string;
|
|
8
|
-
convertToJSValue(value: string | unknown, platform: Platform): unknown;
|
|
8
|
+
convertToJSValue(value: string | unknown, platform: Platform, context?: TransformContext): unknown;
|
|
9
9
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
10
10
|
ensureComparable<T extends object>(meta: EntityMetadata<T>, prop: EntityProperty<T>): boolean;
|
|
11
11
|
compareAsType(): string;
|
package/types/JsonType.js
CHANGED
|
@@ -12,8 +12,13 @@ export class JsonType extends Type {
|
|
|
12
12
|
convertToDatabaseValueSQL(key, platform) {
|
|
13
13
|
return key + platform.castColumn(this.prop);
|
|
14
14
|
}
|
|
15
|
-
convertToJSValue(value, platform) {
|
|
16
|
-
|
|
15
|
+
convertToJSValue(value, platform, context) {
|
|
16
|
+
const isJsonColumn = ['json', 'jsonb', platform.getJsonDeclarationSQL()].includes(this.prop.columnTypes[0]);
|
|
17
|
+
const isObjectEmbedded = this.prop.embedded && this.prop.object;
|
|
18
|
+
if ((platform.convertsJsonAutomatically() || isObjectEmbedded) && isJsonColumn && !context?.force) {
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
return platform.convertJsonToJSValue(value, context);
|
|
17
22
|
}
|
|
18
23
|
getColumnType(prop, platform) {
|
|
19
24
|
return platform.getJsonDeclarationSQL();
|
package/types/Type.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Platform } from '../platforms/Platform.js';
|
|
|
3
3
|
import type { Constructor, EntityMetadata, EntityProperty } from '../typings.js';
|
|
4
4
|
export interface TransformContext {
|
|
5
5
|
fromQuery?: boolean;
|
|
6
|
+
force?: boolean;
|
|
6
7
|
key?: string;
|
|
7
8
|
mode?: 'hydration' | 'query' | 'query-data' | 'discovery' | 'serialization';
|
|
8
9
|
}
|
|
@@ -23,7 +24,7 @@ export declare abstract class Type<JSType = string, DBType = JSType> {
|
|
|
23
24
|
/**
|
|
24
25
|
* Converts a value from its database representation to its JS representation of this type.
|
|
25
26
|
*/
|
|
26
|
-
convertToJSValue(value: DBType, platform: Platform): JSType;
|
|
27
|
+
convertToJSValue(value: DBType, platform: Platform, context?: TransformContext): JSType;
|
|
27
28
|
/**
|
|
28
29
|
* Converts a value from its JS representation to its database representation of this type.
|
|
29
30
|
*/
|
package/types/Type.js
CHANGED
package/typings.d.ts
CHANGED
|
@@ -91,7 +91,7 @@ type PrimaryPropToType<T, Keys extends (keyof T)[]> = {
|
|
|
91
91
|
type ReadonlyPrimary<T> = T extends any[] ? Readonly<T> : T;
|
|
92
92
|
export type Primary<T> = IsAny<T> extends true ? any : T extends {
|
|
93
93
|
[PrimaryKeyProp]?: infer PK;
|
|
94
|
-
} ?
|
|
94
|
+
} ? PK extends undefined ? Omit<T, typeof PrimaryKeyProp> : PK extends keyof T ? ReadonlyPrimary<UnwrapPrimary<T[PK]>> : PK extends (keyof T)[] ? ReadonlyPrimary<PrimaryPropToType<T, PK>> : PK : T extends {
|
|
95
95
|
_id?: infer PK;
|
|
96
96
|
} ? ReadonlyPrimary<PK> | string : T extends {
|
|
97
97
|
id?: infer PK;
|
|
@@ -451,7 +451,7 @@ export interface EntityMetadata<T = any> {
|
|
|
451
451
|
schema?: string;
|
|
452
452
|
pivotTable?: boolean;
|
|
453
453
|
virtual?: boolean;
|
|
454
|
-
expression?: string | ((em: any, where: ObjectQuery<T>, options: FindOptions<T, any, any, any
|
|
454
|
+
expression?: string | ((em: any, where: ObjectQuery<T>, options: FindOptions<T, any, any, any>, stream?: boolean) => MaybePromise<RawQueryFragment | object | string>);
|
|
455
455
|
discriminatorColumn?: EntityKey<T> | AnyString;
|
|
456
456
|
discriminatorValue?: number | string;
|
|
457
457
|
discriminatorMap?: Dictionary<string>;
|
|
@@ -99,6 +99,10 @@ export class UnitOfWork {
|
|
|
99
99
|
}
|
|
100
100
|
data[prop.name] = Utils.getPrimaryKeyValues(data[prop.name], prop.targetMeta, true);
|
|
101
101
|
}
|
|
102
|
+
if (prop.hydrate === false && prop.customType?.ensureComparable(wrapped.__meta, prop)) {
|
|
103
|
+
const converted = prop.customType.convertToJSValue(data[key], this.platform, { key, mode: 'hydration', force: true });
|
|
104
|
+
data[key] = prop.customType.convertToDatabaseValue(converted, this.platform, { key, mode: 'hydration' });
|
|
105
|
+
}
|
|
102
106
|
if (forceUndefined) {
|
|
103
107
|
if (data[key] === null) {
|
|
104
108
|
data[key] = undefined;
|
|
@@ -194,6 +198,9 @@ export class UnitOfWork {
|
|
|
194
198
|
if (this.queuedActions.has(meta.className) || this.queuedActions.has(meta.root.className)) {
|
|
195
199
|
return true;
|
|
196
200
|
}
|
|
201
|
+
if (meta.discriminatorMap && Object.values(meta.discriminatorMap).some(v => this.queuedActions.has(v))) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
197
204
|
for (const entity of this.identityMap.getStore(meta).values()) {
|
|
198
205
|
if (helper(entity).__initialized && helper(entity).isTouched()) {
|
|
199
206
|
return true;
|
package/utils/Configuration.d.ts
CHANGED
|
@@ -146,6 +146,7 @@ export declare class Configuration<D extends IDatabaseDriver = IDatabaseDriver,
|
|
|
146
146
|
fileName: (className: string) => string;
|
|
147
147
|
};
|
|
148
148
|
preferReadReplicas: true;
|
|
149
|
+
dynamicImportProvider: (id: string) => Promise<any>;
|
|
149
150
|
};
|
|
150
151
|
private readonly options;
|
|
151
152
|
private readonly logger;
|
|
@@ -412,6 +413,7 @@ export interface MikroORMOptions<D extends IDatabaseDriver = IDatabaseDriver, EM
|
|
|
412
413
|
};
|
|
413
414
|
seeder: SeederOptions;
|
|
414
415
|
preferReadReplicas: boolean;
|
|
416
|
+
dynamicImportProvider: (id: string) => Promise<unknown>;
|
|
415
417
|
hashAlgorithm: 'md5' | 'sha256';
|
|
416
418
|
}
|
|
417
419
|
export type Options<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager = D[typeof EntityManagerType] & EntityManager> = Pick<MikroORMOptions<D, EM>, Exclude<keyof MikroORMOptions<D, EM>, keyof typeof Configuration.DEFAULTS>> & Partial<MikroORMOptions<D, EM>>;
|
package/utils/Configuration.js
CHANGED
|
@@ -134,6 +134,7 @@ export class Configuration {
|
|
|
134
134
|
fileName: (className) => className,
|
|
135
135
|
},
|
|
136
136
|
preferReadReplicas: true,
|
|
137
|
+
dynamicImportProvider: /* v8 ignore next */ (id) => import(id),
|
|
137
138
|
};
|
|
138
139
|
options;
|
|
139
140
|
logger;
|
|
@@ -142,6 +143,9 @@ export class Configuration {
|
|
|
142
143
|
cache = new Map();
|
|
143
144
|
extensions = new Map();
|
|
144
145
|
constructor(options, validate = true) {
|
|
146
|
+
if (options.dynamicImportProvider) {
|
|
147
|
+
Utils.setDynamicImportProvider(options.dynamicImportProvider);
|
|
148
|
+
}
|
|
145
149
|
this.options = Utils.mergeConfig({}, Configuration.DEFAULTS, options);
|
|
146
150
|
this.options.baseDir = Utils.absolutePath(this.options.baseDir);
|
|
147
151
|
this.options.preferTs ??= options.preferTs;
|
|
@@ -542,10 +542,7 @@ export class EntityComparator {
|
|
|
542
542
|
context.set('compareObjects', compareObjects);
|
|
543
543
|
context.set('equals', equals);
|
|
544
544
|
for (const prop of meta.comparableProps) {
|
|
545
|
-
|
|
546
|
-
if (prop.hydrate !== false) {
|
|
547
|
-
lines.push(this.getPropertyComparator(prop, context));
|
|
548
|
-
}
|
|
545
|
+
lines.push(this.getPropertyComparator(prop, context));
|
|
549
546
|
}
|
|
550
547
|
// also compare 1:1 inverse sides, important for `factory.mergeData`
|
|
551
548
|
lines.push(`if (options?.includeInverseSides) {`);
|
package/utils/Utils.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare function equals(a: any, b: any): boolean;
|
|
|
15
15
|
export declare function parseJsonSafe<T = unknown>(value: unknown): T;
|
|
16
16
|
export declare class Utils {
|
|
17
17
|
static readonly PK_SEPARATOR = "~~~";
|
|
18
|
+
static dynamicImportProvider: (id: string) => Promise<any>;
|
|
18
19
|
/**
|
|
19
20
|
* Checks if the argument is not undefined
|
|
20
21
|
*/
|
|
@@ -236,6 +237,7 @@ export declare class Utils {
|
|
|
236
237
|
*/
|
|
237
238
|
static resolveModulePath(id: string, from?: string): string;
|
|
238
239
|
static dynamicImport<T = any>(id: string): Promise<T>;
|
|
240
|
+
static setDynamicImportProvider(provider: (id: string) => Promise<unknown>): void;
|
|
239
241
|
static ensureDir(path: string): void;
|
|
240
242
|
static pathExistsSync(path: string): boolean;
|
|
241
243
|
static readJSONSync(path: string): Dictionary;
|
package/utils/Utils.js
CHANGED
|
@@ -131,6 +131,8 @@ export function parseJsonSafe(value) {
|
|
|
131
131
|
}
|
|
132
132
|
export class Utils {
|
|
133
133
|
static PK_SEPARATOR = '~~~';
|
|
134
|
+
/* v8 ignore next */
|
|
135
|
+
static dynamicImportProvider = (id) => import(id);
|
|
134
136
|
/**
|
|
135
137
|
* Checks if the argument is not undefined
|
|
136
138
|
*/
|
|
@@ -907,7 +909,11 @@ export class Utils {
|
|
|
907
909
|
static async dynamicImport(id) {
|
|
908
910
|
/* v8 ignore next */
|
|
909
911
|
const specifier = id.startsWith('file://') ? id : pathToFileURL(id).href;
|
|
910
|
-
return
|
|
912
|
+
return this.dynamicImportProvider(specifier);
|
|
913
|
+
}
|
|
914
|
+
/* v8 ignore next 3 */
|
|
915
|
+
static setDynamicImportProvider(provider) {
|
|
916
|
+
this.dynamicImportProvider = provider;
|
|
911
917
|
}
|
|
912
918
|
static ensureDir(path) {
|
|
913
919
|
if (!existsSync(path)) {
|
package/utils/upsert-utils.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import type { EntityData, EntityMetadata } from '../typings.js';
|
|
1
|
+
import type { EntityData, EntityMetadata, FilterQuery } from '../typings.js';
|
|
2
2
|
import type { UpsertOptions } from '../drivers/IDatabaseDriver.js';
|
|
3
|
-
import type
|
|
3
|
+
import { type RawQueryFragment } from '../utils/RawQueryFragment.js';
|
|
4
4
|
/** @internal */
|
|
5
5
|
export declare function getOnConflictFields<T>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | RawQueryFragment, options: UpsertOptions<T>): (keyof T)[];
|
|
6
6
|
/** @internal */
|
|
7
7
|
export declare function getOnConflictReturningFields<T, P extends string>(meta: EntityMetadata<T> | undefined, data: EntityData<T>, uniqueFields: (keyof T)[] | RawQueryFragment, options: UpsertOptions<T, P>): (keyof T)[] | '*';
|
|
8
|
+
/** @internal */
|
|
9
|
+
export declare function getWhereCondition<T extends object>(meta: EntityMetadata<T>, onConflictFields: (keyof T)[] | RawQueryFragment | undefined, data: EntityData<T>, where: FilterQuery<T>): {
|
|
10
|
+
where: FilterQuery<T>;
|
|
11
|
+
propIndex: number | false;
|
|
12
|
+
};
|
package/utils/upsert-utils.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isRaw } from '../utils/RawQueryFragment.js';
|
|
2
|
+
import { Utils } from './Utils.js';
|
|
1
3
|
function expandEmbeddedProperties(prop, key) {
|
|
2
4
|
if (prop.object) {
|
|
3
5
|
return [prop.name];
|
|
@@ -96,3 +98,44 @@ export function getOnConflictReturningFields(meta, data, uniqueFields, options)
|
|
|
96
98
|
}
|
|
97
99
|
return keys.filter(key => !(key in data));
|
|
98
100
|
}
|
|
101
|
+
function getPropertyValue(obj, key) {
|
|
102
|
+
if (key.indexOf('.') === -1) {
|
|
103
|
+
return obj[key];
|
|
104
|
+
}
|
|
105
|
+
const parts = key.split('.');
|
|
106
|
+
let curr = obj;
|
|
107
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
108
|
+
curr[parts[i]] ??= {};
|
|
109
|
+
curr = curr[parts[i]];
|
|
110
|
+
}
|
|
111
|
+
return curr[parts[parts.length - 1]];
|
|
112
|
+
}
|
|
113
|
+
/** @internal */
|
|
114
|
+
export function getWhereCondition(meta, onConflictFields, data, where) {
|
|
115
|
+
const unique = onConflictFields ?? meta.props.filter(p => p.unique).map(p => p.name);
|
|
116
|
+
const propIndex = !isRaw(unique) && unique.findIndex(p => data[p] ?? data[p.substring(0, p.indexOf('.'))] != null);
|
|
117
|
+
if (onConflictFields || where == null) {
|
|
118
|
+
if (propIndex !== false && propIndex >= 0) {
|
|
119
|
+
let key = unique[propIndex];
|
|
120
|
+
if (key.includes('.')) {
|
|
121
|
+
const prop = meta.properties[key.substring(0, key.indexOf('.'))];
|
|
122
|
+
if (prop) {
|
|
123
|
+
key = `${prop.fieldNames[0]}${key.substring(key.indexOf('.'))}`;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
where = { [key]: getPropertyValue(data, unique[propIndex]) };
|
|
127
|
+
}
|
|
128
|
+
else if (meta.uniques.length > 0) {
|
|
129
|
+
for (const u of meta.uniques) {
|
|
130
|
+
if (Utils.asArray(u.properties).every(p => data[p] != null)) {
|
|
131
|
+
where = Utils.asArray(u.properties).reduce((o, key) => {
|
|
132
|
+
o[key] = data[key];
|
|
133
|
+
return o;
|
|
134
|
+
}, {});
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { where, propIndex };
|
|
141
|
+
}
|