@mikro-orm/oracledb 7.2.0-dev.3 → 7.2.0-dev.4
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/OracleConnection.js +20 -1
- package/OracleDriver.d.ts +6 -0
- package/OracleDriver.js +21 -4
- package/OracleSchemaGenerator.d.ts +7 -1
- package/OracleSchemaGenerator.js +20 -10
- package/package.json +4 -4
package/OracleConnection.js
CHANGED
|
@@ -31,10 +31,29 @@ export class OracleConnection extends AbstractSqlConnection {
|
|
|
31
31
|
const password = options.password;
|
|
32
32
|
const onCreateConnection = this.options.onCreateConnection ?? this.config.get('onCreateConnection');
|
|
33
33
|
const initialPassword = typeof password === 'function' ? await password() : password;
|
|
34
|
+
const dbName = this.config.get('dbName');
|
|
35
|
+
// unqualified names resolve against the login user's schema, but we manage `dbName`
|
|
36
|
+
const setSchemaSql = this.config.get('user', dbName) === dbName ? undefined : this.platform.getSchemaHelper().getSetSchemaSQL(dbName);
|
|
34
37
|
const poolOptions = {
|
|
35
38
|
...options,
|
|
36
39
|
password: initialPassword,
|
|
37
|
-
sessionCallback: onCreateConnection
|
|
40
|
+
sessionCallback: setSchemaSql || onCreateConnection
|
|
41
|
+
? (conn, _requestedTag, cb) => {
|
|
42
|
+
const initSession = async () => {
|
|
43
|
+
if (setSchemaSql) {
|
|
44
|
+
// ORA-01435: the schema might not exist yet, `ensureDatabase()` creates it later on
|
|
45
|
+
await conn.execute(setSchemaSql).catch((e) => {
|
|
46
|
+
/* v8 ignore next 3: other failures of `alter session` are not reproducible in tests */
|
|
47
|
+
if (e.errorNum !== 1435) {
|
|
48
|
+
throw e;
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
await onCreateConnection?.(conn);
|
|
53
|
+
};
|
|
54
|
+
initSession().then(() => cb(), cb);
|
|
55
|
+
}
|
|
56
|
+
: undefined,
|
|
38
57
|
};
|
|
39
58
|
// Retry pool creation for transient Oracle errors (e.g. ORA-01017 under load)
|
|
40
59
|
let pool;
|
package/OracleDriver.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ export declare class OracleDriver extends AbstractSqlDriver<OracleConnection, Or
|
|
|
10
10
|
createQueryBuilder<T extends AnyEntity<T>>(entityName: EntityName<T>, ctx?: Transaction, preferredConnectionType?: ConnectionType, convertCustomTypes?: boolean, loggerContext?: LoggingOptions, alias?: string, em?: SqlEntityManager): OracleQueryBuilder<T, any, any, any>;
|
|
11
11
|
nativeInsertMany<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>): Promise<QueryResult<T>>;
|
|
12
12
|
nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>): Promise<QueryResult<T>>;
|
|
13
|
+
/**
|
|
14
|
+
* Resolves the runtime type of every column a property maps to, aligned with its `fieldNames`.
|
|
15
|
+
* A relation covers one column per target PK column, and a target PK can be a relation itself,
|
|
16
|
+
* so we recurse down to the scalar leaves - `prop.runtimeType` is `unknown` for relations.
|
|
17
|
+
*/
|
|
18
|
+
private getOutBindTypes;
|
|
13
19
|
/** @inheritDoc */
|
|
14
20
|
getORMClass(): Constructor<OracleMikroORM>;
|
|
15
21
|
}
|
package/OracleDriver.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isRaw, QueryFlag, Utils, } from '@mikro-orm/core';
|
|
1
|
+
import { isRaw, QueryFlag, ReferenceKind, Utils, } from '@mikro-orm/core';
|
|
2
2
|
import { AbstractSqlDriver } from '@mikro-orm/sql';
|
|
3
3
|
import { OracleConnection } from './OracleConnection.js';
|
|
4
4
|
import { OracleMikroORM } from './OracleMikroORM.js';
|
|
@@ -32,7 +32,7 @@ export class OracleDriver extends AbstractSqlDriver {
|
|
|
32
32
|
let pk;
|
|
33
33
|
if (pks.length > 1) {
|
|
34
34
|
// owner has composite pk
|
|
35
|
-
pk = data.map(d => Utils.
|
|
35
|
+
pk = data.map(d => Utils.getOrderedPrimaryKeys(d, meta));
|
|
36
36
|
}
|
|
37
37
|
else {
|
|
38
38
|
res.row ??= {};
|
|
@@ -61,8 +61,12 @@ export class OracleDriver extends AbstractSqlDriver {
|
|
|
61
61
|
meta.props.filter(prop => prop.generated || prop.version || prop.primary).forEach(prop => returning.add(prop.name));
|
|
62
62
|
for (const propName of returning) {
|
|
63
63
|
const prop = meta.properties[propName];
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
// the parent builds the `returning` list from all field names, so every column needs its own OUT bind
|
|
65
|
+
const runtimeTypes = this.getOutBindTypes(prop);
|
|
66
|
+
prop.fieldNames.forEach((fieldName, idx) => {
|
|
67
|
+
into.push(`:out_${fieldName}`);
|
|
68
|
+
outBindingsMap[`out_${fieldName}`] = runtimeTypes[idx];
|
|
69
|
+
});
|
|
66
70
|
}
|
|
67
71
|
const outBindings = this.platform.createOutBindings(outBindingsMap);
|
|
68
72
|
return super.nativeUpdateMany(entityName, where, data, options, (sql, params) => {
|
|
@@ -74,6 +78,19 @@ export class OracleDriver extends AbstractSqlDriver {
|
|
|
74
78
|
return `${sql} into ${into.join(', ')}`;
|
|
75
79
|
});
|
|
76
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolves the runtime type of every column a property maps to, aligned with its `fieldNames`.
|
|
83
|
+
* A relation covers one column per target PK column, and a target PK can be a relation itself,
|
|
84
|
+
* so we recurse down to the scalar leaves - `prop.runtimeType` is `unknown` for relations.
|
|
85
|
+
*/
|
|
86
|
+
getOutBindTypes(prop) {
|
|
87
|
+
if (!prop.targetMeta || ![ReferenceKind.MANY_TO_ONE, ReferenceKind.ONE_TO_ONE].includes(prop.kind)) {
|
|
88
|
+
return prop.fieldNames.map(() => prop.runtimeType);
|
|
89
|
+
}
|
|
90
|
+
const types = prop.referencedPKs.flatMap(pk => this.getOutBindTypes(prop.targetMeta.properties[pk]));
|
|
91
|
+
// `fieldNames` of a polymorphic relation start with the discriminator column
|
|
92
|
+
return prop.polymorphic ? ['string', ...types] : types;
|
|
93
|
+
}
|
|
77
94
|
/** @inheritDoc */
|
|
78
95
|
getORMClass() {
|
|
79
96
|
return OracleMikroORM;
|
|
@@ -11,7 +11,13 @@ export declare class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
11
11
|
/**
|
|
12
12
|
* creates new database and connects to it
|
|
13
13
|
*/
|
|
14
|
-
createDatabase(name?: string
|
|
14
|
+
createDatabase(name?: string, options?: {
|
|
15
|
+
skipOnConnect?: boolean;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Drops the user representing the database. When dropping the user we are connected as, we stay
|
|
19
|
+
* connected as the management user, as the dropped one can no longer authenticate.
|
|
20
|
+
*/
|
|
15
21
|
dropDatabase(name?: string): Promise<void>;
|
|
16
22
|
/**
|
|
17
23
|
* Oracle uses CASCADE CONSTRAINT in DROP TABLE and has no native enums,
|
package/OracleSchemaGenerator.js
CHANGED
|
@@ -9,7 +9,7 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
9
9
|
/**
|
|
10
10
|
* creates new database and connects to it
|
|
11
11
|
*/
|
|
12
|
-
async createDatabase(name) {
|
|
12
|
+
async createDatabase(name, options) {
|
|
13
13
|
name ??= this.config.get('user');
|
|
14
14
|
/* v8 ignore next: tableSpace fallback */
|
|
15
15
|
const tableSpace = this.config.get('schemaGenerator').tableSpace ?? 'mikro_orm';
|
|
@@ -31,14 +31,24 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
31
31
|
await this.execute(sql);
|
|
32
32
|
await this.execute(`grant connect, resource to ${this.platform.quoteIdentifier(name)}`);
|
|
33
33
|
this.config.set('user', name);
|
|
34
|
-
await this.driver.reconnect();
|
|
34
|
+
await this.driver.reconnect(options);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Drops the user representing the database. When dropping the user we are connected as, we stay
|
|
38
|
+
* connected as the management user, as the dropped one can no longer authenticate.
|
|
39
|
+
*/
|
|
36
40
|
async dropDatabase(name) {
|
|
37
41
|
name ??= this.config.get('dbName');
|
|
42
|
+
const originalUser = this.getOriginalUser();
|
|
38
43
|
this.config.set('user', this.helper.getManagementDbName());
|
|
39
|
-
await this.driver.reconnect();
|
|
44
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
40
45
|
await this.execute(this.helper.getDropDatabaseSQL(name));
|
|
41
|
-
|
|
46
|
+
// the dropped user is gone, so a cached `ensureDatabase` result for it is stale
|
|
47
|
+
this.lastEnsuredDatabase = undefined;
|
|
48
|
+
if (originalUser !== name) {
|
|
49
|
+
this.config.set('user', originalUser);
|
|
50
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
51
|
+
}
|
|
42
52
|
}
|
|
43
53
|
/**
|
|
44
54
|
* Oracle uses CASCADE CONSTRAINT in DROP TABLE and has no native enums,
|
|
@@ -78,14 +88,14 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
78
88
|
catch (e) {
|
|
79
89
|
if (e.code === 'ORA-01017' && this.config.get('user') !== this.helper.getManagementDbName()) {
|
|
80
90
|
this.config.set('user', this.helper.getManagementDbName());
|
|
81
|
-
await this.driver.reconnect();
|
|
91
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
82
92
|
const result = await this.ensureDatabase();
|
|
83
93
|
// Restore connection to the original user (createDatabase does this
|
|
84
94
|
// when the user doesn't exist, but we must handle the case where
|
|
85
95
|
// the user already exists and ensureDatabase returned early)
|
|
86
96
|
if (this.config.get('user') !== dbName) {
|
|
87
97
|
this.config.set('user', dbName);
|
|
88
|
-
await this.driver.reconnect();
|
|
98
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
89
99
|
}
|
|
90
100
|
return result;
|
|
91
101
|
}
|
|
@@ -94,8 +104,8 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
94
104
|
this.lastEnsuredDatabase = dbName;
|
|
95
105
|
if (!exists) {
|
|
96
106
|
this.config.set('user', this.helper.getManagementDbName());
|
|
97
|
-
await this.driver.reconnect();
|
|
98
|
-
await this.createDatabase(dbName);
|
|
107
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
108
|
+
await this.createDatabase(dbName, { skipOnConnect: true });
|
|
99
109
|
if (options?.create) {
|
|
100
110
|
await this.create(options);
|
|
101
111
|
}
|
|
@@ -125,7 +135,7 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
125
135
|
}
|
|
126
136
|
const originalUser = this.getOriginalUser();
|
|
127
137
|
this.config.set('user', this.helper.getManagementDbName());
|
|
128
|
-
await this.driver.reconnect();
|
|
138
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
129
139
|
return originalUser;
|
|
130
140
|
}
|
|
131
141
|
/**
|
|
@@ -136,7 +146,7 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
136
146
|
return;
|
|
137
147
|
}
|
|
138
148
|
this.config.set('user', originalUser);
|
|
139
|
-
await this.driver.reconnect();
|
|
149
|
+
await this.driver.reconnect({ skipOnConnect: true });
|
|
140
150
|
}
|
|
141
151
|
/**
|
|
142
152
|
* Grants DBA (or fallback individual privileges) to the main user.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/oracledb",
|
|
3
|
-
"version": "7.2.0-dev.
|
|
3
|
+
"version": "7.2.0-dev.4",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL, SQLite, MSSQL and Oracle databases.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"data-mapper",
|
|
@@ -42,15 +42,15 @@
|
|
|
42
42
|
"copy": "node ../../scripts/copy.mjs"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@mikro-orm/sql": "7.2.0-dev.
|
|
45
|
+
"@mikro-orm/sql": "7.2.0-dev.4",
|
|
46
46
|
"kysely": "0.29.4",
|
|
47
47
|
"oracledb": "7.0.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@mikro-orm/core": "^7.1.
|
|
50
|
+
"@mikro-orm/core": "^7.1.11"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@mikro-orm/core": "7.2.0-dev.
|
|
53
|
+
"@mikro-orm/core": "7.2.0-dev.4"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">= 22.17.0"
|