@mikro-orm/core 7.0.0-rc.2 → 7.0.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 +4 -16
- package/EntityManager.js +248 -181
- package/MikroORM.d.ts +4 -6
- package/MikroORM.js +24 -24
- package/README.md +5 -4
- package/cache/FileCacheAdapter.d.ts +1 -5
- package/cache/FileCacheAdapter.js +22 -24
- 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 +43 -14
- package/drivers/DatabaseDriver.d.ts +0 -2
- package/drivers/DatabaseDriver.js +28 -12
- package/drivers/IDatabaseDriver.d.ts +43 -0
- package/entity/Collection.d.ts +1 -9
- package/entity/Collection.js +124 -108
- package/entity/EntityAssigner.js +23 -11
- package/entity/EntityFactory.d.ts +1 -8
- package/entity/EntityFactory.js +79 -59
- package/entity/EntityHelper.js +25 -16
- package/entity/EntityLoader.d.ts +1 -3
- package/entity/EntityLoader.js +90 -60
- package/entity/Reference.d.ts +2 -3
- package/entity/Reference.js +48 -19
- package/entity/WrappedEntity.d.ts +4 -2
- package/entity/WrappedEntity.js +5 -1
- package/entity/defineEntity.d.ts +42 -85
- package/entity/utils.js +28 -26
- package/entity/validators.js +2 -1
- package/enums.d.ts +2 -1
- package/enums.js +13 -17
- package/errors.d.ts +11 -11
- package/errors.js +8 -8
- package/events/EventManager.d.ts +1 -4
- package/events/EventManager.js +26 -23
- package/events/index.d.ts +1 -1
- package/events/index.js +0 -1
- package/exceptions.js +9 -2
- package/hydration/ObjectHydrator.d.ts +1 -2
- package/hydration/ObjectHydrator.js +41 -27
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/logging/DefaultLogger.js +6 -7
- package/logging/Logger.d.ts +2 -1
- package/logging/colors.js +2 -5
- package/logging/index.d.ts +1 -1
- package/logging/index.js +0 -1
- package/metadata/EntitySchema.d.ts +3 -3
- package/metadata/EntitySchema.js +12 -2
- package/metadata/MetadataDiscovery.d.ts +1 -9
- package/metadata/MetadataDiscovery.js +251 -179
- package/metadata/MetadataProvider.js +26 -1
- package/metadata/MetadataStorage.d.ts +1 -5
- package/metadata/MetadataStorage.js +37 -39
- package/metadata/MetadataValidator.js +20 -5
- package/metadata/discover-entities.js +1 -1
- package/metadata/index.d.ts +1 -1
- package/metadata/index.js +0 -1
- package/metadata/types.d.ts +2 -2
- package/naming-strategy/AbstractNamingStrategy.js +6 -3
- package/naming-strategy/EntityCaseNamingStrategy.js +1 -1
- package/naming-strategy/index.d.ts +1 -1
- package/naming-strategy/index.js +0 -1
- package/not-supported.js +5 -1
- package/package.json +38 -38
- package/platforms/Platform.d.ts +24 -1
- package/platforms/Platform.js +106 -27
- package/serialization/EntitySerializer.js +8 -4
- package/serialization/EntityTransformer.js +4 -1
- package/serialization/SerializationContext.d.ts +4 -8
- package/serialization/SerializationContext.js +21 -16
- package/types/UuidType.d.ts +2 -0
- package/types/UuidType.js +14 -2
- package/types/index.d.ts +2 -1
- package/typings.d.ts +35 -24
- package/typings.js +9 -9
- package/unit-of-work/ChangeSet.js +4 -4
- package/unit-of-work/ChangeSetComputer.d.ts +1 -6
- package/unit-of-work/ChangeSetComputer.js +29 -27
- package/unit-of-work/ChangeSetPersister.d.ts +1 -9
- package/unit-of-work/ChangeSetPersister.js +63 -58
- package/unit-of-work/CommitOrderCalculator.d.ts +1 -4
- package/unit-of-work/CommitOrderCalculator.js +17 -15
- package/unit-of-work/IdentityMap.d.ts +2 -5
- package/unit-of-work/IdentityMap.js +18 -18
- package/unit-of-work/UnitOfWork.d.ts +12 -20
- package/unit-of-work/UnitOfWork.js +228 -191
- package/utils/AbstractMigrator.d.ts +2 -2
- package/utils/AbstractMigrator.js +10 -12
- package/utils/AbstractSchemaGenerator.js +2 -1
- package/utils/AsyncContext.js +1 -1
- package/utils/Configuration.d.ts +90 -189
- package/utils/Configuration.js +97 -77
- package/utils/Cursor.d.ts +3 -3
- package/utils/Cursor.js +8 -6
- package/utils/DataloaderUtils.js +15 -12
- package/utils/EntityComparator.d.ts +8 -15
- package/utils/EntityComparator.js +100 -92
- package/utils/QueryHelper.d.ts +16 -1
- package/utils/QueryHelper.js +108 -50
- package/utils/RawQueryFragment.d.ts +4 -4
- package/utils/RawQueryFragment.js +3 -2
- package/utils/TransactionManager.js +3 -3
- package/utils/Utils.d.ts +2 -2
- package/utils/Utils.js +39 -32
- package/utils/clone.js +5 -0
- package/utils/env-vars.js +6 -5
- package/utils/fs-utils.d.ts +3 -17
- package/utils/fs-utils.js +2 -5
- package/utils/upsert-utils.js +7 -4
package/MikroORM.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Configuration, type Options } from './utils/Configuration.js';
|
|
|
5
5
|
import type { EntityManager } from './EntityManager.js';
|
|
6
6
|
import type { AnyEntity, Constructor, EntityClass, EntityMetadata, EntityName, IEntityGenerator, IMigrator, ISeedManager } from './typings.js';
|
|
7
7
|
/** @internal */
|
|
8
|
-
export declare function loadOptionalDependencies(options: Options): Promise<void>;
|
|
8
|
+
export declare function loadOptionalDependencies(options: Partial<Options>): Promise<void>;
|
|
9
9
|
/**
|
|
10
10
|
* The main class used to configure and bootstrap the ORM.
|
|
11
11
|
*
|
|
@@ -35,27 +35,25 @@ export declare function loadOptionalDependencies(options: Options): Promise<void
|
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
37
|
export declare class MikroORM<Driver extends IDatabaseDriver = IDatabaseDriver, EM extends Driver[typeof EntityManagerType] & EntityManager<Driver> = Driver[typeof EntityManagerType] & EntityManager<Driver>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> {
|
|
38
|
+
#private;
|
|
38
39
|
/** The global EntityManager instance. If you are using `RequestContext` helper, it will automatically pick the request specific context under the hood */
|
|
39
40
|
em: EM & {
|
|
40
41
|
'~entities'?: Entities;
|
|
41
42
|
};
|
|
42
43
|
readonly driver: Driver;
|
|
43
44
|
readonly config: Configuration<Driver>;
|
|
44
|
-
private metadata;
|
|
45
|
-
private readonly logger;
|
|
46
|
-
private readonly discovery;
|
|
47
45
|
/**
|
|
48
46
|
* Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
|
|
49
47
|
* If you omit the `options` parameter, your CLI config will be used.
|
|
50
48
|
*/
|
|
51
|
-
static init<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Options<D, EM, Entities
|
|
49
|
+
static init<D extends IDatabaseDriver = IDatabaseDriver, EM extends D[typeof EntityManagerType] & EntityManager<D> = D[typeof EntityManagerType] & EntityManager<D>, Entities extends (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]>(options: Partial<Options<D, EM, Entities>>): Promise<MikroORM<D, EM, Entities>>;
|
|
52
50
|
/**
|
|
53
51
|
* Synchronous variant of the `init` method with some limitations:
|
|
54
52
|
* - folder-based discovery not supported
|
|
55
53
|
* - ORM extensions are not autoloaded
|
|
56
54
|
* - when metadata cache is enabled, `FileCacheAdapter` needs to be explicitly set in the config
|
|
57
55
|
*/
|
|
58
|
-
constructor(options: Options<Driver, EM, Entities
|
|
56
|
+
constructor(options: Partial<Options<Driver, EM, Entities>>);
|
|
59
57
|
/**
|
|
60
58
|
* Connects to the database.
|
|
61
59
|
*/
|
package/MikroORM.js
CHANGED
|
@@ -74,9 +74,9 @@ export class MikroORM {
|
|
|
74
74
|
em;
|
|
75
75
|
driver;
|
|
76
76
|
config;
|
|
77
|
-
metadata;
|
|
78
|
-
logger;
|
|
79
|
-
discovery;
|
|
77
|
+
#metadata;
|
|
78
|
+
#logger;
|
|
79
|
+
#discovery;
|
|
80
80
|
/**
|
|
81
81
|
* Initialize the ORM, load entity metadata, create EntityManager and connect to the database.
|
|
82
82
|
* If you omit the `options` parameter, your CLI config will be used.
|
|
@@ -92,7 +92,7 @@ export class MikroORM {
|
|
|
92
92
|
await loadOptionalDependencies(options);
|
|
93
93
|
const orm = new this(options);
|
|
94
94
|
const preferTs = orm.config.get('preferTs', Utils.detectTypeScriptSupport());
|
|
95
|
-
orm
|
|
95
|
+
orm.#metadata = await orm.#discovery.discover(preferTs);
|
|
96
96
|
orm.createEntityManager();
|
|
97
97
|
return orm;
|
|
98
98
|
}
|
|
@@ -104,21 +104,19 @@ export class MikroORM {
|
|
|
104
104
|
*/
|
|
105
105
|
constructor(options) {
|
|
106
106
|
const env = loadEnvironmentVars();
|
|
107
|
-
options = options.preferEnvVars
|
|
108
|
-
? Utils.merge(options, env)
|
|
109
|
-
: Utils.merge(env, options);
|
|
107
|
+
options = options.preferEnvVars ? Utils.merge(options, env) : Utils.merge(env, options);
|
|
110
108
|
this.config = new Configuration(options);
|
|
111
109
|
const discovery = this.config.get('discovery');
|
|
112
110
|
this.driver = this.config.getDriver();
|
|
113
|
-
this
|
|
114
|
-
this
|
|
115
|
-
this
|
|
111
|
+
this.#logger = this.config.getLogger();
|
|
112
|
+
this.#logger.log('info', `MikroORM version: ${colors.green(Utils.getORMVersion())}`);
|
|
113
|
+
this.#discovery = new MetadataDiscovery(new MetadataStorage(), this.driver.getPlatform(), this.config);
|
|
116
114
|
this.driver.getPlatform().init(this);
|
|
117
115
|
for (const extension of this.config.get('extensions')) {
|
|
118
116
|
extension.register(this);
|
|
119
117
|
}
|
|
120
118
|
if (!discovery.skipSyncDiscovery) {
|
|
121
|
-
this
|
|
119
|
+
this.#metadata = this.#discovery.discoverSync();
|
|
122
120
|
this.createEntityManager();
|
|
123
121
|
}
|
|
124
122
|
}
|
|
@@ -164,32 +162,32 @@ export class MikroORM {
|
|
|
164
162
|
*/
|
|
165
163
|
getMetadata(entityName) {
|
|
166
164
|
if (entityName) {
|
|
167
|
-
return this
|
|
165
|
+
return this.#metadata.get(entityName);
|
|
168
166
|
}
|
|
169
|
-
return this
|
|
167
|
+
return this.#metadata;
|
|
170
168
|
}
|
|
171
169
|
createEntityManager() {
|
|
172
|
-
this.driver.setMetadata(this
|
|
170
|
+
this.driver.setMetadata(this.#metadata);
|
|
173
171
|
this.em = this.driver.createEntityManager();
|
|
174
172
|
this.em.global = true;
|
|
175
|
-
this
|
|
176
|
-
this.driver.setMetadata(this
|
|
173
|
+
this.#metadata.decorate(this.em);
|
|
174
|
+
this.driver.setMetadata(this.#metadata);
|
|
177
175
|
}
|
|
178
176
|
/**
|
|
179
177
|
* Allows dynamically discovering new entity by reference, handy for testing schema diffing.
|
|
180
178
|
*/
|
|
181
179
|
discoverEntity(entities, reset) {
|
|
182
180
|
for (const className of Utils.asArray(reset)) {
|
|
183
|
-
this
|
|
184
|
-
this
|
|
181
|
+
this.#metadata.reset(className);
|
|
182
|
+
this.#discovery.reset(className);
|
|
185
183
|
}
|
|
186
|
-
const tmp = this
|
|
187
|
-
const metadata = this
|
|
184
|
+
const tmp = this.#discovery.discoverReferences(Utils.asArray(entities));
|
|
185
|
+
const metadata = this.#discovery.processDiscoveredEntities(tmp);
|
|
188
186
|
for (const meta of metadata) {
|
|
189
|
-
this
|
|
190
|
-
meta.root = this
|
|
187
|
+
this.#metadata.set(meta.class, meta);
|
|
188
|
+
meta.root = this.#metadata.get(meta.root.class);
|
|
191
189
|
}
|
|
192
|
-
this
|
|
190
|
+
this.#metadata.decorate(this.em);
|
|
193
191
|
}
|
|
194
192
|
/**
|
|
195
193
|
* Gets the SchemaGenerator.
|
|
@@ -213,6 +211,8 @@ export class MikroORM {
|
|
|
213
211
|
* Gets the EntityGenerator.
|
|
214
212
|
*/
|
|
215
213
|
get entityGenerator() {
|
|
216
|
-
return this.driver
|
|
214
|
+
return this.driver
|
|
215
|
+
.getPlatform()
|
|
216
|
+
.getExtension('EntityGenerator', '@mikro-orm/entity-generator', '@mikro-orm/entity-generator', this.em);
|
|
217
217
|
}
|
|
218
218
|
}
|
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
<a href="https://mikro-orm.io"><img src="https://raw.githubusercontent.com/mikro-orm/mikro-orm/master/docs/static/img/logo-readme.svg?sanitize=true" alt="MikroORM" /></a>
|
|
3
3
|
</h1>
|
|
4
4
|
|
|
5
|
-
TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL
|
|
5
|
+
TypeScript ORM for Node.js based on Data Mapper, [Unit of Work](https://mikro-orm.io/docs/unit-of-work/) and [Identity Map](https://mikro-orm.io/docs/identity-map/) patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite (including libSQL), MSSQL and Oracle databases.
|
|
6
6
|
|
|
7
7
|
> Heavily inspired by [Doctrine](https://www.doctrine-project.org/) and [Hibernate](https://hibernate.org/).
|
|
8
8
|
|
|
9
|
-
[](https://
|
|
10
|
-
[](https://
|
|
9
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
10
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
11
11
|
[](https://discord.gg/w8bjxFHS7X)
|
|
12
|
-
[](https://
|
|
12
|
+
[](https://npmx.dev/package/@mikro-orm/core)
|
|
13
13
|
[](https://coveralls.io/r/mikro-orm/mikro-orm?branch=master)
|
|
14
14
|
[](https://github.com/mikro-orm/mikro-orm/actions?workflow=tests)
|
|
15
15
|
|
|
@@ -181,6 +181,7 @@ yarn add @mikro-orm/core @mikro-orm/mysql # for mysql/mariadb
|
|
|
181
181
|
yarn add @mikro-orm/core @mikro-orm/mariadb # for mysql/mariadb
|
|
182
182
|
yarn add @mikro-orm/core @mikro-orm/postgresql # for postgresql
|
|
183
183
|
yarn add @mikro-orm/core @mikro-orm/mssql # for mssql
|
|
184
|
+
yarn add @mikro-orm/core @mikro-orm/oracledb # for oracle
|
|
184
185
|
yarn add @mikro-orm/core @mikro-orm/sqlite # for sqlite
|
|
185
186
|
yarn add @mikro-orm/core @mikro-orm/libsql # for libsql
|
|
186
187
|
```
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { SyncCacheAdapter } from './CacheAdapter.js';
|
|
2
2
|
export declare class FileCacheAdapter implements SyncCacheAdapter {
|
|
3
|
-
private
|
|
4
|
-
private readonly baseDir;
|
|
5
|
-
private readonly pretty;
|
|
6
|
-
private readonly VERSION;
|
|
7
|
-
private cache;
|
|
3
|
+
#private;
|
|
8
4
|
constructor(options: {
|
|
9
5
|
cacheDir: string;
|
|
10
6
|
combined?: boolean | string;
|
|
@@ -2,16 +2,16 @@ import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
|
2
2
|
import { fs } from '../utils/fs-utils.js';
|
|
3
3
|
import { Utils } from '../utils/Utils.js';
|
|
4
4
|
export class FileCacheAdapter {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
#VERSION = Utils.getORMVersion();
|
|
6
|
+
#cache = {};
|
|
7
|
+
#options;
|
|
8
|
+
#baseDir;
|
|
9
|
+
#pretty;
|
|
10
10
|
constructor(options = {}, baseDir, pretty = false) {
|
|
11
|
-
this
|
|
12
|
-
this
|
|
13
|
-
this
|
|
14
|
-
this
|
|
11
|
+
this.#options = options;
|
|
12
|
+
this.#baseDir = baseDir;
|
|
13
|
+
this.#pretty = pretty;
|
|
14
|
+
this.#options.cacheDir ??= process.cwd() + '/temp';
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* @inheritDoc
|
|
@@ -32,13 +32,13 @@ export class FileCacheAdapter {
|
|
|
32
32
|
* @inheritDoc
|
|
33
33
|
*/
|
|
34
34
|
set(name, data, origin) {
|
|
35
|
-
if (this
|
|
36
|
-
this
|
|
35
|
+
if (this.#options.combined) {
|
|
36
|
+
this.#cache[name.replace(/\.[jt]s$/, '')] = data;
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
const path = this.path(name);
|
|
40
40
|
const hash = this.getHash(origin);
|
|
41
|
-
writeFileSync(path, JSON.stringify({ data, origin, hash, version: this
|
|
41
|
+
writeFileSync(path, JSON.stringify({ data, origin, hash, version: this.#VERSION }, null, this.#pretty ? 2 : undefined));
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
44
|
* @inheritDoc
|
|
@@ -62,30 +62,28 @@ export class FileCacheAdapter {
|
|
|
62
62
|
// ignore if file is already gone
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
this
|
|
65
|
+
this.#cache = {};
|
|
66
66
|
}
|
|
67
67
|
combine() {
|
|
68
|
-
if (!this
|
|
68
|
+
if (!this.#options.combined) {
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
-
let path = typeof this
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
path
|
|
75
|
-
this.options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
|
|
76
|
-
writeFileSync(path, JSON.stringify(this.cache, null, this.pretty ? 2 : undefined));
|
|
71
|
+
let path = typeof this.#options.combined === 'string' ? this.#options.combined : './metadata.json';
|
|
72
|
+
path = fs.normalizePath(this.#options.cacheDir, path);
|
|
73
|
+
this.#options.combined = path; // override in the options, so we can log it from the CLI in `cache:generate` command
|
|
74
|
+
writeFileSync(path, JSON.stringify(this.#cache, null, this.#pretty ? 2 : undefined));
|
|
77
75
|
return path;
|
|
78
76
|
}
|
|
79
77
|
path(name) {
|
|
80
|
-
fs.ensureDir(this
|
|
81
|
-
return `${this
|
|
78
|
+
fs.ensureDir(this.#options.cacheDir);
|
|
79
|
+
return `${this.#options.cacheDir}/${name}.json`;
|
|
82
80
|
}
|
|
83
81
|
getHash(origin) {
|
|
84
|
-
origin = fs.absolutePath(origin, this
|
|
82
|
+
origin = fs.absolutePath(origin, this.#baseDir);
|
|
85
83
|
if (!existsSync(origin)) {
|
|
86
84
|
return null;
|
|
87
85
|
}
|
|
88
86
|
const contents = readFileSync(origin);
|
|
89
|
-
return Utils.hash(contents.toString() + this
|
|
87
|
+
return Utils.hash(contents.toString() + this.#VERSION);
|
|
90
88
|
}
|
|
91
89
|
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
export class GeneratedCacheAdapter {
|
|
2
|
-
data
|
|
2
|
+
#data;
|
|
3
3
|
constructor(options) {
|
|
4
|
-
this
|
|
4
|
+
this.#data = new Map(Object.entries(options.data));
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* @inheritDoc
|
|
8
8
|
*/
|
|
9
9
|
get(name) {
|
|
10
10
|
const key = name.replace(/\.[jt]s$/, '');
|
|
11
|
-
const data = this
|
|
11
|
+
const data = this.#data.get(key);
|
|
12
12
|
return data;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* @inheritDoc
|
|
16
16
|
*/
|
|
17
17
|
set(name, data, origin) {
|
|
18
|
-
this
|
|
18
|
+
this.#data.set(name, { data });
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* @inheritDoc
|
|
22
22
|
*/
|
|
23
23
|
remove(name) {
|
|
24
|
-
this
|
|
24
|
+
this.#data.delete(name);
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* @inheritDoc
|
|
28
28
|
*/
|
|
29
29
|
clear() {
|
|
30
|
-
this
|
|
30
|
+
this.#data.clear();
|
|
31
31
|
}
|
|
32
32
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
export class MemoryCacheAdapter {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
#data = new Map();
|
|
3
|
+
#options;
|
|
4
4
|
constructor(options) {
|
|
5
|
-
this
|
|
5
|
+
this.#options = options;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
8
|
* @inheritDoc
|
|
9
9
|
*/
|
|
10
10
|
get(name) {
|
|
11
|
-
const data = this
|
|
11
|
+
const data = this.#data.get(name);
|
|
12
12
|
if (data) {
|
|
13
13
|
if (data.expiration < Date.now()) {
|
|
14
|
-
this
|
|
14
|
+
this.#data.delete(name);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
17
|
return data.data;
|
|
@@ -23,18 +23,18 @@ export class MemoryCacheAdapter {
|
|
|
23
23
|
* @inheritDoc
|
|
24
24
|
*/
|
|
25
25
|
set(name, data, origin, expiration) {
|
|
26
|
-
this
|
|
26
|
+
this.#data.set(name, { data, expiration: Date.now() + (expiration ?? this.#options.expiration) });
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* @inheritDoc
|
|
30
30
|
*/
|
|
31
31
|
remove(name) {
|
|
32
|
-
this
|
|
32
|
+
this.#data.delete(name);
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
35
35
|
* @inheritDoc
|
|
36
36
|
*/
|
|
37
37
|
clear() {
|
|
38
|
-
this
|
|
38
|
+
this.#data.clear();
|
|
39
39
|
}
|
|
40
40
|
}
|
package/cache/index.d.ts
CHANGED
package/cache/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import type { Platform } from '../platforms/Platform.js';
|
|
|
6
6
|
import type { TransactionEventBroadcaster } from '../events/TransactionEventBroadcaster.js';
|
|
7
7
|
import type { IsolationLevel } from '../enums.js';
|
|
8
8
|
export declare abstract class Connection {
|
|
9
|
+
#private;
|
|
9
10
|
protected readonly config: Configuration;
|
|
10
11
|
protected readonly type: ConnectionType;
|
|
11
12
|
protected metadata: MetadataStorage;
|
|
@@ -7,6 +7,12 @@ export class Connection {
|
|
|
7
7
|
options;
|
|
8
8
|
logger;
|
|
9
9
|
connected = false;
|
|
10
|
+
get #connectionLabel() {
|
|
11
|
+
return {
|
|
12
|
+
type: this.type,
|
|
13
|
+
name: this.options.name || this.config.get('name') || this.options.host || this.options.dbName,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
10
16
|
constructor(config, options, type = 'write') {
|
|
11
17
|
this.config = config;
|
|
12
18
|
this.type = type;
|
|
@@ -16,7 +22,18 @@ export class Connection {
|
|
|
16
22
|
this.options = Utils.copy(options);
|
|
17
23
|
}
|
|
18
24
|
else {
|
|
19
|
-
const props = [
|
|
25
|
+
const props = [
|
|
26
|
+
'dbName',
|
|
27
|
+
'clientUrl',
|
|
28
|
+
'host',
|
|
29
|
+
'port',
|
|
30
|
+
'user',
|
|
31
|
+
'password',
|
|
32
|
+
'multipleStatements',
|
|
33
|
+
'pool',
|
|
34
|
+
'schema',
|
|
35
|
+
'driverOptions',
|
|
36
|
+
];
|
|
20
37
|
this.options = props.reduce((o, i) => {
|
|
21
38
|
o[i] = this.config.get(i);
|
|
22
39
|
return o;
|
|
@@ -89,8 +106,10 @@ export class Connection {
|
|
|
89
106
|
this.options.host = ret.host = this.options.host ?? this.config.get('host', decodeURIComponent(url.hostname));
|
|
90
107
|
this.options.port = ret.port = this.options.port ?? this.config.get('port', +url.port);
|
|
91
108
|
this.options.user = ret.user = this.options.user ?? this.config.get('user', decodeURIComponent(url.username));
|
|
92
|
-
this.options.password = ret.password =
|
|
93
|
-
|
|
109
|
+
this.options.password = ret.password =
|
|
110
|
+
this.options.password ?? this.config.get('password', decodeURIComponent(url.password));
|
|
111
|
+
this.options.dbName = ret.database =
|
|
112
|
+
this.options.dbName ?? this.config.get('dbName', decodeURIComponent(url.pathname).replace(/^\//, ''));
|
|
94
113
|
}
|
|
95
114
|
return ret;
|
|
96
115
|
}
|
|
@@ -107,28 +126,38 @@ export class Connection {
|
|
|
107
126
|
const now = Date.now();
|
|
108
127
|
try {
|
|
109
128
|
const res = await cb();
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
affected: Utils.isPlainObject(res) ? res.affectedRows : undefined,
|
|
115
|
-
});
|
|
129
|
+
const took = Date.now() - now;
|
|
130
|
+
const results = Array.isArray(res) ? res.length : undefined;
|
|
131
|
+
const affected = Utils.isPlainObject(res) ? res.affectedRows : undefined;
|
|
132
|
+
this.logQuery(query, { ...context, took, results, affected });
|
|
116
133
|
return res;
|
|
117
134
|
}
|
|
118
135
|
catch (e) {
|
|
119
|
-
|
|
136
|
+
const took = Date.now() - now;
|
|
137
|
+
this.logQuery(query, { ...context, took, level: 'error' });
|
|
120
138
|
throw e;
|
|
121
139
|
}
|
|
122
140
|
}
|
|
123
141
|
logQuery(query, context = {}) {
|
|
142
|
+
const connection = this.#connectionLabel;
|
|
124
143
|
this.logger.logQuery({
|
|
125
144
|
level: 'info',
|
|
126
|
-
connection
|
|
127
|
-
type: this.type,
|
|
128
|
-
name: this.options.name || this.config.get('name') || this.options.host,
|
|
129
|
-
},
|
|
145
|
+
connection,
|
|
130
146
|
...context,
|
|
131
147
|
query,
|
|
132
148
|
});
|
|
149
|
+
const threshold = this.config.get('slowQueryThreshold');
|
|
150
|
+
if (threshold != null && (context.took ?? 0) >= threshold) {
|
|
151
|
+
this.config.getSlowQueryLogger().logQuery({
|
|
152
|
+
...context,
|
|
153
|
+
// `enabled: true` bypasses the debug-mode check in isEnabled(),
|
|
154
|
+
// ensuring slow query logs are always emitted regardless of the `debug` setting.
|
|
155
|
+
enabled: true,
|
|
156
|
+
level: context.level ?? 'warning',
|
|
157
|
+
namespace: 'slow-query',
|
|
158
|
+
connection,
|
|
159
|
+
query,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
133
162
|
}
|
|
134
163
|
}
|
|
@@ -9,7 +9,6 @@ import type { Platform } from '../platforms/Platform.js';
|
|
|
9
9
|
import type { Collection } from '../entity/Collection.js';
|
|
10
10
|
import { EntityManager } from '../EntityManager.js';
|
|
11
11
|
import { DriverException } from '../exceptions.js';
|
|
12
|
-
import type { Logger } from '../logging/Logger.js';
|
|
13
12
|
import { MikroORM } from '../MikroORM.js';
|
|
14
13
|
export declare abstract class DatabaseDriver<C extends Connection> implements IDatabaseDriver<C> {
|
|
15
14
|
readonly config: Configuration;
|
|
@@ -18,7 +17,6 @@ export declare abstract class DatabaseDriver<C extends Connection> implements ID
|
|
|
18
17
|
protected readonly connection: C;
|
|
19
18
|
protected readonly replicas: C[];
|
|
20
19
|
protected readonly platform: Platform;
|
|
21
|
-
protected readonly logger: Logger;
|
|
22
20
|
protected comparator: EntityComparator;
|
|
23
21
|
protected metadata: MetadataStorage;
|
|
24
22
|
protected constructor(config: Configuration, dependencies: string[]);
|
|
@@ -18,13 +18,11 @@ export class DatabaseDriver {
|
|
|
18
18
|
connection;
|
|
19
19
|
replicas = [];
|
|
20
20
|
platform;
|
|
21
|
-
logger;
|
|
22
21
|
comparator;
|
|
23
22
|
metadata;
|
|
24
23
|
constructor(config, dependencies) {
|
|
25
24
|
this.config = config;
|
|
26
25
|
this.dependencies = dependencies;
|
|
27
|
-
this.logger = this.config.getLogger();
|
|
28
26
|
}
|
|
29
27
|
async nativeUpdateMany(entityName, where, data, options) {
|
|
30
28
|
throw new Error(`Batch updates are not supported by ${this.constructor.name} driver`);
|
|
@@ -157,11 +155,11 @@ export class DatabaseDriver {
|
|
|
157
155
|
Object.assign(o, createOrderBy(key, direction[key]));
|
|
158
156
|
return o;
|
|
159
157
|
}, {});
|
|
160
|
-
return
|
|
158
|
+
return { [prop]: value };
|
|
161
159
|
}
|
|
162
160
|
const desc = direction === QueryOrderNumeric.DESC || direction.toString().toLowerCase() === 'desc';
|
|
163
161
|
const dir = Utils.xor(desc, isLast) ? 'desc' : 'asc';
|
|
164
|
-
return
|
|
162
|
+
return { [prop]: dir };
|
|
165
163
|
};
|
|
166
164
|
return {
|
|
167
165
|
orderBy: definition.map(([prop, direction]) => createOrderBy(prop, direction)),
|
|
@@ -256,7 +254,7 @@ export class DatabaseDriver {
|
|
|
256
254
|
else {
|
|
257
255
|
data[prop.fieldNames[0]] = this.mapDataToFieldNames(copy, stringifyJsonArrays, prop.embeddedProps, convertCustomTypes, true);
|
|
258
256
|
}
|
|
259
|
-
if (stringifyJsonArrays && prop.array) {
|
|
257
|
+
if (stringifyJsonArrays && prop.array && !object) {
|
|
260
258
|
data[prop.fieldNames[0]] = this.platform.convertJsonToDatabaseValue(data[prop.fieldNames[0]]);
|
|
261
259
|
}
|
|
262
260
|
return;
|
|
@@ -301,16 +299,23 @@ export class DatabaseDriver {
|
|
|
301
299
|
if (prop.joinColumns && Array.isArray(data[k])) {
|
|
302
300
|
const copy = Utils.flatten(data[k]);
|
|
303
301
|
delete data[k];
|
|
304
|
-
prop.joinColumns.forEach((joinColumn, idx) => data[joinColumn] = copy[idx]);
|
|
302
|
+
prop.joinColumns.forEach((joinColumn, idx) => (data[joinColumn] = copy[idx]));
|
|
305
303
|
return;
|
|
306
304
|
}
|
|
307
305
|
if (prop.joinColumns?.length > 1 && data[k] == null) {
|
|
308
306
|
delete data[k];
|
|
309
|
-
prop.ownColumns.forEach(joinColumn => data[joinColumn] = null);
|
|
307
|
+
prop.ownColumns.forEach(joinColumn => (data[joinColumn] = null));
|
|
310
308
|
return;
|
|
311
309
|
}
|
|
312
|
-
if (prop.customType &&
|
|
313
|
-
|
|
310
|
+
if (prop.customType &&
|
|
311
|
+
convertCustomTypes &&
|
|
312
|
+
!(prop.customType instanceof JsonType && object) &&
|
|
313
|
+
!isRaw(data[k])) {
|
|
314
|
+
data[k] = prop.customType.convertToDatabaseValue(data[k], this.platform, {
|
|
315
|
+
fromQuery: true,
|
|
316
|
+
key: k,
|
|
317
|
+
mode: 'query-data',
|
|
318
|
+
});
|
|
314
319
|
}
|
|
315
320
|
if (prop.hasConvertToDatabaseValueSQL && !prop.object && !isRaw(data[k])) {
|
|
316
321
|
const quoted = this.platform.quoteValue(data[k]);
|
|
@@ -341,8 +346,8 @@ export class DatabaseDriver {
|
|
|
341
346
|
const props = prop.embeddedProps;
|
|
342
347
|
let unknownProp = false;
|
|
343
348
|
Object.keys(data[prop.name]).forEach(kk => {
|
|
344
|
-
// explicitly allow `$exists`, `$eq` and `$
|
|
345
|
-
const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f) && !['$exists', '$ne', '$eq'].includes(f));
|
|
349
|
+
// explicitly allow `$exists`, `$eq`, `$ne` and `$elemMatch` operators here as they can't be misused this way
|
|
350
|
+
const operator = Object.keys(data[prop.name]).some(f => Utils.isOperator(f) && !['$exists', '$ne', '$eq', '$elemMatch'].includes(f));
|
|
346
351
|
if (operator) {
|
|
347
352
|
throw ValidationError.cannotUseOperatorsInsideEmbeddables(meta.class, prop.name, data);
|
|
348
353
|
}
|
|
@@ -390,7 +395,18 @@ export class DatabaseDriver {
|
|
|
390
395
|
createReplicas(cb) {
|
|
391
396
|
const replicas = this.config.get('replicas', []);
|
|
392
397
|
const ret = [];
|
|
393
|
-
const props = [
|
|
398
|
+
const props = [
|
|
399
|
+
'dbName',
|
|
400
|
+
'clientUrl',
|
|
401
|
+
'host',
|
|
402
|
+
'port',
|
|
403
|
+
'user',
|
|
404
|
+
'password',
|
|
405
|
+
'multipleStatements',
|
|
406
|
+
'pool',
|
|
407
|
+
'name',
|
|
408
|
+
'driverOptions',
|
|
409
|
+
];
|
|
394
410
|
for (const conf of replicas) {
|
|
395
411
|
const replicaConfig = Utils.copy(conf);
|
|
396
412
|
for (const prop of props) {
|