@mikro-orm/core 7.0.10-dev.9 → 7.0.10
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 +885 -583
- package/EntityManager.js +1927 -1899
- package/MikroORM.d.ts +103 -74
- package/MikroORM.js +177 -178
- package/README.md +1 -1
- package/cache/CacheAdapter.d.ts +36 -36
- package/cache/FileCacheAdapter.d.ts +30 -24
- package/cache/FileCacheAdapter.js +80 -78
- package/cache/GeneratedCacheAdapter.d.ts +18 -20
- package/cache/GeneratedCacheAdapter.js +30 -30
- package/cache/MemoryCacheAdapter.d.ts +18 -20
- package/cache/MemoryCacheAdapter.js +35 -36
- package/cache/NullCacheAdapter.d.ts +16 -16
- package/cache/NullCacheAdapter.js +24 -24
- package/connections/Connection.d.ts +95 -84
- package/connections/Connection.js +165 -168
- package/drivers/DatabaseDriver.d.ts +186 -80
- package/drivers/DatabaseDriver.js +450 -443
- package/drivers/IDatabaseDriver.d.ts +440 -301
- package/entity/BaseEntity.d.ts +120 -83
- package/entity/BaseEntity.js +43 -43
- package/entity/Collection.d.ts +215 -181
- package/entity/Collection.js +733 -725
- package/entity/EntityAssigner.d.ts +88 -77
- package/entity/EntityAssigner.js +231 -230
- package/entity/EntityFactory.d.ts +67 -55
- package/entity/EntityFactory.js +457 -416
- package/entity/EntityHelper.d.ts +35 -23
- package/entity/EntityHelper.js +302 -290
- package/entity/EntityIdentifier.d.ts +4 -4
- package/entity/EntityIdentifier.js +10 -10
- package/entity/EntityLoader.d.ts +98 -72
- package/entity/EntityLoader.js +805 -760
- package/entity/EntityRepository.d.ts +316 -201
- package/entity/EntityRepository.js +213 -213
- package/entity/PolymorphicRef.d.ts +5 -5
- package/entity/PolymorphicRef.js +10 -10
- package/entity/Reference.d.ts +127 -83
- package/entity/Reference.js +285 -279
- package/entity/WrappedEntity.d.ts +115 -72
- package/entity/WrappedEntity.js +168 -166
- package/entity/defineEntity.d.ts +1359 -654
- package/entity/defineEntity.js +527 -518
- package/entity/utils.d.ts +13 -3
- package/entity/utils.js +71 -73
- package/entity/validators.js +43 -43
- package/entity/wrap.js +8 -8
- package/enums.d.ts +258 -253
- package/enums.js +251 -252
- package/errors.d.ts +114 -72
- package/errors.js +350 -253
- package/events/EventManager.d.ts +26 -14
- package/events/EventManager.js +79 -77
- package/events/EventSubscriber.d.ts +29 -29
- package/events/TransactionEventBroadcaster.d.ts +15 -8
- package/events/TransactionEventBroadcaster.js +14 -14
- package/exceptions.d.ts +23 -40
- package/exceptions.js +35 -52
- package/hydration/Hydrator.d.ts +42 -17
- package/hydration/Hydrator.js +43 -43
- package/hydration/ObjectHydrator.d.ts +50 -17
- package/hydration/ObjectHydrator.js +483 -418
- package/index.d.ts +116 -2
- package/index.js +10 -1
- package/logging/DefaultLogger.d.ts +34 -32
- package/logging/DefaultLogger.js +86 -86
- package/logging/Logger.d.ts +41 -41
- package/logging/SimpleLogger.d.ts +13 -11
- package/logging/SimpleLogger.js +22 -22
- package/logging/colors.d.ts +6 -6
- package/logging/colors.js +11 -10
- package/logging/inspect.js +7 -7
- package/metadata/EntitySchema.d.ts +214 -130
- package/metadata/EntitySchema.js +411 -412
- package/metadata/MetadataDiscovery.d.ts +114 -114
- package/metadata/MetadataDiscovery.js +1962 -1879
- package/metadata/MetadataProvider.d.ts +29 -26
- package/metadata/MetadataProvider.js +95 -97
- package/metadata/MetadataStorage.d.ts +38 -32
- package/metadata/MetadataStorage.js +118 -118
- package/metadata/MetadataValidator.d.ts +39 -39
- package/metadata/MetadataValidator.js +381 -338
- package/metadata/discover-entities.d.ts +5 -2
- package/metadata/discover-entities.js +35 -37
- package/metadata/types.d.ts +615 -531
- package/naming-strategy/AbstractNamingStrategy.d.ts +54 -39
- package/naming-strategy/AbstractNamingStrategy.js +90 -85
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +6 -6
- package/naming-strategy/EntityCaseNamingStrategy.js +22 -22
- package/naming-strategy/MongoNamingStrategy.d.ts +6 -6
- package/naming-strategy/MongoNamingStrategy.js +18 -18
- package/naming-strategy/NamingStrategy.d.ts +109 -99
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +7 -7
- package/naming-strategy/UnderscoreNamingStrategy.js +21 -21
- package/not-supported.js +7 -4
- package/package.json +1 -1
- package/platforms/ExceptionConverter.d.ts +1 -1
- package/platforms/ExceptionConverter.js +4 -4
- package/platforms/Platform.d.ts +312 -303
- package/platforms/Platform.js +695 -675
- package/serialization/EntitySerializer.d.ts +49 -26
- package/serialization/EntitySerializer.js +224 -218
- package/serialization/EntityTransformer.d.ts +10 -6
- package/serialization/EntityTransformer.js +219 -217
- package/serialization/SerializationContext.d.ts +27 -23
- package/serialization/SerializationContext.js +105 -105
- package/types/ArrayType.d.ts +8 -8
- package/types/ArrayType.js +33 -33
- package/types/BigIntType.d.ts +17 -10
- package/types/BigIntType.js +37 -37
- package/types/BlobType.d.ts +3 -3
- package/types/BlobType.js +13 -13
- package/types/BooleanType.d.ts +4 -4
- package/types/BooleanType.js +12 -12
- package/types/CharacterType.d.ts +2 -2
- package/types/CharacterType.js +6 -6
- package/types/DateTimeType.d.ts +5 -5
- package/types/DateTimeType.js +15 -15
- package/types/DateType.d.ts +5 -5
- package/types/DateType.js +15 -15
- package/types/DecimalType.d.ts +7 -7
- package/types/DecimalType.js +26 -26
- package/types/DoubleType.d.ts +3 -3
- package/types/DoubleType.js +12 -12
- package/types/EnumArrayType.d.ts +5 -5
- package/types/EnumArrayType.js +24 -24
- package/types/EnumType.d.ts +3 -3
- package/types/EnumType.js +11 -11
- package/types/FloatType.d.ts +3 -3
- package/types/FloatType.js +9 -9
- package/types/IntegerType.d.ts +3 -3
- package/types/IntegerType.js +9 -9
- package/types/IntervalType.d.ts +4 -4
- package/types/IntervalType.js +12 -12
- package/types/JsonType.d.ts +8 -8
- package/types/JsonType.js +32 -32
- package/types/MediumIntType.d.ts +1 -1
- package/types/MediumIntType.js +3 -3
- package/types/SmallIntType.d.ts +3 -3
- package/types/SmallIntType.js +9 -9
- package/types/StringType.d.ts +4 -4
- package/types/StringType.js +12 -12
- package/types/TextType.d.ts +3 -3
- package/types/TextType.js +9 -9
- package/types/TimeType.d.ts +5 -5
- package/types/TimeType.js +17 -17
- package/types/TinyIntType.d.ts +3 -3
- package/types/TinyIntType.js +10 -10
- package/types/Type.d.ts +83 -79
- package/types/Type.js +82 -82
- package/types/Uint8ArrayType.d.ts +4 -4
- package/types/Uint8ArrayType.js +21 -21
- package/types/UnknownType.d.ts +4 -4
- package/types/UnknownType.js +12 -12
- package/types/UuidType.d.ts +5 -5
- package/types/UuidType.js +19 -19
- package/types/index.d.ts +75 -49
- package/types/index.js +52 -26
- package/typings.d.ts +1254 -741
- package/typings.js +244 -233
- package/unit-of-work/ChangeSet.d.ts +26 -26
- package/unit-of-work/ChangeSet.js +56 -56
- package/unit-of-work/ChangeSetComputer.d.ts +12 -12
- package/unit-of-work/ChangeSetComputer.js +187 -179
- package/unit-of-work/ChangeSetPersister.d.ts +69 -50
- package/unit-of-work/ChangeSetPersister.js +465 -442
- package/unit-of-work/CommitOrderCalculator.d.ts +40 -40
- package/unit-of-work/CommitOrderCalculator.js +89 -88
- package/unit-of-work/IdentityMap.d.ts +31 -31
- package/unit-of-work/IdentityMap.js +105 -105
- package/unit-of-work/UnitOfWork.d.ts +181 -141
- package/unit-of-work/UnitOfWork.js +1237 -1223
- package/utils/AbstractMigrator.d.ts +111 -91
- package/utils/AbstractMigrator.js +275 -275
- package/utils/AbstractSchemaGenerator.d.ts +43 -34
- package/utils/AbstractSchemaGenerator.js +121 -122
- package/utils/AsyncContext.d.ts +3 -3
- package/utils/AsyncContext.js +34 -35
- package/utils/Configuration.d.ts +852 -808
- package/utils/Configuration.js +359 -344
- package/utils/Cursor.d.ts +40 -22
- package/utils/Cursor.js +135 -127
- package/utils/DataloaderUtils.d.ts +58 -43
- package/utils/DataloaderUtils.js +203 -198
- package/utils/EntityComparator.d.ts +99 -82
- package/utils/EntityComparator.js +829 -737
- package/utils/NullHighlighter.d.ts +1 -1
- package/utils/NullHighlighter.js +3 -3
- package/utils/QueryHelper.d.ts +79 -51
- package/utils/QueryHelper.js +375 -361
- package/utils/RawQueryFragment.d.ts +52 -36
- package/utils/RawQueryFragment.js +147 -109
- package/utils/RequestContext.d.ts +32 -32
- package/utils/RequestContext.js +52 -53
- package/utils/TransactionContext.d.ts +16 -16
- package/utils/TransactionContext.js +27 -27
- package/utils/TransactionManager.d.ts +58 -58
- package/utils/TransactionManager.js +202 -196
- package/utils/Utils.d.ts +204 -145
- package/utils/Utils.js +826 -817
- package/utils/clone.js +105 -114
- package/utils/env-vars.js +90 -88
- package/utils/fs-utils.d.ts +15 -15
- package/utils/fs-utils.js +181 -182
- package/utils/upsert-utils.d.ts +20 -5
- package/utils/upsert-utils.js +114 -116
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityManagerType
|
|
1
|
+
import { EntityManagerType } from './IDatabaseDriver.js';
|
|
2
2
|
import { Utils } from '../utils/Utils.js';
|
|
3
3
|
import { Cursor } from '../utils/Cursor.js';
|
|
4
4
|
import { isRaw, raw } from '../utils/RawQueryFragment.js';
|
|
@@ -12,474 +12,481 @@ import { JsonType } from '../types/JsonType.js';
|
|
|
12
12
|
import { MikroORM } from '../MikroORM.js';
|
|
13
13
|
/** Abstract base class for all database drivers, implementing common driver logic. */
|
|
14
14
|
export class DatabaseDriver {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
/* v8 ignore next */
|
|
59
|
-
{
|
|
60
|
-
const pk = coll.property.targetMeta.primaryKeys[0];
|
|
61
|
-
const data = { [coll.property.name]: coll.getIdentifiers(pk) };
|
|
62
|
-
await this.nativeUpdate(coll.owner.constructor, helper(coll.owner).getPrimaryKey(), data, options);
|
|
63
|
-
}
|
|
15
|
+
config;
|
|
16
|
+
dependencies;
|
|
17
|
+
[EntityManagerType];
|
|
18
|
+
connection;
|
|
19
|
+
replicas = [];
|
|
20
|
+
platform;
|
|
21
|
+
comparator;
|
|
22
|
+
metadata;
|
|
23
|
+
constructor(config, dependencies) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
this.dependencies = dependencies;
|
|
26
|
+
}
|
|
27
|
+
async nativeUpdateMany(entityName, where, data, options) {
|
|
28
|
+
throw new Error(`Batch updates are not supported by ${this.constructor.name} driver`);
|
|
29
|
+
}
|
|
30
|
+
/** Creates a new EntityManager instance bound to this driver. */
|
|
31
|
+
createEntityManager(useContext) {
|
|
32
|
+
const EntityManagerClass = this.config.get('entityManager', EntityManager);
|
|
33
|
+
return new EntityManagerClass(this.config, this, this.metadata, useContext);
|
|
34
|
+
}
|
|
35
|
+
/* v8 ignore next */
|
|
36
|
+
async findVirtual(entityName, where, options) {
|
|
37
|
+
throw new Error(`Virtual entities are not supported by ${this.constructor.name} driver.`);
|
|
38
|
+
}
|
|
39
|
+
/* v8 ignore next */
|
|
40
|
+
async countVirtual(entityName, where, options) {
|
|
41
|
+
throw new Error(`Counting virtual entities is not supported by ${this.constructor.name} driver.`);
|
|
42
|
+
}
|
|
43
|
+
async aggregate(entityName, pipeline) {
|
|
44
|
+
throw new Error(`Aggregations are not supported by ${this.constructor.name} driver`);
|
|
45
|
+
}
|
|
46
|
+
async loadFromPivotTable(prop, owners, where, orderBy, ctx, options, pivotJoin) {
|
|
47
|
+
throw new Error(`${this.constructor.name} does not use pivot tables`);
|
|
48
|
+
}
|
|
49
|
+
async syncCollections(collections, options) {
|
|
50
|
+
for (const coll of collections) {
|
|
51
|
+
/* v8 ignore else */
|
|
52
|
+
if (!coll.property.owner) {
|
|
53
|
+
if (coll.getSnapshot() === undefined) {
|
|
54
|
+
throw ValidationError.cannotModifyInverseCollection(coll.owner, coll.property);
|
|
64
55
|
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
/* v8 ignore next */
|
|
59
|
+
{
|
|
60
|
+
const pk = coll.property.targetMeta.primaryKeys[0];
|
|
61
|
+
const data = { [coll.property.name]: coll.getIdentifiers(pk) };
|
|
62
|
+
await this.nativeUpdate(coll.owner.constructor, helper(coll.owner).getPrimaryKey(), data, options);
|
|
63
|
+
}
|
|
65
64
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return this.comparator.mapResult(meta, result);
|
|
72
|
-
}
|
|
73
|
-
/** Opens the primary connection and all read replicas. */
|
|
74
|
-
async connect(options) {
|
|
75
|
-
await this.connection.connect(options);
|
|
76
|
-
await Promise.all(this.replicas.map(replica => replica.connect()));
|
|
77
|
-
return this.connection;
|
|
78
|
-
}
|
|
79
|
-
/** Closes all connections and re-establishes them. */
|
|
80
|
-
async reconnect(options) {
|
|
81
|
-
await this.close(true);
|
|
82
|
-
await this.connect(options);
|
|
83
|
-
return this.connection;
|
|
65
|
+
}
|
|
66
|
+
/** Maps raw database result to entity data, converting column names to property names. */
|
|
67
|
+
mapResult(result, meta, populate = []) {
|
|
68
|
+
if (!result || !meta) {
|
|
69
|
+
return result ?? null;
|
|
84
70
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
71
|
+
return this.comparator.mapResult(meta, result);
|
|
72
|
+
}
|
|
73
|
+
/** Opens the primary connection and all read replicas. */
|
|
74
|
+
async connect(options) {
|
|
75
|
+
await this.connection.connect(options);
|
|
76
|
+
await Promise.all(this.replicas.map(replica => replica.connect()));
|
|
77
|
+
return this.connection;
|
|
78
|
+
}
|
|
79
|
+
/** Closes all connections and re-establishes them. */
|
|
80
|
+
async reconnect(options) {
|
|
81
|
+
await this.close(true);
|
|
82
|
+
await this.connect(options);
|
|
83
|
+
return this.connection;
|
|
84
|
+
}
|
|
85
|
+
/** Returns the write connection or a random read replica. */
|
|
86
|
+
getConnection(type = 'write') {
|
|
87
|
+
if (type === 'write' || this.replicas.length === 0) {
|
|
88
|
+
return this.connection;
|
|
92
89
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
const rand = Utils.randomInt(0, this.replicas.length - 1);
|
|
91
|
+
return this.replicas[rand];
|
|
92
|
+
}
|
|
93
|
+
/** Closes the primary connection and all read replicas. */
|
|
94
|
+
async close(force) {
|
|
95
|
+
await Promise.all(this.replicas.map(replica => replica.close(force)));
|
|
96
|
+
await this.connection.close(force);
|
|
97
|
+
}
|
|
98
|
+
/** Returns the database platform abstraction for this driver. */
|
|
99
|
+
getPlatform() {
|
|
100
|
+
return this.platform;
|
|
101
|
+
}
|
|
102
|
+
/** Sets the metadata storage and initializes the comparator for all connections. */
|
|
103
|
+
setMetadata(metadata) {
|
|
104
|
+
this.metadata = metadata;
|
|
105
|
+
this.comparator = this.config.getComparator(metadata);
|
|
106
|
+
this.connection.setMetadata(metadata);
|
|
107
|
+
this.connection.setPlatform(this.platform);
|
|
108
|
+
this.replicas.forEach(replica => {
|
|
109
|
+
replica.setMetadata(metadata);
|
|
110
|
+
replica.setPlatform(this.platform);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Returns the metadata storage used by this driver. */
|
|
114
|
+
getMetadata() {
|
|
115
|
+
return this.metadata;
|
|
116
|
+
}
|
|
117
|
+
/** Returns the names of native database dependencies required by this driver. */
|
|
118
|
+
getDependencies() {
|
|
119
|
+
return this.dependencies;
|
|
120
|
+
}
|
|
121
|
+
isPopulated(meta, prop, hint, name) {
|
|
122
|
+
if (hint.field === prop.name || hint.field === name || hint.all) {
|
|
123
|
+
return true;
|
|
97
124
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return this.platform;
|
|
125
|
+
if (prop.embedded && hint.children && meta.properties[prop.embedded[0]].name === hint.field) {
|
|
126
|
+
return hint.children.some(c => this.isPopulated(meta, prop, c, prop.embedded[1]));
|
|
101
127
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
processCursorOptions(meta, options, orderBy) {
|
|
131
|
+
const { first, last, before, after, overfetch } = options;
|
|
132
|
+
const limit = first ?? last;
|
|
133
|
+
const isLast = !first && !!last;
|
|
134
|
+
const definition = Cursor.getDefinition(meta, orderBy);
|
|
135
|
+
const $and = [];
|
|
136
|
+
// allow POJO as well, we care only about the correct key being present
|
|
137
|
+
const isCursor = (val, key) => {
|
|
138
|
+
return !!val && typeof val === 'object' && key in val;
|
|
139
|
+
};
|
|
140
|
+
const createCursor = (val, key, inverse = false) => {
|
|
141
|
+
let def = isCursor(val, key) ? val[key] : val;
|
|
142
|
+
if (Utils.isPlainObject(def)) {
|
|
143
|
+
def = Cursor.for(meta, def, orderBy);
|
|
144
|
+
}
|
|
145
|
+
/* v8 ignore next */
|
|
146
|
+
const offsets = def ? Cursor.decode(def) : [];
|
|
147
|
+
if (definition.length === offsets.length) {
|
|
148
|
+
return this.createCursorCondition(definition, offsets, inverse, meta);
|
|
149
|
+
}
|
|
150
|
+
/* v8 ignore next */
|
|
151
|
+
return {};
|
|
152
|
+
};
|
|
153
|
+
if (after) {
|
|
154
|
+
$and.push(createCursor(after, 'endCursor'));
|
|
112
155
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return this.metadata;
|
|
156
|
+
if (before) {
|
|
157
|
+
$and.push(createCursor(before, 'startCursor', true));
|
|
116
158
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return this.dependencies;
|
|
159
|
+
if (limit != null) {
|
|
160
|
+
options.limit = limit + (overfetch ? 1 : 0);
|
|
120
161
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
162
|
+
const createOrderBy = (prop, direction) => {
|
|
163
|
+
if (Utils.isPlainObject(direction)) {
|
|
164
|
+
const value = Utils.getObjectQueryKeys(direction).reduce((o, key) => {
|
|
165
|
+
Object.assign(o, createOrderBy(key, direction[key]));
|
|
166
|
+
return o;
|
|
167
|
+
}, {});
|
|
168
|
+
return { [prop]: value };
|
|
169
|
+
}
|
|
170
|
+
const desc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
|
171
|
+
const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
|
|
172
|
+
return { [prop]: dir };
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
|
|
176
|
+
where: $and.length > 1 ? { $and } : { ...$and[0] },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
createCursorCondition(definition, offsets, inverse, meta) {
|
|
180
|
+
const createCondition = (prop, direction, offset, eq = false, path = prop) => {
|
|
181
|
+
if (Utils.isPlainObject(direction)) {
|
|
182
|
+
if (offset === undefined) {
|
|
183
|
+
throw CursorError.missingValue(meta.className, path);
|
|
124
184
|
}
|
|
125
|
-
|
|
126
|
-
|
|
185
|
+
const value = Utils.keys(direction).reduce((o, key) => {
|
|
186
|
+
Object.assign(o, createCondition(key, direction[key], offset?.[key], eq, `${path}.${key}`));
|
|
187
|
+
return o;
|
|
188
|
+
}, {});
|
|
189
|
+
return { [prop]: value };
|
|
190
|
+
}
|
|
191
|
+
const isDesc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
|
192
|
+
const dirStr = direction.toString().toLowerCase();
|
|
193
|
+
let nullsFirst;
|
|
194
|
+
if (dirStr.includes('nulls first')) {
|
|
195
|
+
nullsFirst = true;
|
|
196
|
+
} else if (dirStr.includes('nulls last')) {
|
|
197
|
+
nullsFirst = false;
|
|
198
|
+
} else {
|
|
199
|
+
// Default: NULLS LAST for ASC, NULLS FIRST for DESC (matches most databases)
|
|
200
|
+
nullsFirst = isDesc;
|
|
201
|
+
}
|
|
202
|
+
const operator = Utils.xor(isDesc, inverse) ? '$lt' : '$gt';
|
|
203
|
+
// For leaf-level properties, undefined means missing value
|
|
204
|
+
if (offset === undefined) {
|
|
205
|
+
throw CursorError.missingValue(meta.className, path);
|
|
206
|
+
}
|
|
207
|
+
// Handle null offset (intentional null cursor value)
|
|
208
|
+
if (offset === null) {
|
|
209
|
+
if (eq) {
|
|
210
|
+
// Equal to null
|
|
211
|
+
return { [prop]: null };
|
|
127
212
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const isLast = !first && !!last;
|
|
134
|
-
const definition = Cursor.getDefinition(meta, orderBy);
|
|
135
|
-
const $and = [];
|
|
136
|
-
// allow POJO as well, we care only about the correct key being present
|
|
137
|
-
const isCursor = (val, key) => {
|
|
138
|
-
return !!val && typeof val === 'object' && key in val;
|
|
139
|
-
};
|
|
140
|
-
const createCursor = (val, key, inverse = false) => {
|
|
141
|
-
let def = isCursor(val, key) ? val[key] : val;
|
|
142
|
-
if (Utils.isPlainObject(def)) {
|
|
143
|
-
def = Cursor.for(meta, def, orderBy);
|
|
144
|
-
}
|
|
145
|
-
/* v8 ignore next */
|
|
146
|
-
const offsets = def ? Cursor.decode(def) : [];
|
|
147
|
-
if (definition.length === offsets.length) {
|
|
148
|
-
return this.createCursorCondition(definition, offsets, inverse, meta);
|
|
149
|
-
}
|
|
150
|
-
/* v8 ignore next */
|
|
151
|
-
return {};
|
|
152
|
-
};
|
|
153
|
-
if (after) {
|
|
154
|
-
$and.push(createCursor(after, 'endCursor'));
|
|
213
|
+
// Strict comparison with null cursor value
|
|
214
|
+
// hasItemsAfterNull: forward + nullsFirst, or backward + nullsLast
|
|
215
|
+
const hasItemsAfterNull = Utils.xor(nullsFirst, inverse);
|
|
216
|
+
if (hasItemsAfterNull) {
|
|
217
|
+
return { [prop]: { $ne: null } };
|
|
155
218
|
}
|
|
156
|
-
|
|
157
|
-
|
|
219
|
+
// No items after null in this direction, return impossible condition
|
|
220
|
+
return { [prop]: [] };
|
|
221
|
+
}
|
|
222
|
+
// Non-null offset
|
|
223
|
+
return { [prop]: { [operator + (eq ? 'e' : '')]: offset } };
|
|
224
|
+
};
|
|
225
|
+
const [order, ...otherOrders] = definition;
|
|
226
|
+
const [offset, ...otherOffsets] = offsets;
|
|
227
|
+
const [prop, direction] = order;
|
|
228
|
+
if (!otherOrders.length) {
|
|
229
|
+
return createCondition(prop, direction, offset);
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
...createCondition(prop, direction, offset, true),
|
|
233
|
+
$or: [
|
|
234
|
+
createCondition(prop, direction, offset),
|
|
235
|
+
this.createCursorCondition(otherOrders, otherOffsets, inverse, meta),
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** @internal */
|
|
240
|
+
mapDataToFieldNames(data, stringifyJsonArrays, properties, convertCustomTypes, object) {
|
|
241
|
+
if (!properties || data == null) {
|
|
242
|
+
return data;
|
|
243
|
+
}
|
|
244
|
+
data = Object.assign({}, data); // copy first
|
|
245
|
+
Object.keys(data).forEach(k => {
|
|
246
|
+
const prop = properties[k];
|
|
247
|
+
if (!prop) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (prop.embeddedProps && !prop.object && !object) {
|
|
251
|
+
const copy = data[k];
|
|
252
|
+
delete data[k];
|
|
253
|
+
Object.assign(
|
|
254
|
+
data,
|
|
255
|
+
this.mapDataToFieldNames(copy, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes),
|
|
256
|
+
);
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (prop.embeddedProps && (object || prop.object)) {
|
|
260
|
+
const copy = data[k];
|
|
261
|
+
delete data[k];
|
|
262
|
+
if (prop.array) {
|
|
263
|
+
data[prop.fieldNames[0]] = copy?.map(item =>
|
|
264
|
+
this.mapDataToFieldNames(item, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes, true),
|
|
265
|
+
);
|
|
266
|
+
} else {
|
|
267
|
+
data[prop.fieldNames[0]] = this.mapDataToFieldNames(
|
|
268
|
+
copy,
|
|
269
|
+
stringifyJsonArrays,
|
|
270
|
+
prop.embeddedProps,
|
|
271
|
+
convertCustomTypes,
|
|
272
|
+
true,
|
|
273
|
+
);
|
|
158
274
|
}
|
|
159
|
-
if (
|
|
160
|
-
|
|
275
|
+
if (stringifyJsonArrays && prop.array && !object) {
|
|
276
|
+
data[prop.fieldNames[0]] = this.platform.convertJsonToDatabaseValue(data[prop.fieldNames[0]]);
|
|
161
277
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
return o;
|
|
188
|
-
}, {});
|
|
189
|
-
return { [prop]: value };
|
|
190
|
-
}
|
|
191
|
-
const isDesc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
|
192
|
-
const dirStr = direction.toString().toLowerCase();
|
|
193
|
-
let nullsFirst;
|
|
194
|
-
if (dirStr.includes('nulls first')) {
|
|
195
|
-
nullsFirst = true;
|
|
196
|
-
}
|
|
197
|
-
else if (dirStr.includes('nulls last')) {
|
|
198
|
-
nullsFirst = false;
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
// Default: NULLS LAST for ASC, NULLS FIRST for DESC (matches most databases)
|
|
202
|
-
nullsFirst = isDesc;
|
|
203
|
-
}
|
|
204
|
-
const operator = Utils.xor(isDesc, inverse) ? '$lt' : '$gt';
|
|
205
|
-
// For leaf-level properties, undefined means missing value
|
|
206
|
-
if (offset === undefined) {
|
|
207
|
-
throw CursorError.missingValue(meta.className, path);
|
|
208
|
-
}
|
|
209
|
-
// Handle null offset (intentional null cursor value)
|
|
210
|
-
if (offset === null) {
|
|
211
|
-
if (eq) {
|
|
212
|
-
// Equal to null
|
|
213
|
-
return { [prop]: null };
|
|
214
|
-
}
|
|
215
|
-
// Strict comparison with null cursor value
|
|
216
|
-
// hasItemsAfterNull: forward + nullsFirst, or backward + nullsLast
|
|
217
|
-
const hasItemsAfterNull = Utils.xor(nullsFirst, inverse);
|
|
218
|
-
if (hasItemsAfterNull) {
|
|
219
|
-
return { [prop]: { $ne: null } };
|
|
220
|
-
}
|
|
221
|
-
// No items after null in this direction, return impossible condition
|
|
222
|
-
return { [prop]: [] };
|
|
223
|
-
}
|
|
224
|
-
// Non-null offset
|
|
225
|
-
return { [prop]: { [operator + (eq ? 'e' : '')]: offset } };
|
|
226
|
-
};
|
|
227
|
-
const [order, ...otherOrders] = definition;
|
|
228
|
-
const [offset, ...otherOffsets] = offsets;
|
|
229
|
-
const [prop, direction] = order;
|
|
230
|
-
if (!otherOrders.length) {
|
|
231
|
-
return createCondition(prop, direction, offset);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// Handle polymorphic relations - convert tuple or PolymorphicRef to separate columns
|
|
281
|
+
// Tuple format: ['discriminator', id] or ['discriminator', id1, id2] for composite keys
|
|
282
|
+
// Must be checked BEFORE joinColumns array handling since polymorphic uses fieldNames (includes discriminator)
|
|
283
|
+
if (prop.polymorphic && prop.fieldNames && prop.fieldNames.length >= 2) {
|
|
284
|
+
let discriminator;
|
|
285
|
+
let ids;
|
|
286
|
+
if (Array.isArray(data[k]) && typeof data[k][0] === 'string' && prop.discriminatorMap?.[data[k][0]]) {
|
|
287
|
+
// Tuple format: ['discriminator', ...ids]
|
|
288
|
+
const [disc, ...rest] = data[k];
|
|
289
|
+
discriminator = disc;
|
|
290
|
+
ids = rest;
|
|
291
|
+
} else if (data[k] instanceof PolymorphicRef) {
|
|
292
|
+
// PolymorphicRef wrapper (internal use)
|
|
293
|
+
discriminator = data[k].discriminator;
|
|
294
|
+
const polyId = data[k].id;
|
|
295
|
+
// Handle object-style composite key IDs like { tenantId: 1, orgId: 100 }
|
|
296
|
+
if (polyId && typeof polyId === 'object' && !Array.isArray(polyId)) {
|
|
297
|
+
const targetEntity = prop.discriminatorMap?.[discriminator];
|
|
298
|
+
const targetMeta = this.metadata.get(targetEntity);
|
|
299
|
+
ids = targetMeta.primaryKeys.map(pk => polyId[pk]);
|
|
300
|
+
} else {
|
|
301
|
+
ids = Utils.asArray(polyId);
|
|
302
|
+
}
|
|
232
303
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
mapDataToFieldNames(data, stringifyJsonArrays, properties, convertCustomTypes, object) {
|
|
243
|
-
if (!properties || data == null) {
|
|
244
|
-
return data;
|
|
304
|
+
if (discriminator) {
|
|
305
|
+
const discriminatorColumn = prop.fieldNames[0];
|
|
306
|
+
const idColumns = prop.fieldNames.slice(1);
|
|
307
|
+
delete data[k];
|
|
308
|
+
data[discriminatorColumn] = discriminator;
|
|
309
|
+
idColumns.forEach((col, idx) => {
|
|
310
|
+
data[col] = ids[idx];
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
245
313
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
data[prop.fieldNames[0]] = this.platform.convertJsonToDatabaseValue(data[prop.fieldNames[0]]);
|
|
269
|
-
}
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
// Handle polymorphic relations - convert tuple or PolymorphicRef to separate columns
|
|
273
|
-
// Tuple format: ['discriminator', id] or ['discriminator', id1, id2] for composite keys
|
|
274
|
-
// Must be checked BEFORE joinColumns array handling since polymorphic uses fieldNames (includes discriminator)
|
|
275
|
-
if (prop.polymorphic && prop.fieldNames && prop.fieldNames.length >= 2) {
|
|
276
|
-
let discriminator;
|
|
277
|
-
let ids;
|
|
278
|
-
if (Array.isArray(data[k]) && typeof data[k][0] === 'string' && prop.discriminatorMap?.[data[k][0]]) {
|
|
279
|
-
// Tuple format: ['discriminator', ...ids]
|
|
280
|
-
const [disc, ...rest] = data[k];
|
|
281
|
-
discriminator = disc;
|
|
282
|
-
ids = rest;
|
|
283
|
-
}
|
|
284
|
-
else if (data[k] instanceof PolymorphicRef) {
|
|
285
|
-
// PolymorphicRef wrapper (internal use)
|
|
286
|
-
discriminator = data[k].discriminator;
|
|
287
|
-
const polyId = data[k].id;
|
|
288
|
-
// Handle object-style composite key IDs like { tenantId: 1, orgId: 100 }
|
|
289
|
-
if (polyId && typeof polyId === 'object' && !Array.isArray(polyId)) {
|
|
290
|
-
const targetEntity = prop.discriminatorMap?.[discriminator];
|
|
291
|
-
const targetMeta = this.metadata.get(targetEntity);
|
|
292
|
-
ids = targetMeta.primaryKeys.map(pk => polyId[pk]);
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
ids = Utils.asArray(polyId);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (discriminator) {
|
|
299
|
-
const discriminatorColumn = prop.fieldNames[0];
|
|
300
|
-
const idColumns = prop.fieldNames.slice(1);
|
|
301
|
-
delete data[k];
|
|
302
|
-
data[discriminatorColumn] = discriminator;
|
|
303
|
-
idColumns.forEach((col, idx) => {
|
|
304
|
-
data[col] = ids[idx];
|
|
305
|
-
});
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
310
|
-
const copy = Utils.flatten(data[k]);
|
|
311
|
-
delete data[k];
|
|
312
|
-
(prop.ownColumns ?? prop.joinColumns).forEach(col => (data[col] = copy[prop.joinColumns.indexOf(col)]));
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
if (prop.joinColumns?.length > 1 && data[k] == null) {
|
|
316
|
-
delete data[k];
|
|
317
|
-
prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
if (prop.customType &&
|
|
321
|
-
convertCustomTypes &&
|
|
322
|
-
!(prop.customType instanceof JsonType && object) &&
|
|
323
|
-
!isRaw(data[k])) {
|
|
324
|
-
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
|
|
325
|
-
fromQuery: true,
|
|
326
|
-
key: k,
|
|
327
|
-
mode: 'query-data',
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
|
|
331
|
-
const quoted = this.platform.quoteValue(data[k]);
|
|
332
|
-
const sql = prop.customType.convertToDatabaseValueSQL(quoted, this.platform);
|
|
333
|
-
data[k] = raw(sql.replace(/\?/g, '\\?'));
|
|
334
|
-
}
|
|
335
|
-
if (prop.fieldNames) {
|
|
336
|
-
Utils.renameKey(data, k, prop.fieldNames[0]);
|
|
337
|
-
}
|
|
314
|
+
}
|
|
315
|
+
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
316
|
+
const copy = Utils.flatten(data[k]);
|
|
317
|
+
delete data[k];
|
|
318
|
+
(prop.ownColumns ?? prop.joinColumns).forEach(col => (data[col] = copy[prop.joinColumns.indexOf(col)]));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (prop.joinColumns?.length > 1 && data[k] == null) {
|
|
322
|
+
delete data[k];
|
|
323
|
+
prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (
|
|
327
|
+
prop.customType &&
|
|
328
|
+
convertCustomTypes &&
|
|
329
|
+
!(prop.customType instanceof JsonType && object) &&
|
|
330
|
+
!isRaw(data[k])
|
|
331
|
+
) {
|
|
332
|
+
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
|
|
333
|
+
fromQuery: true,
|
|
334
|
+
key: k,
|
|
335
|
+
mode: 'query-data',
|
|
338
336
|
});
|
|
339
|
-
|
|
337
|
+
}
|
|
338
|
+
if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
|
|
339
|
+
const quoted = this.platform.quoteValue(data[k]);
|
|
340
|
+
const sql = prop.customType.convertToDatabaseValueSQL(quoted, this.platform);
|
|
341
|
+
data[k] = raw(sql.replace(/\?/g, '\\?'));
|
|
342
|
+
}
|
|
343
|
+
if (prop.fieldNames) {
|
|
344
|
+
Utils.renameKey(data, k, prop.fieldNames[0]);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
return data;
|
|
348
|
+
}
|
|
349
|
+
inlineEmbeddables(meta, data, where) {
|
|
350
|
+
/* v8 ignore next */
|
|
351
|
+
if (data == null) {
|
|
352
|
+
return;
|
|
340
353
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
throw ValidationError.invalidEmbeddableQuery(meta.class, kkk, sub.type);
|
|
370
|
-
}
|
|
371
|
-
inline(payload[sub.embedded[1]], sub.embeddedProps[kkk], [...path, sub.fieldNames[0]]);
|
|
372
|
-
});
|
|
373
|
-
}
|
|
374
|
-
data[`${path.join('.')}.${sub.fieldNames[0]}`] = payload[sub.embedded[1]];
|
|
375
|
-
};
|
|
376
|
-
const parentPropName = kk.substring(0, kk.indexOf('.'));
|
|
377
|
-
// we might be using some native JSON operator, e.g. with mongodb's `$geoWithin` or `$exists`
|
|
378
|
-
if (props[kk]) {
|
|
379
|
-
/* v8 ignore next */
|
|
380
|
-
inline(data[prop.name], props[kk] || props[parentPropName], [prop.fieldNames[0]]);
|
|
381
|
-
}
|
|
382
|
-
else if (props[parentPropName]) {
|
|
383
|
-
data[`${prop.fieldNames[0]}.${kk}`] = data[prop.name][kk];
|
|
384
|
-
}
|
|
385
|
-
else {
|
|
386
|
-
unknownProp = true;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
else if (props[kk]) {
|
|
390
|
-
data[props[kk].fieldNames[0]] = data[prop.name][props[kk].embedded[1]];
|
|
391
|
-
}
|
|
392
|
-
else {
|
|
393
|
-
throw ValidationError.invalidEmbeddableQuery(meta.class, kk, prop.type);
|
|
394
|
-
}
|
|
354
|
+
Utils.keys(data).forEach(k => {
|
|
355
|
+
if (Utils.isOperator(k)) {
|
|
356
|
+
Utils.asArray(data[k]).forEach(payload => this.inlineEmbeddables(meta, payload, where));
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
meta.props.forEach(prop => {
|
|
360
|
+
if (prop.kind === ReferenceKind.EMBEDDED && prop.object && !where && Utils.isObject(data[prop.name])) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (prop.kind === ReferenceKind.EMBEDDED && Utils.isObject(data[prop.name])) {
|
|
364
|
+
const props = prop.embeddedProps;
|
|
365
|
+
let unknownProp = false;
|
|
366
|
+
Object.keys(data[prop.name]).forEach(kk => {
|
|
367
|
+
// explicitly allow `$exists`, `$eq`, `$ne` and `$elemMatch` operators here as they can't be misused this way
|
|
368
|
+
const operator = Object.keys(data[prop.name]).some(
|
|
369
|
+
f => Utils.isOperator(f) && !['$exists', '$ne', '$eq', '$elemMatch'].includes(f),
|
|
370
|
+
);
|
|
371
|
+
if (operator) {
|
|
372
|
+
throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.class, prop.name, data);
|
|
373
|
+
}
|
|
374
|
+
if (prop.object && where) {
|
|
375
|
+
const inline = (payload, sub, path) => {
|
|
376
|
+
if (sub.kind === ReferenceKind.EMBEDDED && Utils.isObject(payload[sub.embedded[1]])) {
|
|
377
|
+
return Object.keys(payload[sub.embedded[1]]).forEach(kkk => {
|
|
378
|
+
if (!sub.embeddedProps[kkk]) {
|
|
379
|
+
throw ValidationError.invalidEmbeddableQuery(meta.class, kkk, sub.type);
|
|
380
|
+
}
|
|
381
|
+
inline(payload[sub.embedded[1]], sub.embeddedProps[kkk], [...path, sub.fieldNames[0]]);
|
|
395
382
|
});
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
383
|
+
}
|
|
384
|
+
data[`${path.join('.')}.${sub.fieldNames[0]}`] = payload[sub.embedded[1]];
|
|
385
|
+
};
|
|
386
|
+
const parentPropName = kk.substring(0, kk.indexOf('.'));
|
|
387
|
+
// we might be using some native JSON operator, e.g. with mongodb's `$geoWithin` or `$exists`
|
|
388
|
+
if (props[kk]) {
|
|
389
|
+
/* v8 ignore next */
|
|
390
|
+
inline(data[prop.name], props[kk] || props[parentPropName], [prop.fieldNames[0]]);
|
|
391
|
+
} else if (props[parentPropName]) {
|
|
392
|
+
data[`${prop.fieldNames[0]}.${kk}`] = data[prop.name][kk];
|
|
393
|
+
} else {
|
|
394
|
+
unknownProp = true;
|
|
399
395
|
}
|
|
396
|
+
} else if (props[kk]) {
|
|
397
|
+
data[props[kk].fieldNames[0]] = data[prop.name][props[kk].embedded[1]];
|
|
398
|
+
} else {
|
|
399
|
+
throw ValidationError.invalidEmbeddableQuery(meta.class, kk, prop.type);
|
|
400
|
+
}
|
|
400
401
|
});
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
return meta.getPrimaryProps().flatMap(pk => pk.fieldNames);
|
|
404
|
-
}
|
|
405
|
-
createReplicas(cb) {
|
|
406
|
-
const replicas = this.config.get('replicas', []);
|
|
407
|
-
const ret = [];
|
|
408
|
-
const props = [
|
|
409
|
-
'dbName',
|
|
410
|
-
'clientUrl',
|
|
411
|
-
'host',
|
|
412
|
-
'port',
|
|
413
|
-
'user',
|
|
414
|
-
'password',
|
|
415
|
-
'multipleStatements',
|
|
416
|
-
'pool',
|
|
417
|
-
'name',
|
|
418
|
-
'driverOptions',
|
|
419
|
-
];
|
|
420
|
-
for (const conf of replicas) {
|
|
421
|
-
const replicaConfig = Utils.copy(conf);
|
|
422
|
-
for (const prop of props) {
|
|
423
|
-
if (conf[prop]) {
|
|
424
|
-
continue;
|
|
425
|
-
}
|
|
426
|
-
// do not copy options that can be inferred from explicitly provided `clientUrl`
|
|
427
|
-
if (conf.clientUrl && ['clientUrl', 'host', 'port', 'user', 'password'].includes(prop)) {
|
|
428
|
-
continue;
|
|
429
|
-
}
|
|
430
|
-
if (conf.clientUrl && prop === 'dbName' && new URL(conf.clientUrl).pathname) {
|
|
431
|
-
continue;
|
|
432
|
-
}
|
|
433
|
-
replicaConfig[prop] = this.config.get(prop);
|
|
434
|
-
}
|
|
435
|
-
ret.push(cb(replicaConfig));
|
|
402
|
+
if (!unknownProp) {
|
|
403
|
+
delete data[prop.name];
|
|
436
404
|
}
|
|
437
|
-
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
getPrimaryKeyFields(meta) {
|
|
409
|
+
return meta.getPrimaryProps().flatMap(pk => pk.fieldNames);
|
|
410
|
+
}
|
|
411
|
+
createReplicas(cb) {
|
|
412
|
+
const replicas = this.config.get('replicas', []);
|
|
413
|
+
const ret = [];
|
|
414
|
+
const props = [
|
|
415
|
+
'dbName',
|
|
416
|
+
'clientUrl',
|
|
417
|
+
'host',
|
|
418
|
+
'port',
|
|
419
|
+
'user',
|
|
420
|
+
'password',
|
|
421
|
+
'multipleStatements',
|
|
422
|
+
'pool',
|
|
423
|
+
'name',
|
|
424
|
+
'driverOptions',
|
|
425
|
+
];
|
|
426
|
+
for (const conf of replicas) {
|
|
427
|
+
const replicaConfig = Utils.copy(conf);
|
|
428
|
+
for (const prop of props) {
|
|
429
|
+
if (conf[prop]) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
// do not copy options that can be inferred from explicitly provided `clientUrl`
|
|
433
|
+
if (conf.clientUrl && ['clientUrl', 'host', 'port', 'user', 'password'].includes(prop)) {
|
|
434
|
+
continue;
|
|
449
435
|
}
|
|
450
|
-
|
|
436
|
+
if (conf.clientUrl && prop === 'dbName' && new URL(conf.clientUrl).pathname) {
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
replicaConfig[prop] = this.config.get(prop);
|
|
440
|
+
}
|
|
441
|
+
ret.push(cb(replicaConfig));
|
|
451
442
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
443
|
+
return ret;
|
|
444
|
+
}
|
|
445
|
+
/** Acquires a pessimistic lock on the given entity. */
|
|
446
|
+
async lockPessimistic(entity, options) {
|
|
447
|
+
throw new Error(`Pessimistic locks are not supported by ${this.constructor.name} driver`);
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* @inheritDoc
|
|
451
|
+
*/
|
|
452
|
+
convertException(exception) {
|
|
453
|
+
if (exception instanceof DriverException) {
|
|
454
|
+
return exception;
|
|
456
455
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
456
|
+
return this.platform.getExceptionConverter().convertException(exception);
|
|
457
|
+
}
|
|
458
|
+
rethrow(promise) {
|
|
459
|
+
return promise.catch(e => {
|
|
460
|
+
throw this.convertException(e);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* @internal
|
|
465
|
+
*/
|
|
466
|
+
getTableName(meta, options, quote = true) {
|
|
467
|
+
const schema = this.getSchemaName(meta, options);
|
|
468
|
+
const tableName =
|
|
469
|
+
schema && schema !== this.platform.getDefaultSchemaName() ? `${schema}.${meta.tableName}` : meta.tableName;
|
|
470
|
+
if (quote) {
|
|
471
|
+
return this.platform.quoteIdentifier(tableName);
|
|
467
472
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return this.config.get('schema');
|
|
477
|
-
}
|
|
478
|
-
const schemaName = meta?.schema === '*' ? this.config.getSchema() : meta?.schema;
|
|
479
|
-
return options?.schema ?? options?.parentSchema ?? schemaName ?? this.config.getSchema();
|
|
473
|
+
return tableName;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* @internal
|
|
477
|
+
*/
|
|
478
|
+
getSchemaName(meta, options) {
|
|
479
|
+
if (meta?.schema && meta.schema !== '*') {
|
|
480
|
+
return meta.schema;
|
|
480
481
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
return MikroORM;
|
|
482
|
+
if (options?.schema === '*') {
|
|
483
|
+
return this.config.get('schema');
|
|
484
484
|
}
|
|
485
|
+
const schemaName = meta?.schema === '*' ? this.config.getSchema() : meta?.schema;
|
|
486
|
+
return options?.schema ?? options?.parentSchema ?? schemaName ?? this.config.getSchema();
|
|
487
|
+
}
|
|
488
|
+
/** @internal */
|
|
489
|
+
getORMClass() {
|
|
490
|
+
return MikroORM;
|
|
491
|
+
}
|
|
485
492
|
}
|