@mikro-orm/core 7.0.0-dev.34 → 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/EntityComparator.js +1 -4
- 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;
|
|
@@ -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/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
|
+
}
|