@mikro-orm/core 7.0.0-dev.12 → 7.0.0-dev.120
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 +85 -56
- package/EntityManager.js +332 -293
- package/MikroORM.d.ts +41 -32
- package/MikroORM.js +100 -140
- package/README.md +3 -2
- package/cache/FileCacheAdapter.d.ts +1 -1
- package/cache/FileCacheAdapter.js +8 -7
- package/cache/GeneratedCacheAdapter.d.ts +0 -1
- package/cache/GeneratedCacheAdapter.js +0 -2
- package/cache/index.d.ts +0 -1
- package/cache/index.js +0 -1
- package/connections/Connection.d.ts +16 -7
- package/connections/Connection.js +23 -14
- package/drivers/DatabaseDriver.d.ts +25 -16
- package/drivers/DatabaseDriver.js +35 -19
- package/drivers/IDatabaseDriver.d.ts +38 -17
- package/entity/BaseEntity.d.ts +0 -1
- package/entity/BaseEntity.js +0 -3
- package/entity/Collection.d.ts +95 -30
- package/entity/Collection.js +439 -99
- package/entity/EntityAssigner.d.ts +1 -1
- package/entity/EntityAssigner.js +26 -18
- package/entity/EntityFactory.d.ts +7 -0
- package/entity/EntityFactory.js +72 -53
- package/entity/EntityHelper.d.ts +2 -2
- package/entity/EntityHelper.js +30 -15
- package/entity/EntityLoader.d.ts +7 -6
- package/entity/EntityLoader.js +84 -72
- package/entity/EntityRepository.d.ts +1 -1
- package/entity/EntityRepository.js +2 -2
- package/entity/Reference.d.ts +6 -5
- package/entity/Reference.js +34 -9
- package/entity/WrappedEntity.d.ts +2 -7
- package/entity/WrappedEntity.js +3 -8
- package/entity/defineEntity.d.ts +568 -0
- package/entity/defineEntity.js +529 -0
- package/entity/index.d.ts +3 -2
- package/entity/index.js +3 -2
- package/entity/utils.d.ts +7 -0
- package/entity/utils.js +16 -4
- package/entity/validators.d.ts +11 -0
- package/entity/validators.js +65 -0
- package/enums.d.ts +21 -6
- package/enums.js +14 -1
- package/errors.d.ts +17 -9
- package/errors.js +41 -21
- package/events/EventManager.d.ts +2 -1
- package/events/EventManager.js +19 -11
- package/hydration/Hydrator.js +1 -2
- package/hydration/ObjectHydrator.d.ts +4 -4
- package/hydration/ObjectHydrator.js +50 -33
- package/index.d.ts +2 -2
- package/index.js +1 -2
- package/logging/DefaultLogger.d.ts +1 -1
- package/logging/DefaultLogger.js +1 -0
- package/logging/SimpleLogger.d.ts +1 -1
- package/logging/colors.d.ts +1 -1
- package/logging/colors.js +7 -6
- package/logging/index.d.ts +1 -0
- package/logging/index.js +1 -0
- package/logging/inspect.d.ts +2 -0
- package/logging/inspect.js +11 -0
- package/metadata/EntitySchema.d.ts +13 -17
- package/metadata/EntitySchema.js +67 -51
- package/metadata/MetadataDiscovery.d.ts +6 -10
- package/metadata/MetadataDiscovery.js +289 -298
- package/metadata/MetadataProvider.d.ts +11 -2
- package/metadata/MetadataProvider.js +46 -2
- package/metadata/MetadataStorage.d.ts +13 -11
- package/metadata/MetadataStorage.js +70 -37
- package/metadata/MetadataValidator.d.ts +2 -9
- package/metadata/MetadataValidator.js +22 -38
- package/metadata/discover-entities.d.ts +5 -0
- package/metadata/discover-entities.js +40 -0
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +1 -1
- package/metadata/types.d.ts +480 -0
- package/metadata/types.js +1 -0
- package/naming-strategy/AbstractNamingStrategy.d.ts +8 -4
- package/naming-strategy/AbstractNamingStrategy.js +8 -2
- package/naming-strategy/EntityCaseNamingStrategy.d.ts +3 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +6 -5
- package/naming-strategy/MongoNamingStrategy.d.ts +3 -3
- package/naming-strategy/MongoNamingStrategy.js +6 -6
- package/naming-strategy/NamingStrategy.d.ts +14 -4
- package/naming-strategy/UnderscoreNamingStrategy.d.ts +3 -3
- package/naming-strategy/UnderscoreNamingStrategy.js +6 -6
- package/not-supported.d.ts +2 -0
- package/not-supported.js +4 -0
- package/package.json +19 -11
- package/platforms/ExceptionConverter.js +1 -1
- package/platforms/Platform.d.ts +6 -13
- package/platforms/Platform.js +17 -43
- package/serialization/EntitySerializer.d.ts +5 -0
- package/serialization/EntitySerializer.js +47 -27
- package/serialization/EntityTransformer.js +28 -18
- package/serialization/SerializationContext.d.ts +6 -6
- package/serialization/SerializationContext.js +16 -13
- package/types/ArrayType.d.ts +1 -1
- package/types/ArrayType.js +2 -3
- package/types/BigIntType.d.ts +8 -6
- package/types/BigIntType.js +1 -1
- package/types/BlobType.d.ts +0 -1
- package/types/BlobType.js +0 -3
- package/types/BooleanType.d.ts +2 -1
- package/types/BooleanType.js +3 -0
- package/types/DecimalType.d.ts +6 -4
- package/types/DecimalType.js +3 -3
- package/types/DoubleType.js +2 -2
- package/types/EnumArrayType.js +1 -2
- package/types/JsonType.d.ts +1 -1
- package/types/JsonType.js +7 -2
- package/types/TinyIntType.js +1 -1
- package/types/Type.d.ts +2 -4
- package/types/Type.js +3 -3
- package/types/Uint8ArrayType.d.ts +0 -1
- package/types/Uint8ArrayType.js +1 -4
- package/types/index.d.ts +1 -1
- package/typings.d.ts +124 -86
- package/typings.js +50 -42
- package/unit-of-work/ChangeSet.d.ts +2 -6
- package/unit-of-work/ChangeSet.js +4 -5
- package/unit-of-work/ChangeSetComputer.d.ts +1 -3
- package/unit-of-work/ChangeSetComputer.js +14 -12
- package/unit-of-work/ChangeSetPersister.d.ts +5 -4
- package/unit-of-work/ChangeSetPersister.js +65 -33
- package/unit-of-work/CommitOrderCalculator.d.ts +12 -10
- package/unit-of-work/CommitOrderCalculator.js +13 -13
- package/unit-of-work/UnitOfWork.d.ts +10 -3
- package/unit-of-work/UnitOfWork.js +139 -96
- package/utils/AbstractSchemaGenerator.d.ts +5 -5
- package/utils/AbstractSchemaGenerator.js +18 -16
- package/utils/AsyncContext.d.ts +6 -0
- package/utils/AsyncContext.js +42 -0
- package/utils/Configuration.d.ts +753 -207
- package/utils/Configuration.js +145 -190
- package/utils/ConfigurationLoader.d.ts +1 -54
- package/utils/ConfigurationLoader.js +1 -352
- package/utils/Cursor.d.ts +0 -3
- package/utils/Cursor.js +9 -6
- package/utils/DataloaderUtils.d.ts +15 -5
- package/utils/DataloaderUtils.js +65 -17
- package/utils/EntityComparator.d.ts +13 -9
- package/utils/EntityComparator.js +85 -43
- package/utils/QueryHelper.d.ts +14 -6
- package/utils/QueryHelper.js +87 -25
- package/utils/RawQueryFragment.d.ts +48 -25
- package/utils/RawQueryFragment.js +66 -70
- package/utils/RequestContext.js +2 -2
- package/utils/TransactionContext.js +2 -2
- package/utils/TransactionManager.d.ts +65 -0
- package/utils/TransactionManager.js +223 -0
- package/utils/Utils.d.ts +12 -119
- package/utils/Utils.js +97 -373
- package/utils/clone.js +8 -23
- package/utils/env-vars.d.ts +7 -0
- package/utils/env-vars.js +97 -0
- package/utils/fs-utils.d.ts +32 -0
- package/utils/fs-utils.js +178 -0
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/upsert-utils.d.ts +9 -4
- package/utils/upsert-utils.js +55 -4
- package/decorators/Check.d.ts +0 -3
- package/decorators/Check.js +0 -13
- package/decorators/CreateRequestContext.d.ts +0 -3
- package/decorators/CreateRequestContext.js +0 -32
- package/decorators/Embeddable.d.ts +0 -8
- package/decorators/Embeddable.js +0 -11
- package/decorators/Embedded.d.ts +0 -18
- package/decorators/Embedded.js +0 -18
- package/decorators/Entity.d.ts +0 -18
- package/decorators/Entity.js +0 -12
- package/decorators/Enum.d.ts +0 -9
- package/decorators/Enum.js +0 -16
- package/decorators/Filter.d.ts +0 -2
- package/decorators/Filter.js +0 -8
- package/decorators/Formula.d.ts +0 -4
- package/decorators/Formula.js +0 -15
- package/decorators/Indexed.d.ts +0 -19
- package/decorators/Indexed.js +0 -20
- package/decorators/ManyToMany.d.ts +0 -40
- package/decorators/ManyToMany.js +0 -14
- package/decorators/ManyToOne.d.ts +0 -30
- package/decorators/ManyToOne.js +0 -14
- package/decorators/OneToMany.d.ts +0 -28
- package/decorators/OneToMany.js +0 -17
- package/decorators/OneToOne.d.ts +0 -24
- package/decorators/OneToOne.js +0 -7
- package/decorators/PrimaryKey.d.ts +0 -8
- package/decorators/PrimaryKey.js +0 -20
- package/decorators/Property.d.ts +0 -250
- package/decorators/Property.js +0 -32
- package/decorators/Transactional.d.ts +0 -13
- package/decorators/Transactional.js +0 -28
- package/decorators/hooks.d.ts +0 -16
- package/decorators/hooks.js +0 -47
- package/decorators/index.d.ts +0 -17
- package/decorators/index.js +0 -17
- package/entity/ArrayCollection.d.ts +0 -116
- package/entity/ArrayCollection.js +0 -402
- package/entity/EntityValidator.d.ts +0 -19
- package/entity/EntityValidator.js +0 -150
- package/metadata/ReflectMetadataProvider.d.ts +0 -8
- package/metadata/ReflectMetadataProvider.js +0 -44
- package/utils/resolveContextProvider.d.ts +0 -10
- package/utils/resolveContextProvider.js +0 -28
|
@@ -1,352 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { realpathSync } from 'node:fs';
|
|
3
|
-
import { platform } from 'node:os';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { colors } from '../logging/colors.js';
|
|
6
|
-
import { Configuration } from './Configuration.js';
|
|
7
|
-
import { Utils } from './Utils.js';
|
|
8
|
-
/**
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
export class ConfigurationLoader {
|
|
12
|
-
static async getConfiguration(contextName = 'default', paths = ConfigurationLoader.getConfigPaths(), options = {}) {
|
|
13
|
-
// Backwards compatibility layer
|
|
14
|
-
if (typeof contextName === 'boolean' || !Array.isArray(paths)) {
|
|
15
|
-
this.commonJSCompat(options);
|
|
16
|
-
this.registerDotenv(options);
|
|
17
|
-
const configPathFromArg = ConfigurationLoader.configPathsFromArg();
|
|
18
|
-
const configPaths = configPathFromArg ?? (Array.isArray(paths) ? paths : ConfigurationLoader.getConfigPaths());
|
|
19
|
-
const config = contextName
|
|
20
|
-
? (await ConfigurationLoader.getConfiguration(process.env.MIKRO_ORM_CONTEXT_NAME ?? 'default', configPaths, Array.isArray(paths) ? {} : paths))
|
|
21
|
-
: await (async () => {
|
|
22
|
-
const env = await this.loadEnvironmentVars();
|
|
23
|
-
const [path, tmp] = await this.getConfigFile(configPaths);
|
|
24
|
-
if (!path) {
|
|
25
|
-
if (Utils.hasObjectKeys(env)) {
|
|
26
|
-
return new Configuration(Utils.mergeConfig({}, options, env), false);
|
|
27
|
-
}
|
|
28
|
-
throw new Error(`MikroORM config file not found in ['${configPaths.join(`', '`)}']`);
|
|
29
|
-
}
|
|
30
|
-
return new Configuration(Utils.mergeConfig(tmp, options, env), false);
|
|
31
|
-
})();
|
|
32
|
-
if (configPathFromArg) {
|
|
33
|
-
config.getLogger().warn('deprecated', 'Path for config file was inferred from the command line arguments. Instead, you should set the MIKRO_ORM_CLI_CONFIG environment variable to specify the path, or if you really must use the command line arguments, import the config manually based on them, and pass it to init.', { label: 'D0001' });
|
|
34
|
-
}
|
|
35
|
-
return config;
|
|
36
|
-
}
|
|
37
|
-
const env = await this.loadEnvironmentVars();
|
|
38
|
-
const configFinder = (cfg) => {
|
|
39
|
-
return typeof cfg === 'object' && cfg !== null && ('contextName' in cfg ? cfg.contextName === contextName : (contextName === 'default'));
|
|
40
|
-
};
|
|
41
|
-
const isValidConfigFactoryResult = (cfg) => {
|
|
42
|
-
return typeof cfg === 'object' && cfg !== null && (!('contextName' in cfg) || cfg.contextName === contextName);
|
|
43
|
-
};
|
|
44
|
-
const result = await this.getConfigFile(paths);
|
|
45
|
-
if (!result[0]) {
|
|
46
|
-
if (Utils.hasObjectKeys(env)) {
|
|
47
|
-
return new Configuration(Utils.mergeConfig({ contextName }, options, env));
|
|
48
|
-
}
|
|
49
|
-
throw new Error(`MikroORM config file not found in ['${paths.join(`', '`)}']`);
|
|
50
|
-
}
|
|
51
|
-
const path = result[0];
|
|
52
|
-
let tmp = result[1];
|
|
53
|
-
if (Array.isArray(tmp)) {
|
|
54
|
-
const tmpFirstIndex = tmp.findIndex(configFinder);
|
|
55
|
-
if (tmpFirstIndex === -1) {
|
|
56
|
-
// Static config not found. Try factory functions
|
|
57
|
-
let configCandidate;
|
|
58
|
-
for (let i = 0, l = tmp.length; i < l; ++i) {
|
|
59
|
-
const f = tmp[i];
|
|
60
|
-
if (typeof f !== 'function') {
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
configCandidate = await f(contextName);
|
|
64
|
-
if (!isValidConfigFactoryResult(configCandidate)) {
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
tmp = configCandidate;
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
if (Array.isArray(tmp)) {
|
|
71
|
-
throw new Error(`MikroORM config '${contextName}' was not found within the config file '${path}'. Either add a config with this name to the array, or add a function that when given this name will return a configuration object without a name, or with name set to this name.`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
const tmpLastIndex = tmp.findLastIndex(configFinder);
|
|
76
|
-
if (tmpLastIndex !== tmpFirstIndex) {
|
|
77
|
-
throw new Error(`MikroORM config '${contextName}' is not unique within the array exported by '${path}' (first occurrence index: ${tmpFirstIndex}; last occurrence index: ${tmpLastIndex})`);
|
|
78
|
-
}
|
|
79
|
-
tmp = tmp[tmpFirstIndex];
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
if (tmp instanceof Function) {
|
|
84
|
-
tmp = await tmp(contextName);
|
|
85
|
-
if (!isValidConfigFactoryResult(tmp)) {
|
|
86
|
-
throw new Error(`MikroORM config '${contextName}' was not what the function exported from '${path}' provided. Ensure it returns a config object with no name, or name matching the requested one.`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
if (!configFinder(tmp)) {
|
|
91
|
-
throw new Error(`MikroORM config '${contextName}' was not what the default export from '${path}' provided.`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
const esmConfigOptions = this.isESM() ? { entityGenerator: { esmImport: true } } : {};
|
|
96
|
-
return new Configuration(Utils.mergeConfig({}, esmConfigOptions, tmp, options, env));
|
|
97
|
-
}
|
|
98
|
-
static async getConfigFile(paths) {
|
|
99
|
-
for (let path of paths) {
|
|
100
|
-
path = Utils.absolutePath(path);
|
|
101
|
-
path = Utils.normalizePath(path);
|
|
102
|
-
if (Utils.pathExistsSync(path)) {
|
|
103
|
-
const config = await Utils.dynamicImport(path);
|
|
104
|
-
/* v8 ignore next */
|
|
105
|
-
return [path, await (config.default ?? config)];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return [];
|
|
109
|
-
}
|
|
110
|
-
static getPackageConfig(basePath = process.cwd()) {
|
|
111
|
-
if (Utils.pathExistsSync(`${basePath}/package.json`)) {
|
|
112
|
-
/* v8 ignore next 5 */
|
|
113
|
-
try {
|
|
114
|
-
return Utils.readJSONSync(`${basePath}/package.json`);
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
return {};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const parentFolder = realpathSync(`${basePath}/..`);
|
|
121
|
-
// we reached the root folder
|
|
122
|
-
if (basePath === parentFolder) {
|
|
123
|
-
return {};
|
|
124
|
-
}
|
|
125
|
-
return this.getPackageConfig(parentFolder);
|
|
126
|
-
}
|
|
127
|
-
static getSettings() {
|
|
128
|
-
const config = ConfigurationLoader.getPackageConfig();
|
|
129
|
-
const settings = { ...config['mikro-orm'] };
|
|
130
|
-
const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
|
|
131
|
-
settings.preferTs = process.env.MIKRO_ORM_CLI_PREFER_TS != null ? bool(process.env.MIKRO_ORM_CLI_PREFER_TS) : settings.preferTs;
|
|
132
|
-
settings.tsConfigPath = process.env.MIKRO_ORM_CLI_TS_CONFIG_PATH ?? settings.tsConfigPath;
|
|
133
|
-
settings.alwaysAllowTs = process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS != null ? bool(process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS) : settings.alwaysAllowTs;
|
|
134
|
-
settings.verbose = process.env.MIKRO_ORM_CLI_VERBOSE != null ? bool(process.env.MIKRO_ORM_CLI_VERBOSE) : settings.verbose;
|
|
135
|
-
if (process.env.MIKRO_ORM_CLI_CONFIG?.endsWith('.ts')) {
|
|
136
|
-
settings.preferTs = true;
|
|
137
|
-
}
|
|
138
|
-
return settings;
|
|
139
|
-
}
|
|
140
|
-
static configPathsFromArg() {
|
|
141
|
-
const options = Utils.parseArgs();
|
|
142
|
-
const configArgName = process.env.MIKRO_ORM_CONFIG_ARG_NAME ?? 'config';
|
|
143
|
-
if (options[configArgName]) {
|
|
144
|
-
return [options[configArgName]];
|
|
145
|
-
}
|
|
146
|
-
return undefined;
|
|
147
|
-
}
|
|
148
|
-
static getConfigPaths() {
|
|
149
|
-
const paths = [];
|
|
150
|
-
const settings = ConfigurationLoader.getSettings();
|
|
151
|
-
if (process.env.MIKRO_ORM_CLI_CONFIG) {
|
|
152
|
-
paths.push(process.env.MIKRO_ORM_CLI_CONFIG);
|
|
153
|
-
}
|
|
154
|
-
paths.push(...(settings.configPaths || []));
|
|
155
|
-
const alwaysAllowTs = settings.alwaysAllowTs ?? process.versions.bun;
|
|
156
|
-
if (settings.preferTs !== false || alwaysAllowTs) {
|
|
157
|
-
paths.push('./src/mikro-orm.config.ts');
|
|
158
|
-
paths.push('./mikro-orm.config.ts');
|
|
159
|
-
}
|
|
160
|
-
const distDir = Utils.pathExistsSync(process.cwd() + '/dist');
|
|
161
|
-
const buildDir = Utils.pathExistsSync(process.cwd() + '/build');
|
|
162
|
-
/* v8 ignore next */
|
|
163
|
-
const path = distDir ? 'dist' : (buildDir ? 'build' : 'src');
|
|
164
|
-
paths.push(`./${path}/mikro-orm.config.js`);
|
|
165
|
-
paths.push('./mikro-orm.config.js');
|
|
166
|
-
const typeScriptSupport = Utils.detectTypeScriptSupport();
|
|
167
|
-
/* v8 ignore next */
|
|
168
|
-
return Utils.unique(paths).filter(p => p.endsWith('.js') || typeScriptSupport || alwaysAllowTs);
|
|
169
|
-
}
|
|
170
|
-
static isESM() {
|
|
171
|
-
const config = ConfigurationLoader.getPackageConfig();
|
|
172
|
-
const type = config?.type ?? '';
|
|
173
|
-
return type === 'module';
|
|
174
|
-
}
|
|
175
|
-
static async registerTypeScriptSupport(configPath = 'tsconfig.json') {
|
|
176
|
-
/* v8 ignore next 3 */
|
|
177
|
-
if (process.versions.bun) {
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
process.env.SWC_NODE_PROJECT ??= configPath;
|
|
181
|
-
process.env.MIKRO_ORM_CLI_ALWAYS_ALLOW_TS ??= '1';
|
|
182
|
-
const esm = this.isESM();
|
|
183
|
-
/* v8 ignore next 2 */
|
|
184
|
-
const importMethod = esm ? 'tryImport' : 'tryRequire';
|
|
185
|
-
const module = esm ? '@swc-node/register/esm-register' : '@swc-node/register';
|
|
186
|
-
const supported = await Utils[importMethod]({
|
|
187
|
-
module,
|
|
188
|
-
warning: '@swc-node/register and @swc/core are not installed, support for working with TypeScript files might not work',
|
|
189
|
-
});
|
|
190
|
-
return !!supported;
|
|
191
|
-
}
|
|
192
|
-
static registerDotenv(options) {
|
|
193
|
-
const path = process.env.MIKRO_ORM_ENV ?? ((options?.baseDir ?? process.cwd()) + '/.env');
|
|
194
|
-
const env = {};
|
|
195
|
-
dotenv.config({ path, processEnv: env });
|
|
196
|
-
// only propagate known env vars
|
|
197
|
-
for (const key of Object.keys(env)) {
|
|
198
|
-
if (key.startsWith('MIKRO_ORM_')) {
|
|
199
|
-
process.env[key] ??= env[key]; // respect user provided values
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
static async loadEnvironmentVars() {
|
|
204
|
-
const ret = this.loadEnvironmentVarsSync();
|
|
205
|
-
// only to keep some sort of back compatibility with those using env vars only, to support `MIKRO_ORM_TYPE`
|
|
206
|
-
const PLATFORMS = {
|
|
207
|
-
mongo: { className: 'MongoDriver', module: '@mikro-orm/mongodb' },
|
|
208
|
-
mysql: { className: 'MySqlDriver', module: '@mikro-orm/mysql' },
|
|
209
|
-
mssql: { className: 'MsSqlDriver', module: '@mikro-orm/mssql' },
|
|
210
|
-
mariadb: { className: 'MariaDbDriver', module: '@mikro-orm/mariadb' },
|
|
211
|
-
postgresql: { className: 'PostgreSqlDriver', module: '@mikro-orm/postgresql' },
|
|
212
|
-
sqlite: { className: 'SqliteDriver', module: '@mikro-orm/sqlite' },
|
|
213
|
-
libsql: { className: 'LibSqlDriver', module: '@mikro-orm/libsql' },
|
|
214
|
-
};
|
|
215
|
-
if (process.env.MIKRO_ORM_TYPE) {
|
|
216
|
-
const val = process.env.MIKRO_ORM_TYPE;
|
|
217
|
-
const driver = await import(PLATFORMS[val].module);
|
|
218
|
-
ret.driver = driver[PLATFORMS[val].className];
|
|
219
|
-
}
|
|
220
|
-
return ret;
|
|
221
|
-
}
|
|
222
|
-
static loadEnvironmentVarsSync() {
|
|
223
|
-
const ret = {};
|
|
224
|
-
const array = (v) => v.split(',').map(vv => vv.trim());
|
|
225
|
-
const bool = (v) => ['true', 't', '1'].includes(v.toLowerCase());
|
|
226
|
-
const num = (v) => +v;
|
|
227
|
-
const read = (o, envKey, key, mapper = v => v) => {
|
|
228
|
-
if (!(envKey in process.env)) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
const val = process.env[envKey];
|
|
232
|
-
o[key] = mapper(val);
|
|
233
|
-
};
|
|
234
|
-
const cleanup = (o, k) => Utils.hasObjectKeys(o[k]) ? {} : delete o[k];
|
|
235
|
-
read(ret, 'MIKRO_ORM_BASE_DIR', 'baseDir');
|
|
236
|
-
read(ret, 'MIKRO_ORM_ENTITIES', 'entities', array);
|
|
237
|
-
read(ret, 'MIKRO_ORM_ENTITIES_TS', 'entitiesTs', array);
|
|
238
|
-
read(ret, 'MIKRO_ORM_CLIENT_URL', 'clientUrl');
|
|
239
|
-
read(ret, 'MIKRO_ORM_HOST', 'host');
|
|
240
|
-
read(ret, 'MIKRO_ORM_PORT', 'port', num);
|
|
241
|
-
read(ret, 'MIKRO_ORM_USER', 'user');
|
|
242
|
-
read(ret, 'MIKRO_ORM_PASSWORD', 'password');
|
|
243
|
-
read(ret, 'MIKRO_ORM_DB_NAME', 'dbName');
|
|
244
|
-
read(ret, 'MIKRO_ORM_SCHEMA', 'schema');
|
|
245
|
-
read(ret, 'MIKRO_ORM_LOAD_STRATEGY', 'loadStrategy');
|
|
246
|
-
read(ret, 'MIKRO_ORM_BATCH_SIZE', 'batchSize', num);
|
|
247
|
-
read(ret, 'MIKRO_ORM_USE_BATCH_INSERTS', 'useBatchInserts', bool);
|
|
248
|
-
read(ret, 'MIKRO_ORM_USE_BATCH_UPDATES', 'useBatchUpdates', bool);
|
|
249
|
-
read(ret, 'MIKRO_ORM_STRICT', 'strict', bool);
|
|
250
|
-
read(ret, 'MIKRO_ORM_VALIDATE', 'validate', bool);
|
|
251
|
-
read(ret, 'MIKRO_ORM_ALLOW_GLOBAL_CONTEXT', 'allowGlobalContext', bool);
|
|
252
|
-
read(ret, 'MIKRO_ORM_AUTO_JOIN_ONE_TO_ONE_OWNER', 'autoJoinOneToOneOwner', bool);
|
|
253
|
-
read(ret, 'MIKRO_ORM_POPULATE_AFTER_FLUSH', 'populateAfterFlush', bool);
|
|
254
|
-
read(ret, 'MIKRO_ORM_FORCE_ENTITY_CONSTRUCTOR', 'forceEntityConstructor', bool);
|
|
255
|
-
read(ret, 'MIKRO_ORM_FORCE_UNDEFINED', 'forceUndefined', bool);
|
|
256
|
-
read(ret, 'MIKRO_ORM_FORCE_UTC_TIMEZONE', 'forceUtcTimezone', bool);
|
|
257
|
-
read(ret, 'MIKRO_ORM_TIMEZONE', 'timezone');
|
|
258
|
-
read(ret, 'MIKRO_ORM_ENSURE_INDEXES', 'ensureIndexes', bool);
|
|
259
|
-
read(ret, 'MIKRO_ORM_IMPLICIT_TRANSACTIONS', 'implicitTransactions', bool);
|
|
260
|
-
read(ret, 'MIKRO_ORM_DEBUG', 'debug', bool);
|
|
261
|
-
read(ret, 'MIKRO_ORM_COLORS', 'colors', bool);
|
|
262
|
-
ret.discovery = {};
|
|
263
|
-
read(ret.discovery, 'MIKRO_ORM_DISCOVERY_WARN_WHEN_NO_ENTITIES', 'warnWhenNoEntities', bool);
|
|
264
|
-
read(ret.discovery, 'MIKRO_ORM_DISCOVERY_REQUIRE_ENTITIES_ARRAY', 'requireEntitiesArray', bool);
|
|
265
|
-
read(ret.discovery, 'MIKRO_ORM_DISCOVERY_ALWAYS_ANALYSE_PROPERTIES', 'alwaysAnalyseProperties', bool);
|
|
266
|
-
read(ret.discovery, 'MIKRO_ORM_DISCOVERY_DISABLE_DYNAMIC_FILE_ACCESS', 'disableDynamicFileAccess', bool);
|
|
267
|
-
cleanup(ret, 'discovery');
|
|
268
|
-
ret.migrations = {};
|
|
269
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_TABLE_NAME', 'tableName');
|
|
270
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_PATH', 'path');
|
|
271
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_PATH_TS', 'pathTs');
|
|
272
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_GLOB', 'glob');
|
|
273
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_TRANSACTIONAL', 'transactional', bool);
|
|
274
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_DISABLE_FOREIGN_KEYS', 'disableForeignKeys', bool);
|
|
275
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_ALL_OR_NOTHING', 'allOrNothing', bool);
|
|
276
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_DROP_TABLES', 'dropTables', bool);
|
|
277
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_SAFE', 'safe', bool);
|
|
278
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_SILENT', 'silent', bool);
|
|
279
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_EMIT', 'emit');
|
|
280
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_SNAPSHOT', 'snapshot', bool);
|
|
281
|
-
read(ret.migrations, 'MIKRO_ORM_MIGRATIONS_SNAPSHOT_NAME', 'snapshotName');
|
|
282
|
-
cleanup(ret, 'migrations');
|
|
283
|
-
ret.schemaGenerator = {};
|
|
284
|
-
read(ret.schemaGenerator, 'MIKRO_ORM_SCHEMA_GENERATOR_DISABLE_FOREIGN_KEYS', 'disableForeignKeys', bool);
|
|
285
|
-
read(ret.schemaGenerator, 'MIKRO_ORM_SCHEMA_GENERATOR_CREATE_FOREIGN_KEY_CONSTRAINTS', 'createForeignKeyConstraints', bool);
|
|
286
|
-
cleanup(ret, 'schemaGenerator');
|
|
287
|
-
ret.seeder = {};
|
|
288
|
-
read(ret.seeder, 'MIKRO_ORM_SEEDER_PATH', 'path');
|
|
289
|
-
read(ret.seeder, 'MIKRO_ORM_SEEDER_PATH_TS', 'pathTs');
|
|
290
|
-
read(ret.seeder, 'MIKRO_ORM_SEEDER_GLOB', 'glob');
|
|
291
|
-
read(ret.seeder, 'MIKRO_ORM_SEEDER_EMIT', 'emit');
|
|
292
|
-
read(ret.seeder, 'MIKRO_ORM_SEEDER_DEFAULT_SEEDER', 'defaultSeeder');
|
|
293
|
-
cleanup(ret, 'seeder');
|
|
294
|
-
return ret;
|
|
295
|
-
}
|
|
296
|
-
static getORMPackages() {
|
|
297
|
-
const pkg = this.getPackageConfig();
|
|
298
|
-
return new Set([
|
|
299
|
-
...Object.keys(pkg.dependencies ?? {}),
|
|
300
|
-
...Object.keys(pkg.devDependencies ?? {}),
|
|
301
|
-
]);
|
|
302
|
-
}
|
|
303
|
-
/** @internal */
|
|
304
|
-
static commonJSCompat(options) {
|
|
305
|
-
if (this.isESM()) {
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
/* v8 ignore next 11 */
|
|
309
|
-
options.dynamicImportProvider ??= id => {
|
|
310
|
-
if (platform() === 'win32') {
|
|
311
|
-
try {
|
|
312
|
-
id = fileURLToPath(id);
|
|
313
|
-
}
|
|
314
|
-
catch {
|
|
315
|
-
// ignore
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return Utils.requireFrom(id);
|
|
319
|
-
};
|
|
320
|
-
Utils.setDynamicImportProvider(options.dynamicImportProvider);
|
|
321
|
-
}
|
|
322
|
-
static getORMPackageVersion(name) {
|
|
323
|
-
try {
|
|
324
|
-
const pkg = Utils.requireFrom(`${name}/package.json`);
|
|
325
|
-
/* v8 ignore next */
|
|
326
|
-
return pkg?.version;
|
|
327
|
-
}
|
|
328
|
-
catch (e) {
|
|
329
|
-
return undefined;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
// inspired by https://github.com/facebook/docusaurus/pull/3386
|
|
333
|
-
static checkPackageVersion() {
|
|
334
|
-
const coreVersion = Utils.getORMVersion();
|
|
335
|
-
if (process.env.MIKRO_ORM_ALLOW_VERSION_MISMATCH) {
|
|
336
|
-
return coreVersion;
|
|
337
|
-
}
|
|
338
|
-
const deps = this.getORMPackages();
|
|
339
|
-
const exceptions = new Set(['nestjs', 'sql-highlighter', 'mongo-highlighter']);
|
|
340
|
-
const ormPackages = [...deps].filter(d => d.startsWith('@mikro-orm/') && d !== '@mikro-orm/core' && !exceptions.has(d.substring('@mikro-orm/'.length)));
|
|
341
|
-
for (const ormPackage of ormPackages) {
|
|
342
|
-
const version = this.getORMPackageVersion(ormPackage);
|
|
343
|
-
if (version != null && version !== coreVersion) {
|
|
344
|
-
throw new Error(`Bad ${colors.cyan(ormPackage)} version ${colors.yellow('' + version)}.\n` +
|
|
345
|
-
`All official @mikro-orm/* packages need to have the exact same version as @mikro-orm/core (${colors.green(coreVersion)}).\n` +
|
|
346
|
-
`Only exceptions are packages that don't live in the 'mikro-orm' repository: ${[...exceptions].join(', ')}.\n` +
|
|
347
|
-
`Maybe you want to check, or regenerate your yarn.lock or package-lock.json file?`);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
return coreVersion;
|
|
351
|
-
}
|
|
352
|
-
}
|
|
1
|
+
export {};
|
package/utils/Cursor.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import type { EntityMetadata, FilterObject, Loaded } from '../typings.js';
|
|
3
2
|
import type { FindByCursorOptions, OrderDefinition } from '../drivers/IDatabaseDriver.js';
|
|
4
3
|
import { type QueryOrder } from '../enums.js';
|
|
@@ -71,6 +70,4 @@ export declare class Cursor<Entity extends object, Hint extends string = never,
|
|
|
71
70
|
static encode(value: unknown[]): string;
|
|
72
71
|
static decode(value: string): unknown[];
|
|
73
72
|
static getDefinition<Entity extends object>(meta: EntityMetadata<Entity>, orderBy: OrderDefinition<Entity>): [never, QueryOrder][];
|
|
74
|
-
/** @ignore */
|
|
75
|
-
[inspect.custom](): string;
|
|
76
73
|
}
|
package/utils/Cursor.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { inspect } from 'node:util';
|
|
2
1
|
import { Utils } from './Utils.js';
|
|
3
2
|
import { ReferenceKind } from '../enums.js';
|
|
4
3
|
import { Reference } from '../entity/Reference.js';
|
|
5
4
|
import { helper } from '../entity/wrap.js';
|
|
6
|
-
import {
|
|
5
|
+
import { Raw } from '../utils/RawQueryFragment.js';
|
|
7
6
|
import { CursorError } from '../errors.js';
|
|
7
|
+
import { inspect } from '../logging/inspect.js';
|
|
8
8
|
/**
|
|
9
9
|
* As an alternative to the offset-based pagination with `limit` and `offset`, we can paginate based on a cursor.
|
|
10
10
|
* A cursor is an opaque string that defines a specific place in ordered entity graph. You can use `em.findByCursor()`
|
|
@@ -107,6 +107,9 @@ export class Cursor {
|
|
|
107
107
|
if (Utils.isEntity(value, true)) {
|
|
108
108
|
value = helper(value).getPrimaryKey();
|
|
109
109
|
}
|
|
110
|
+
if (Utils.isScalarReference(value)) {
|
|
111
|
+
value = value.unwrap();
|
|
112
|
+
}
|
|
110
113
|
if (object) {
|
|
111
114
|
return ({ [prop]: value });
|
|
112
115
|
}
|
|
@@ -144,8 +147,8 @@ export class Cursor {
|
|
|
144
147
|
static getDefinition(meta, orderBy) {
|
|
145
148
|
return Utils.asArray(orderBy).flatMap(order => {
|
|
146
149
|
const ret = [];
|
|
147
|
-
for (const key of Utils.
|
|
148
|
-
if (
|
|
150
|
+
for (const key of Utils.getObjectQueryKeys(order)) {
|
|
151
|
+
if (Raw.isKnownFragmentSymbol(key)) {
|
|
149
152
|
ret.push([key, order[key]]);
|
|
150
153
|
continue;
|
|
151
154
|
}
|
|
@@ -159,9 +162,9 @@ export class Cursor {
|
|
|
159
162
|
return ret;
|
|
160
163
|
});
|
|
161
164
|
}
|
|
162
|
-
/* v8 ignore start */
|
|
163
165
|
/** @ignore */
|
|
164
|
-
|
|
166
|
+
/* v8 ignore next */
|
|
167
|
+
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
165
168
|
const type = this.items[0]?.constructor.name;
|
|
166
169
|
const { items, startCursor, endCursor, hasPrevPage, hasNextPage, totalCount, length } = this;
|
|
167
170
|
const options = inspect({ startCursor, endCursor, totalCount, hasPrevPage, hasNextPage, items, length }, { depth: 0 });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { Primary, Ref } from '../typings.js';
|
|
1
|
+
import type { Constructor, Primary, Ref } from '../typings.js';
|
|
2
2
|
import { Collection, type InitCollectionOptions } from '../entity/Collection.js';
|
|
3
3
|
import { type EntityManager } from '../EntityManager.js';
|
|
4
|
-
import type DataLoader from 'dataloader';
|
|
5
4
|
import { type LoadReferenceOptions } from '../entity/Reference.js';
|
|
5
|
+
type BatchLoadFn<K, V> = (keys: readonly K[]) => PromiseLike<ArrayLike<V | Error>>;
|
|
6
6
|
export declare class DataloaderUtils {
|
|
7
|
+
private static DataLoader?;
|
|
7
8
|
/**
|
|
8
9
|
* Groups identified references by entity and returns a Map with the
|
|
9
10
|
* class name as the index and the corresponding primary keys as the value.
|
|
@@ -13,7 +14,7 @@ export declare class DataloaderUtils {
|
|
|
13
14
|
* Returns the reference dataloader batchLoadFn, which aggregates references by entity,
|
|
14
15
|
* makes one query per entity and maps each input reference to the corresponding result.
|
|
15
16
|
*/
|
|
16
|
-
static getRefBatchLoadFn(em: EntityManager):
|
|
17
|
+
static getRefBatchLoadFn(em: EntityManager): BatchLoadFn<[Ref<any>, Omit<LoadReferenceOptions<any, any>, 'dataloader'>?], any>;
|
|
17
18
|
/**
|
|
18
19
|
* Groups collections by entity and returns a Map whose keys are the entity names and whose values are filter Maps
|
|
19
20
|
* which we can use to narrow down the find query to return just the items of the collections that have been dataloaded.
|
|
@@ -34,8 +35,17 @@ export declare class DataloaderUtils {
|
|
|
34
35
|
*/
|
|
35
36
|
static getColFilter<T, S extends T>(collection: Collection<any>): (result: T) => result is S;
|
|
36
37
|
/**
|
|
37
|
-
* Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
38
|
+
* Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
38
39
|
* makes one query per entity and maps each input collection to the corresponding result.
|
|
39
40
|
*/
|
|
40
|
-
static getColBatchLoadFn(em: EntityManager):
|
|
41
|
+
static getColBatchLoadFn(em: EntityManager): BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
|
|
42
|
+
/**
|
|
43
|
+
* Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
44
|
+
* makes one query per entity and maps each input collection to the corresponding result.
|
|
45
|
+
*/
|
|
46
|
+
static getManyToManyColBatchLoadFn(em: EntityManager): BatchLoadFn<[Collection<any>, Omit<InitCollectionOptions<any, any>, 'dataloader'>?], any>;
|
|
47
|
+
static getDataLoader(): Promise<Constructor<{
|
|
48
|
+
load: (...args: unknown[]) => Promise<unknown>;
|
|
49
|
+
}>>;
|
|
41
50
|
}
|
|
51
|
+
export {};
|
package/utils/DataloaderUtils.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Collection } from '../entity/Collection.js';
|
|
2
2
|
import { helper } from '../entity/wrap.js';
|
|
3
|
-
import { ReferenceKind } from '../enums.js';
|
|
4
3
|
import { Reference } from '../entity/Reference.js';
|
|
4
|
+
import { Utils } from './Utils.js';
|
|
5
5
|
export class DataloaderUtils {
|
|
6
|
+
static DataLoader;
|
|
6
7
|
/**
|
|
7
8
|
* Groups identified references by entity and returns a Map with the
|
|
8
9
|
* class name as the index and the corresponding primary keys as the value.
|
|
@@ -10,7 +11,7 @@ export class DataloaderUtils {
|
|
|
10
11
|
static groupPrimaryKeysByEntityAndOpts(refsWithOpts) {
|
|
11
12
|
const map = new Map();
|
|
12
13
|
for (const [ref, opts] of refsWithOpts) {
|
|
13
|
-
/* The key is a combination of the
|
|
14
|
+
/* The key is a combination of the uniqueName (a unique table name based identifier) and a stringified version if the load options because we want
|
|
14
15
|
to map each combination of entities/options into separate find queries in order to return accurate results.
|
|
15
16
|
This could be further optimized finding the "lowest common denominator" among the different options
|
|
16
17
|
for each Entity and firing a single query for each Entity instead of Entity+options combination.
|
|
@@ -23,7 +24,7 @@ export class DataloaderUtils {
|
|
|
23
24
|
Thus such approach should probably be configurable, if not opt-in.
|
|
24
25
|
NOTE: meta + opts multi maps (https://github.com/martian17/ds-js) might be a more elegant way
|
|
25
26
|
to implement this but not necessarily faster. */
|
|
26
|
-
const key = `${helper(ref).__meta.
|
|
27
|
+
const key = `${helper(ref).__meta.uniqueName}|${JSON.stringify(opts ?? {})}`;
|
|
27
28
|
let primaryKeysSet = map.get(key);
|
|
28
29
|
if (primaryKeysSet == null) {
|
|
29
30
|
primaryKeysSet = new Set();
|
|
@@ -41,9 +42,10 @@ export class DataloaderUtils {
|
|
|
41
42
|
return async (refsWithOpts) => {
|
|
42
43
|
const groupedIdsMap = DataloaderUtils.groupPrimaryKeysByEntityAndOpts(refsWithOpts);
|
|
43
44
|
const promises = Array.from(groupedIdsMap).map(([key, idsSet]) => {
|
|
44
|
-
const
|
|
45
|
+
const uniqueName = key.substring(0, key.indexOf('|'));
|
|
45
46
|
const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
|
|
46
|
-
|
|
47
|
+
const meta = em.getMetadata().getByUniqueName(uniqueName);
|
|
48
|
+
return em.find(meta.class, Array.from(idsSet), opts);
|
|
47
49
|
});
|
|
48
50
|
await Promise.all(promises);
|
|
49
51
|
/* Instead of assigning each find result to the original reference we use a shortcut
|
|
@@ -69,7 +71,7 @@ export class DataloaderUtils {
|
|
|
69
71
|
The value is another Map which we can use to filter the find query to get results pertaining to the collections that have been dataloaded:
|
|
70
72
|
its keys are the props we are going to filter to and its values are the corresponding PKs.
|
|
71
73
|
*/
|
|
72
|
-
const key = `${col.property.targetMeta.
|
|
74
|
+
const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
|
|
73
75
|
let filterMap = entitiesMap.get(key); // We are going to use this map to filter the entities pertaining to the collections that have been dataloaded.
|
|
74
76
|
if (filterMap == null) {
|
|
75
77
|
filterMap = new Map();
|
|
@@ -96,9 +98,10 @@ export class DataloaderUtils {
|
|
|
96
98
|
*/
|
|
97
99
|
static entitiesAndOptsMapToQueries(entitiesAndOptsMap, em) {
|
|
98
100
|
return Array.from(entitiesAndOptsMap, async ([key, filterMap]) => {
|
|
99
|
-
const
|
|
101
|
+
const uniqueName = key.substring(0, key.indexOf('|'));
|
|
100
102
|
const opts = JSON.parse(key.substring(key.indexOf('|') + 1));
|
|
101
|
-
const
|
|
103
|
+
const meta = em.getMetadata().getByUniqueName(uniqueName);
|
|
104
|
+
const res = await em.find(meta.class, opts?.where != null && Object.keys(opts.where).length > 0 ?
|
|
102
105
|
{
|
|
103
106
|
$and: [
|
|
104
107
|
{
|
|
@@ -118,10 +121,9 @@ export class DataloaderUtils {
|
|
|
118
121
|
// We need to populate the inverse side of the relationship in order to be able to later retrieve the PK(s) from its item(s)
|
|
119
122
|
populate: [
|
|
120
123
|
...(opts.populate === false ? [] : opts.populate ?? []),
|
|
121
|
-
...(opts.ref ? [':ref'] : []),
|
|
122
124
|
...Array.from(filterMap.keys()).filter(
|
|
123
125
|
// We need to do so only if the inverse side is a collection, because we can already retrieve the PK from a reference without having to load it
|
|
124
|
-
prop =>
|
|
126
|
+
prop => meta.properties[prop]?.ref !== true),
|
|
125
127
|
],
|
|
126
128
|
});
|
|
127
129
|
return [key, res];
|
|
@@ -149,15 +151,11 @@ export class DataloaderUtils {
|
|
|
149
151
|
else if (target) {
|
|
150
152
|
return target === collection.owner;
|
|
151
153
|
}
|
|
152
|
-
// FIXME https://github.com/mikro-orm/mikro-orm/issues/6031
|
|
153
|
-
if (!target && collection.property.kind === ReferenceKind.MANY_TO_MANY) {
|
|
154
|
-
throw new Error(`Inverse side is required for M:N relations with dataloader: ${collection.owner.constructor.name}.${collection.property.name}`);
|
|
155
|
-
}
|
|
156
154
|
return false;
|
|
157
155
|
};
|
|
158
156
|
}
|
|
159
157
|
/**
|
|
160
|
-
* Returns the collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
158
|
+
* Returns the 1:M collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
161
159
|
* makes one query per entity and maps each input collection to the corresponding result.
|
|
162
160
|
*/
|
|
163
161
|
static getColBatchLoadFn(em) {
|
|
@@ -168,15 +166,65 @@ export class DataloaderUtils {
|
|
|
168
166
|
// We need to filter the results in order to map each input collection
|
|
169
167
|
// to a subset of each query matching the collection items.
|
|
170
168
|
return collsWithOpts.map(([col, opts]) => {
|
|
171
|
-
const key = `${col.property.targetMeta.
|
|
169
|
+
const key = `${col.property.targetMeta.uniqueName}|${JSON.stringify(opts ?? {})}`;
|
|
172
170
|
const entities = resultsMap.get(key);
|
|
173
171
|
if (entities == null) {
|
|
174
172
|
// Should never happen
|
|
175
|
-
/* v8 ignore next
|
|
173
|
+
/* v8 ignore next */
|
|
176
174
|
throw new Error('Cannot match results');
|
|
177
175
|
}
|
|
178
176
|
return entities.filter(DataloaderUtils.getColFilter(col));
|
|
179
177
|
});
|
|
180
178
|
};
|
|
181
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Returns the M:N collection dataloader batchLoadFn, which aggregates collections by entity,
|
|
182
|
+
* makes one query per entity and maps each input collection to the corresponding result.
|
|
183
|
+
*/
|
|
184
|
+
static getManyToManyColBatchLoadFn(em) {
|
|
185
|
+
return async (collsWithOpts) => {
|
|
186
|
+
const groups = new Map();
|
|
187
|
+
for (const [col, opts] of collsWithOpts) {
|
|
188
|
+
const key = `${col.property.targetMeta.uniqueName}.${col.property.name}|${JSON.stringify(opts ?? {})}`;
|
|
189
|
+
const value = groups.get(key) ?? [];
|
|
190
|
+
value.push([col, opts ?? {}]);
|
|
191
|
+
groups.set(key, value);
|
|
192
|
+
}
|
|
193
|
+
const ret = [];
|
|
194
|
+
for (const group of groups.values()) {
|
|
195
|
+
const prop = group[0][0].property;
|
|
196
|
+
const options = {};
|
|
197
|
+
const wrap = (cond) => ({ [prop.name]: cond });
|
|
198
|
+
const orderBy = Utils.asArray(group[0][1]?.orderBy).map(o => wrap(o));
|
|
199
|
+
const populate = wrap(group[0][1]?.populate);
|
|
200
|
+
const owners = group.map(c => c[0].owner);
|
|
201
|
+
const $or = [];
|
|
202
|
+
// a bit of a hack, but we need to prefix the key, since we have only a column name, not a property name
|
|
203
|
+
const alias = em.config.getNamingStrategy().aliasName(Utils.className(prop.pivotEntity), 0);
|
|
204
|
+
const fk = `${alias}.${Utils.getPrimaryKeyHash(prop.joinColumns)}`;
|
|
205
|
+
for (const c of group) {
|
|
206
|
+
$or.push({ $and: [c[1]?.where ?? {}, { [fk]: c[0].owner }] });
|
|
207
|
+
options.refresh ??= c[1]?.refresh;
|
|
208
|
+
}
|
|
209
|
+
options.where = wrap({ $or });
|
|
210
|
+
const r = await em.getEntityLoader().findChildrenFromPivotTable(owners, prop, options, orderBy, populate, group[0][1]?.ref);
|
|
211
|
+
ret.push(...r);
|
|
212
|
+
}
|
|
213
|
+
return ret;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
static async getDataLoader() {
|
|
217
|
+
if (this.DataLoader) {
|
|
218
|
+
return this.DataLoader;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
const mod = await import('dataloader');
|
|
222
|
+
const DataLoader = mod.default;
|
|
223
|
+
return (this.DataLoader ??= DataLoader);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
/* v8 ignore next */
|
|
227
|
+
throw new Error('DataLoader is not found, make sure `dataloader` package is installed in your project\'s dependencies.');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
182
230
|
}
|