@mikro-orm/core 7.0.0-rc.3 → 7.0.1-dev.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 +2 -15
- package/EntityManager.js +155 -152
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +20 -20
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -22
- package/cache/GeneratedCacheAdapter.d.ts +1 -1
- package/cache/GeneratedCacheAdapter.js +6 -6
- package/cache/MemoryCacheAdapter.d.ts +1 -2
- package/cache/MemoryCacheAdapter.js +8 -8
- package/cache/index.d.ts +1 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +1 -0
- package/connections/Connection.js +27 -11
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +2 -4
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +95 -105
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +48 -48
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +36 -39
- package/entity/Reference.d.ts +1 -2
- package/entity/Reference.js +11 -11
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/defineEntity.d.ts +18 -73
- package/enums.d.ts +2 -1
- package/enums.js +1 -0
- package/errors.d.ts +11 -11
- package/errors.js +3 -13
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +25 -22
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +8 -6
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +16 -16
- package/logging/DefaultLogger.js +3 -2
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +1 -1
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +1 -1
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +162 -149
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +36 -36
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/naming-strategy/AbstractNamingStrategy.js +1 -1
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/package.json +1 -1
- package/platforms/Platform.d.ts +23 -1
- package/platforms/Platform.js +57 -4
- package/serialization/EntitySerializer.js +1 -1
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +20 -15
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +12 -1
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +21 -21
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +52 -52
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +5 -19
- package/unit-of-work/UnitOfWork.js +182 -174
- package/utils/AbstractMigrator.d.ts +1 -1
- package/utils/AbstractMigrator.js +7 -7
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +94 -78
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +4 -4
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +49 -49
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +70 -24
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/TransactionManager.js +1 -2
- package/utils/Utils.d.ts +1 -1
- package/utils/Utils.js +5 -4
- package/utils/clone.js +5 -0
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +1 -1
- package/utils/upsert-utils.js +1 -1
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { type Dictionary, EntityMetadata, type EntityName } from '../typings.js';
|
|
2
2
|
import type { EntityManager } from '../EntityManager.js';
|
|
3
3
|
export declare class MetadataStorage {
|
|
4
|
+
#private;
|
|
4
5
|
static readonly PATH_SYMBOL: unique symbol;
|
|
5
|
-
private static readonly metadata;
|
|
6
|
-
private readonly metadata;
|
|
7
|
-
private readonly idMap;
|
|
8
|
-
private readonly classNameMap;
|
|
9
|
-
private readonly uniqueNameMap;
|
|
10
6
|
constructor(metadata?: Dictionary<EntityMetadata>);
|
|
11
7
|
static getMetadata(): Dictionary<EntityMetadata>;
|
|
12
8
|
static getMetadata<T = any>(entity: string, path: string): EntityMetadata<T>;
|
|
@@ -10,39 +10,39 @@ function getGlobalStorage(namespace) {
|
|
|
10
10
|
}
|
|
11
11
|
export class MetadataStorage {
|
|
12
12
|
static PATH_SYMBOL = Symbol.for('@mikro-orm/core/MetadataStorage.PATH_SYMBOL');
|
|
13
|
-
static metadata = getGlobalStorage('metadata');
|
|
14
|
-
|
|
15
|
-
idMap;
|
|
16
|
-
classNameMap;
|
|
17
|
-
uniqueNameMap;
|
|
13
|
+
static #metadata = getGlobalStorage('metadata');
|
|
14
|
+
#metadataMap = new Map();
|
|
15
|
+
#idMap;
|
|
16
|
+
#classNameMap;
|
|
17
|
+
#uniqueNameMap;
|
|
18
18
|
constructor(metadata = {}) {
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
for (const meta of Object.values(this
|
|
23
|
-
this
|
|
24
|
-
this
|
|
25
|
-
this.
|
|
19
|
+
this.#idMap = {};
|
|
20
|
+
this.#uniqueNameMap = {};
|
|
21
|
+
this.#classNameMap = Utils.copy(metadata, false);
|
|
22
|
+
for (const meta of Object.values(this.#classNameMap)) {
|
|
23
|
+
this.#idMap[meta._id] = meta;
|
|
24
|
+
this.#uniqueNameMap[meta.uniqueName] = meta;
|
|
25
|
+
this.#metadataMap.set(meta.class, meta);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
static getMetadata(entity, path) {
|
|
29
29
|
const key = entity && path ? entity + '-' + Utils.hash(path) : null;
|
|
30
|
-
if (key && !MetadataStorage
|
|
31
|
-
MetadataStorage
|
|
30
|
+
if (key && !MetadataStorage.#metadata[key]) {
|
|
31
|
+
MetadataStorage.#metadata[key] = new EntityMetadata({ className: entity, path });
|
|
32
32
|
}
|
|
33
33
|
if (key) {
|
|
34
|
-
return MetadataStorage
|
|
34
|
+
return MetadataStorage.#metadata[key];
|
|
35
35
|
}
|
|
36
|
-
return MetadataStorage
|
|
36
|
+
return MetadataStorage.#metadata;
|
|
37
37
|
}
|
|
38
38
|
static isKnownEntity(name) {
|
|
39
|
-
return !!Object.values(this
|
|
39
|
+
return !!Object.values(this.#metadata).find(meta => meta.className === name);
|
|
40
40
|
}
|
|
41
41
|
static clear() {
|
|
42
|
-
Object.keys(this
|
|
42
|
+
Object.keys(this.#metadata).forEach(k => delete this.#metadata[k]);
|
|
43
43
|
}
|
|
44
44
|
getAll() {
|
|
45
|
-
return this
|
|
45
|
+
return this.#metadataMap;
|
|
46
46
|
}
|
|
47
47
|
get(entityName, init = false) {
|
|
48
48
|
const exists = this.find(entityName);
|
|
@@ -61,50 +61,50 @@ export class MetadataStorage {
|
|
|
61
61
|
if (!entityName) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
const meta = this.
|
|
64
|
+
const meta = this.#metadataMap.get(entityName);
|
|
65
65
|
if (meta) {
|
|
66
66
|
return meta;
|
|
67
67
|
}
|
|
68
68
|
if (entityName instanceof EntitySchema) {
|
|
69
|
-
return this.
|
|
69
|
+
return this.#metadataMap.get(entityName.meta.class) ?? entityName.meta;
|
|
70
70
|
}
|
|
71
|
-
return this
|
|
71
|
+
return this.#classNameMap[Utils.className(entityName)];
|
|
72
72
|
}
|
|
73
73
|
has(entityName) {
|
|
74
|
-
return this.
|
|
74
|
+
return this.#metadataMap.has(entityName);
|
|
75
75
|
}
|
|
76
76
|
set(entityName, meta) {
|
|
77
|
-
this.
|
|
78
|
-
this
|
|
79
|
-
this
|
|
80
|
-
this
|
|
77
|
+
this.#metadataMap.set(entityName, meta);
|
|
78
|
+
this.#idMap[meta._id] = meta;
|
|
79
|
+
this.#uniqueNameMap[meta.uniqueName] = meta;
|
|
80
|
+
this.#classNameMap[Utils.className(entityName)] = meta;
|
|
81
81
|
return meta;
|
|
82
82
|
}
|
|
83
83
|
reset(entityName) {
|
|
84
84
|
const meta = this.find(entityName);
|
|
85
85
|
if (meta) {
|
|
86
|
-
this.
|
|
87
|
-
delete this
|
|
88
|
-
delete this
|
|
89
|
-
delete this
|
|
86
|
+
this.#metadataMap.delete(meta.class);
|
|
87
|
+
delete this.#idMap[meta._id];
|
|
88
|
+
delete this.#uniqueNameMap[meta.uniqueName];
|
|
89
|
+
delete this.#classNameMap[meta.className];
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
decorate(em) {
|
|
93
|
-
[...this.
|
|
93
|
+
[...this.#metadataMap.values()].filter(meta => meta.prototype).forEach(meta => EntityHelper.decorate(meta, em));
|
|
94
94
|
}
|
|
95
95
|
*[Symbol.iterator]() {
|
|
96
|
-
for (const meta of this.
|
|
96
|
+
for (const meta of this.#metadataMap.values()) {
|
|
97
97
|
yield meta;
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
getById(id) {
|
|
101
|
-
return this
|
|
101
|
+
return this.#idMap[id];
|
|
102
102
|
}
|
|
103
103
|
getByClassName(className, validate = true) {
|
|
104
|
-
return this.validate(this
|
|
104
|
+
return this.validate(this.#classNameMap[className], className, validate);
|
|
105
105
|
}
|
|
106
106
|
getByUniqueName(uniqueName, validate = true) {
|
|
107
|
-
return this.validate(this
|
|
107
|
+
return this.validate(this.#uniqueNameMap[uniqueName], uniqueName, validate);
|
|
108
108
|
}
|
|
109
109
|
validate(meta, id, validate) {
|
|
110
110
|
if (!meta && validate) {
|
|
@@ -31,7 +31,7 @@ export async function discoverEntities(paths, options) {
|
|
|
31
31
|
const found = new Map();
|
|
32
32
|
for (const filepath of files) {
|
|
33
33
|
const filename = basename(filepath);
|
|
34
|
-
if (
|
|
34
|
+
if (!/\.[cm]?[jt]s$/.exec(filename) || /\.d\.[cm]?ts/.exec(filename)) {
|
|
35
35
|
continue;
|
|
36
36
|
}
|
|
37
37
|
await getEntityClassOrSchema(filepath, found, baseDir);
|
package/metadata/index.d.ts
CHANGED
package/metadata/index.js
CHANGED
|
@@ -34,7 +34,7 @@ export class AbstractNamingStrategy {
|
|
|
34
34
|
* @inheritDoc
|
|
35
35
|
*/
|
|
36
36
|
getEntityName(tableName, schemaName) {
|
|
37
|
-
const name =
|
|
37
|
+
const name = /^[^$_\p{ID_Start}]/u.exec(tableName) ? `E_${tableName}` : tableName;
|
|
38
38
|
return this.getClassName(name.replaceAll(/[^\u200C\u200D\p{ID_Continue}]+/gu, r => r
|
|
39
39
|
.split('')
|
|
40
40
|
.map(c => `$${c.codePointAt(0)}`)
|
|
@@ -11,7 +11,7 @@ export class EntityCaseNamingStrategy extends AbstractNamingStrategy {
|
|
|
11
11
|
}
|
|
12
12
|
joinKeyColumnName(entityName, referencedColumnName, composite, tableName) {
|
|
13
13
|
entityName = this.classToTableName(entityName, tableName);
|
|
14
|
-
const name = entityName.
|
|
14
|
+
const name = entityName.substring(0, 1).toLowerCase() + entityName.substring(1);
|
|
15
15
|
if (composite && referencedColumnName) {
|
|
16
16
|
return name + '_' + referencedColumnName;
|
|
17
17
|
}
|
package/naming-strategy/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/core",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.1-dev.0",
|
|
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/platforms/Platform.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EntityRepository } from '../entity/EntityRepository.js';
|
|
2
2
|
import { type NamingStrategy } from '../naming-strategy/NamingStrategy.js';
|
|
3
|
-
import type { Constructor, EntityMetadata, EntityProperty, IPrimaryKey, ISchemaGenerator, PopulateOptions, Primary, SimpleColumnMeta } from '../typings.js';
|
|
3
|
+
import type { Constructor, EntityMetadata, EntityProperty, IPrimaryKey, ISchemaGenerator, PopulateOptions, Primary, SimpleColumnMeta, FilterQuery, EntityValue, EntityKey } from '../typings.js';
|
|
4
4
|
import { ExceptionConverter } from './ExceptionConverter.js';
|
|
5
5
|
import type { EntityManager } from '../EntityManager.js';
|
|
6
6
|
import type { Configuration } from '../utils/Configuration.js';
|
|
@@ -61,6 +61,13 @@ export declare abstract class Platform {
|
|
|
61
61
|
getDateTypeDeclarationSQL(length?: number): string;
|
|
62
62
|
getTimeTypeDeclarationSQL(length?: number): string;
|
|
63
63
|
getRegExpOperator(val?: unknown, flags?: string): string;
|
|
64
|
+
mapRegExpCondition(mappedKey: string, value: {
|
|
65
|
+
$re: string;
|
|
66
|
+
$flags?: string;
|
|
67
|
+
}): {
|
|
68
|
+
sql: string;
|
|
69
|
+
params: unknown[];
|
|
70
|
+
};
|
|
64
71
|
getRegExpValue(val: RegExp): {
|
|
65
72
|
$re: string;
|
|
66
73
|
$flags?: string;
|
|
@@ -139,6 +146,11 @@ export declare abstract class Platform {
|
|
|
139
146
|
getMappedType(type: string): Type<unknown>;
|
|
140
147
|
getDefaultMappedType(type: string): Type<unknown>;
|
|
141
148
|
supportsMultipleCascadePaths(): boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Returns true if the platform supports ON UPDATE foreign key rules.
|
|
151
|
+
* Oracle doesn't support ON UPDATE rules.
|
|
152
|
+
*/
|
|
153
|
+
supportsOnUpdate(): boolean;
|
|
142
154
|
supportsMultipleStatements(): boolean;
|
|
143
155
|
supportsUnionWhere(): boolean;
|
|
144
156
|
getArrayDeclarationSQL(): string;
|
|
@@ -148,6 +160,8 @@ export declare abstract class Platform {
|
|
|
148
160
|
getJsonDeclarationSQL(): string;
|
|
149
161
|
getSearchJsonPropertySQL(path: string, type: string, aliased: boolean): string | Raw;
|
|
150
162
|
getSearchJsonPropertyKey(path: string[], type: string, aliased: boolean, value?: unknown): string | Raw;
|
|
163
|
+
processJsonCondition<T extends object>(o: FilterQuery<T>, value: EntityValue<T>, path: EntityKey<T>[], alias: boolean): FilterQuery<T>;
|
|
164
|
+
protected getJsonValueType(value: unknown): string;
|
|
151
165
|
getJsonIndexDefinition(index: {
|
|
152
166
|
columnNames: string[];
|
|
153
167
|
}): string[];
|
|
@@ -160,6 +174,14 @@ export declare abstract class Platform {
|
|
|
160
174
|
convertDateToJSValue(value: string | Date): string;
|
|
161
175
|
convertIntervalToJSValue(value: string): unknown;
|
|
162
176
|
convertIntervalToDatabaseValue(value: unknown): unknown;
|
|
177
|
+
usesAsKeyword(): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Determines how UUID values are compared in the change set tracking.
|
|
180
|
+
* Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
|
|
181
|
+
*/
|
|
182
|
+
compareUuids(): string;
|
|
183
|
+
convertUuidToJSValue(value: unknown): unknown;
|
|
184
|
+
convertUuidToDatabaseValue(value: unknown): unknown;
|
|
163
185
|
parseDate(value: string | number): Date;
|
|
164
186
|
getRepositoryClass<T extends object>(): Constructor<EntityRepository<T>>;
|
|
165
187
|
getDefaultCharset(): string;
|
package/platforms/Platform.js
CHANGED
|
@@ -3,7 +3,7 @@ import { EntityRepository } from '../entity/EntityRepository.js';
|
|
|
3
3
|
import { UnderscoreNamingStrategy } from '../naming-strategy/UnderscoreNamingStrategy.js';
|
|
4
4
|
import { ExceptionConverter } from './ExceptionConverter.js';
|
|
5
5
|
import { ArrayType, BigIntType, BlobType, BooleanType, CharacterType, DateTimeType, DateType, DecimalType, DoubleType, EnumType, FloatType, IntegerType, IntervalType, JsonType, MediumIntType, SmallIntType, StringType, TextType, TimeType, TinyIntType, Type, Uint8ArrayType, UnknownType, UuidType, } from '../types/index.js';
|
|
6
|
-
import { parseJsonSafe } from '../utils/Utils.js';
|
|
6
|
+
import { parseJsonSafe, Utils } from '../utils/Utils.js';
|
|
7
7
|
import { ReferenceKind } from '../enums.js';
|
|
8
8
|
import { Raw } from '../utils/RawQueryFragment.js';
|
|
9
9
|
export const JsonProperty = Symbol('JsonProperty');
|
|
@@ -104,6 +104,11 @@ export class Platform {
|
|
|
104
104
|
getRegExpOperator(val, flags) {
|
|
105
105
|
return 'regexp';
|
|
106
106
|
}
|
|
107
|
+
mapRegExpCondition(mappedKey, value) {
|
|
108
|
+
const operator = this.getRegExpOperator(value.$re, value.$flags);
|
|
109
|
+
const quotedKey = this.quoteIdentifier(mappedKey);
|
|
110
|
+
return { sql: `${quotedKey} ${operator} ?`, params: [value.$re] };
|
|
111
|
+
}
|
|
107
112
|
getRegExpValue(val) {
|
|
108
113
|
if (val.flags.includes('i')) {
|
|
109
114
|
return { $re: `(?i)${val.source}` };
|
|
@@ -156,7 +161,7 @@ export class Platform {
|
|
|
156
161
|
return 'interval' + (column.length ? `(${column.length})` : '');
|
|
157
162
|
}
|
|
158
163
|
getTextTypeDeclarationSQL(_column) {
|
|
159
|
-
return
|
|
164
|
+
return 'text';
|
|
160
165
|
}
|
|
161
166
|
getEnumTypeDeclarationSQL(column) {
|
|
162
167
|
if (column.items?.every(item => typeof item === 'string')) {
|
|
@@ -180,7 +185,7 @@ export class Platform {
|
|
|
180
185
|
return this.getVarcharTypeDeclarationSQL(column);
|
|
181
186
|
}
|
|
182
187
|
extractSimpleType(type) {
|
|
183
|
-
return
|
|
188
|
+
return /[^(), ]+/.exec(type.toLowerCase())[0];
|
|
184
189
|
}
|
|
185
190
|
/**
|
|
186
191
|
* This should be used only to compare types, it can strip some information like the length.
|
|
@@ -255,6 +260,13 @@ export class Platform {
|
|
|
255
260
|
supportsMultipleCascadePaths() {
|
|
256
261
|
return true;
|
|
257
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Returns true if the platform supports ON UPDATE foreign key rules.
|
|
265
|
+
* Oracle doesn't support ON UPDATE rules.
|
|
266
|
+
*/
|
|
267
|
+
supportsOnUpdate() {
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
258
270
|
supportsMultipleStatements() {
|
|
259
271
|
return this.config.get('multipleStatements');
|
|
260
272
|
}
|
|
@@ -285,6 +297,31 @@ export class Platform {
|
|
|
285
297
|
getSearchJsonPropertyKey(path, type, aliased, value) {
|
|
286
298
|
return path.join('.');
|
|
287
299
|
}
|
|
300
|
+
processJsonCondition(o, value, path, alias) {
|
|
301
|
+
if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
|
|
302
|
+
Utils.keys(value).forEach(k => {
|
|
303
|
+
this.processJsonCondition(o, value[k], [...path, k], alias);
|
|
304
|
+
});
|
|
305
|
+
return o;
|
|
306
|
+
}
|
|
307
|
+
if (path.length === 1) {
|
|
308
|
+
o[path[0]] = value;
|
|
309
|
+
return o;
|
|
310
|
+
}
|
|
311
|
+
const type = this.getJsonValueType(value);
|
|
312
|
+
const k = this.getSearchJsonPropertyKey(path, type, alias, value);
|
|
313
|
+
o[k] = value;
|
|
314
|
+
return o;
|
|
315
|
+
}
|
|
316
|
+
getJsonValueType(value) {
|
|
317
|
+
if (Array.isArray(value)) {
|
|
318
|
+
return typeof value[0];
|
|
319
|
+
}
|
|
320
|
+
if (Utils.isPlainObject(value) && Object.keys(value).every(k => Utils.isOperator(k))) {
|
|
321
|
+
return this.getJsonValueType(Object.values(value)[0]);
|
|
322
|
+
}
|
|
323
|
+
return typeof value;
|
|
324
|
+
}
|
|
288
325
|
/* v8 ignore next */
|
|
289
326
|
getJsonIndexDefinition(index) {
|
|
290
327
|
return index.columnNames;
|
|
@@ -316,6 +353,22 @@ export class Platform {
|
|
|
316
353
|
convertIntervalToDatabaseValue(value) {
|
|
317
354
|
return value;
|
|
318
355
|
}
|
|
356
|
+
usesAsKeyword() {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Determines how UUID values are compared in the change set tracking.
|
|
361
|
+
* Return `'string'` for inline string comparison (fast), or `'any'` for deep comparison via type methods.
|
|
362
|
+
*/
|
|
363
|
+
compareUuids() {
|
|
364
|
+
return 'string';
|
|
365
|
+
}
|
|
366
|
+
convertUuidToJSValue(value) {
|
|
367
|
+
return value;
|
|
368
|
+
}
|
|
369
|
+
convertUuidToDatabaseValue(value) {
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
319
372
|
parseDate(value) {
|
|
320
373
|
const date = new Date(value);
|
|
321
374
|
/* v8 ignore next */
|
|
@@ -380,7 +433,7 @@ export class Platform {
|
|
|
380
433
|
let j = 0;
|
|
381
434
|
let pos = 0;
|
|
382
435
|
let ret = '';
|
|
383
|
-
if (sql
|
|
436
|
+
if (sql.startsWith('?')) {
|
|
384
437
|
if (sql[1] === '?') {
|
|
385
438
|
ret += this.quoteIdentifier(params[j++]);
|
|
386
439
|
pos = 2;
|
|
@@ -36,7 +36,7 @@ export class EntitySerializer {
|
|
|
36
36
|
const meta = wrapped.__meta;
|
|
37
37
|
let contextCreated = false;
|
|
38
38
|
if (!wrapped.__serializationContext.root) {
|
|
39
|
-
const root = new SerializationContext(
|
|
39
|
+
const root = new SerializationContext();
|
|
40
40
|
SerializationContext.propagate(root, entity, (meta, prop) => meta.properties[prop]?.kind !== ReferenceKind.SCALAR);
|
|
41
41
|
options.populate = (options.populate ? Utils.asArray(options.populate) : options.populate);
|
|
42
42
|
contextCreated = true;
|
|
@@ -20,7 +20,7 @@ export class EntityTransformer {
|
|
|
20
20
|
return entity;
|
|
21
21
|
}
|
|
22
22
|
if (!wrapped.__serializationContext.root) {
|
|
23
|
-
const root = new SerializationContext(wrapped.
|
|
23
|
+
const root = new SerializationContext(wrapped.__serializationContext.populate, wrapped.__serializationContext.fields, wrapped.__serializationContext.exclude);
|
|
24
24
|
SerializationContext.propagate(root, entity, isVisible);
|
|
25
25
|
contextCreated = true;
|
|
26
26
|
}
|
|
@@ -64,6 +64,9 @@ export class EntityTransformer {
|
|
|
64
64
|
if (!partiallyLoaded && !populated && !isPrimary) {
|
|
65
65
|
continue;
|
|
66
66
|
}
|
|
67
|
+
if (root.isExcluded(meta.class, prop) && !populated) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
67
70
|
}
|
|
68
71
|
const cycle = root.visit(meta.class, prop);
|
|
69
72
|
if (cycle && visited) {
|
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { AnyEntity, EntityMetadata, EntityName, PopulateOptions } from '../typings.js';
|
|
2
|
-
import type { Configuration } from '../utils/Configuration.js';
|
|
3
2
|
/**
|
|
4
3
|
* Helper that allows to keep track of where we are currently at when serializing complex entity graph with cycles.
|
|
5
4
|
* Before we process a property, we call `visit` that checks if it is not a cycle path (but allows to pass cycles that
|
|
6
5
|
* are defined in populate hint). If not, we proceed and call `leave` afterwards.
|
|
7
6
|
*/
|
|
8
7
|
export declare class SerializationContext<T extends object> {
|
|
9
|
-
private
|
|
10
|
-
private readonly populate;
|
|
11
|
-
private readonly fields?;
|
|
12
|
-
private readonly exclude?;
|
|
8
|
+
#private;
|
|
13
9
|
readonly path: [EntityName, string][];
|
|
14
|
-
readonly visited: Set<
|
|
15
|
-
|
|
16
|
-
constructor(config: Configuration, populate?: PopulateOptions<T>[], fields?: Set<string> | undefined, exclude?: string[] | undefined);
|
|
10
|
+
readonly visited: Set<AnyEntity>;
|
|
11
|
+
constructor(populate?: PopulateOptions<T>[], fields?: Set<string>, exclude?: readonly string[]);
|
|
17
12
|
/**
|
|
18
13
|
* Returns true when there is a cycle detected.
|
|
19
14
|
*/
|
|
@@ -25,6 +20,7 @@ export declare class SerializationContext<T extends object> {
|
|
|
25
20
|
*/
|
|
26
21
|
static propagate(root: SerializationContext<any>, entity: AnyEntity, isVisible: (meta: EntityMetadata, prop: string) => boolean): void;
|
|
27
22
|
isMarkedAsPopulated(entityName: EntityName, prop: string): boolean;
|
|
23
|
+
isExcluded(entityName: EntityName, prop: string): boolean;
|
|
28
24
|
isPartiallyLoaded(entityName: EntityName, prop: string): boolean;
|
|
29
25
|
private register;
|
|
30
26
|
}
|
|
@@ -6,18 +6,16 @@ import { helper } from '../entity/wrap.js';
|
|
|
6
6
|
* are defined in populate hint). If not, we proceed and call `leave` afterwards.
|
|
7
7
|
*/
|
|
8
8
|
export class SerializationContext {
|
|
9
|
-
config;
|
|
10
|
-
populate;
|
|
11
|
-
fields;
|
|
12
|
-
exclude;
|
|
13
9
|
path = [];
|
|
14
10
|
visited = new Set();
|
|
15
|
-
entities = new Set();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this
|
|
11
|
+
#entities = new Set();
|
|
12
|
+
#populate;
|
|
13
|
+
#fields;
|
|
14
|
+
#exclude;
|
|
15
|
+
constructor(populate = [], fields, exclude) {
|
|
16
|
+
this.#populate = populate;
|
|
17
|
+
this.#fields = fields;
|
|
18
|
+
this.#exclude = exclude;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
21
|
* Returns true when there is a cycle detected.
|
|
@@ -42,7 +40,7 @@ export class SerializationContext {
|
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
close() {
|
|
45
|
-
for (const entity of this
|
|
43
|
+
for (const entity of this.#entities) {
|
|
46
44
|
delete helper(entity).__serializationContext.root;
|
|
47
45
|
}
|
|
48
46
|
}
|
|
@@ -73,7 +71,7 @@ export class SerializationContext {
|
|
|
73
71
|
}
|
|
74
72
|
}
|
|
75
73
|
isMarkedAsPopulated(entityName, prop) {
|
|
76
|
-
let populate = this
|
|
74
|
+
let populate = this.#populate ?? [];
|
|
77
75
|
for (const segment of this.path) {
|
|
78
76
|
const hints = populate.filter(p => p.field === segment[1]);
|
|
79
77
|
if (hints.length > 0) {
|
|
@@ -92,11 +90,18 @@ export class SerializationContext {
|
|
|
92
90
|
}
|
|
93
91
|
return !!populate?.some(p => p.field === prop);
|
|
94
92
|
}
|
|
93
|
+
isExcluded(entityName, prop) {
|
|
94
|
+
if (!this.#exclude || this.#exclude.length === 0) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const fullPath = this.path.map(segment => segment[1] + '.').join('') + prop;
|
|
98
|
+
return this.#exclude.includes(fullPath);
|
|
99
|
+
}
|
|
95
100
|
isPartiallyLoaded(entityName, prop) {
|
|
96
|
-
if (!this
|
|
101
|
+
if (!this.#fields) {
|
|
97
102
|
return true;
|
|
98
103
|
}
|
|
99
|
-
let fields = [...this
|
|
104
|
+
let fields = [...this.#fields];
|
|
100
105
|
for (const segment of this.path) {
|
|
101
106
|
/* v8 ignore next */
|
|
102
107
|
if (fields.length === 0) {
|
|
@@ -110,6 +115,6 @@ export class SerializationContext {
|
|
|
110
115
|
}
|
|
111
116
|
register(entity) {
|
|
112
117
|
helper(entity).__serializationContext.root = this;
|
|
113
|
-
this
|
|
118
|
+
this.#entities.add(entity);
|
|
114
119
|
}
|
|
115
120
|
}
|
package/types/UuidType.d.ts
CHANGED
|
@@ -4,5 +4,7 @@ import type { EntityProperty } from '../typings.js';
|
|
|
4
4
|
export declare class UuidType extends Type<string | null | undefined> {
|
|
5
5
|
getColumnType(prop: EntityProperty, platform: Platform): string;
|
|
6
6
|
compareAsType(): string;
|
|
7
|
+
convertToDatabaseValue(value: string | null | undefined, platform: Platform): string | null;
|
|
8
|
+
convertToJSValue(value: string | null | undefined, platform: Platform): string | null | undefined;
|
|
7
9
|
ensureComparable(): boolean;
|
|
8
10
|
}
|
package/types/UuidType.js
CHANGED
|
@@ -4,9 +4,21 @@ export class UuidType extends Type {
|
|
|
4
4
|
return platform.getUuidTypeDeclarationSQL(prop);
|
|
5
5
|
}
|
|
6
6
|
compareAsType() {
|
|
7
|
-
return 'string';
|
|
7
|
+
return this.platform?.compareUuids() ?? 'string';
|
|
8
|
+
}
|
|
9
|
+
convertToDatabaseValue(value, platform) {
|
|
10
|
+
if (value == null) {
|
|
11
|
+
return value;
|
|
12
|
+
}
|
|
13
|
+
return platform.convertUuidToDatabaseValue(value);
|
|
14
|
+
}
|
|
15
|
+
convertToJSValue(value, platform) {
|
|
16
|
+
if (value == null) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
return platform.convertUuidToJSValue(value);
|
|
8
20
|
}
|
|
9
21
|
ensureComparable() {
|
|
10
|
-
return
|
|
22
|
+
return this.platform?.compareUuids() !== 'string';
|
|
11
23
|
}
|
|
12
24
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -23,7 +23,8 @@ import { type IType, type TransformContext, Type } from './Type.js';
|
|
|
23
23
|
import { Uint8ArrayType } from './Uint8ArrayType.js';
|
|
24
24
|
import { UnknownType } from './UnknownType.js';
|
|
25
25
|
import { UuidType } from './UuidType.js';
|
|
26
|
-
export {
|
|
26
|
+
export type { TransformContext, IType };
|
|
27
|
+
export { Type, DateType, TimeType, DateTimeType, BigIntType, BlobType, Uint8ArrayType, ArrayType, EnumArrayType, EnumType, JsonType, IntegerType, SmallIntType, TinyIntType, MediumIntType, FloatType, DoubleType, BooleanType, DecimalType, StringType, UuidType, TextType, UnknownType, IntervalType, CharacterType, };
|
|
27
28
|
export declare const types: {
|
|
28
29
|
readonly date: typeof DateType;
|
|
29
30
|
readonly time: typeof TimeType;
|
package/typings.d.ts
CHANGED
|
@@ -234,8 +234,18 @@ export type FilterItemValue<T> = T | ExpandScalar<T> | Primary<T> | Raw;
|
|
|
234
234
|
export type FilterValue<T> = OperatorMap<FilterItemValue<T>> | FilterItemValue<T> | FilterItemValue<T>[] | null;
|
|
235
235
|
type FilterObjectProp<T, K extends PropertyKey> = K extends keyof MergeUnion<T> ? MergeUnion<T>[K] : K extends keyof T ? T[K] : never;
|
|
236
236
|
type ExpandQueryMerged<T> = [T] extends [object] ? [T] extends [Scalar] ? never : FilterQuery<MergeUnion<T>> : FilterValue<T>;
|
|
237
|
+
type ElemMatchCondition<T extends Record<string, any>> = {
|
|
238
|
+
[K in keyof T]?: T[K] | OperatorMap<T[K]>;
|
|
239
|
+
} & {
|
|
240
|
+
$or?: ElemMatchCondition<T>[];
|
|
241
|
+
$and?: ElemMatchCondition<T>[];
|
|
242
|
+
$not?: ElemMatchCondition<T>;
|
|
243
|
+
};
|
|
244
|
+
type ElemMatchFilter<T> = T extends readonly (infer E)[] ? E extends Record<string, any> ? {
|
|
245
|
+
$elemMatch: ElemMatchCondition<E>;
|
|
246
|
+
} : never : never;
|
|
237
247
|
export type FilterObject<T> = {
|
|
238
|
-
-readonly [K in EntityKey<T>]?: ExpandQuery<ExpandProperty<FilterObjectProp<T, K>>> | ExpandQueryMerged<ExpandProperty<FilterObjectProp<T, K>>> | FilterValue<ExpandProperty<FilterObjectProp<T, K>>> | null;
|
|
248
|
+
-readonly [K in EntityKey<T>]?: ExpandQuery<ExpandProperty<FilterObjectProp<T, K>>> | ExpandQueryMerged<ExpandProperty<FilterObjectProp<T, K>>> | FilterValue<ExpandProperty<FilterObjectProp<T, K>>> | ElemMatchFilter<FilterObjectProp<T, K>> | null;
|
|
239
249
|
};
|
|
240
250
|
export type ExpandQuery<T> = T extends object ? (T extends Scalar ? never : FilterQuery<T>) : FilterValue<T>;
|
|
241
251
|
export type EntityProps<T> = {
|
|
@@ -523,6 +533,7 @@ export interface EntityProperty<Owner = any, Target = any> {
|
|
|
523
533
|
nullable?: boolean;
|
|
524
534
|
inherited?: boolean;
|
|
525
535
|
renamedFrom?: string;
|
|
536
|
+
stiMerged?: boolean;
|
|
526
537
|
stiFieldNames?: string[];
|
|
527
538
|
stiFieldNameMap?: Dictionary<string>;
|
|
528
539
|
unsigned?: boolean;
|
|
@@ -3,12 +3,7 @@ import { ChangeSet } from './ChangeSet.js';
|
|
|
3
3
|
import { type Collection } from '../entity/Collection.js';
|
|
4
4
|
import type { EntityManager } from '../EntityManager.js';
|
|
5
5
|
export declare class ChangeSetComputer {
|
|
6
|
-
private
|
|
7
|
-
private readonly collectionUpdates;
|
|
8
|
-
private readonly comparator;
|
|
9
|
-
private readonly metadata;
|
|
10
|
-
private readonly platform;
|
|
11
|
-
private readonly config;
|
|
6
|
+
#private;
|
|
12
7
|
constructor(em: EntityManager, collectionUpdates: Set<Collection<AnyEntity>>);
|
|
13
8
|
computeChangeSet<T extends object>(entity: T): ChangeSet<T> | null;
|
|
14
9
|
/**
|