@mikro-orm/oracledb 7.1.0-dev.9 → 7.1.1-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/OracleConnection.d.ts +10 -1
- package/OracleConnection.js +117 -6
- package/OracleMikroORM.d.ts +3 -3
- package/OracleMikroORM.js +3 -2
- package/OraclePlatform.d.ts +2 -0
- package/OraclePlatform.js +7 -1
- package/OracleSchemaGenerator.js +4 -0
- package/OracleSchemaHelper.d.ts +19 -1
- package/OracleSchemaHelper.js +189 -8
- package/README.md +2 -1
- package/index.d.ts +4 -0
- package/index.js +2 -0
- package/package.json +5 -5
package/OracleConnection.d.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { AbstractSqlConnection, type AnyEntity, type EntityData, type LoggingOptions, NativeQueryBuilder, OracleDialect, type QueryResult, type RawQueryFragment, type Transaction } from '@mikro-orm/sql';
|
|
2
|
+
import type { Routine } from '@mikro-orm/core';
|
|
2
3
|
import { type PoolAttributes } from 'oracledb';
|
|
3
|
-
/** Oracle database connection using the `oracledb` driver. */
|
|
4
4
|
export declare class OracleConnection extends AbstractSqlConnection {
|
|
5
|
+
private oraclePool?;
|
|
6
|
+
private acquireOracleConnection?;
|
|
5
7
|
createKyselyDialect(overrides: PoolAttributes): Promise<OracleDialect>;
|
|
6
8
|
mapOptions(overrides: PoolAttributes): PoolAttributes;
|
|
7
9
|
execute<T extends QueryResult | EntityData<AnyEntity> | EntityData<AnyEntity>[] = EntityData<AnyEntity>[]>(query: string | NativeQueryBuilder | RawQueryFragment, params?: readonly unknown[], method?: 'all' | 'get' | 'run', ctx?: Transaction, loggerContext?: LoggingOptions): Promise<T>;
|
|
8
10
|
/** @inheritDoc */
|
|
9
11
|
executeDump(dump: string): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Oracle routines acquire their own pool connection with `autoCommit: true` (refcursor binds
|
|
14
|
+
* and DML need to resolve in one round-trip), so they cannot share the EM's transaction. Wrapping
|
|
15
|
+
* a writing routine in `em.transactional(...)` would silently auto-commit its writes. Read-only
|
|
16
|
+
* functions are allowed through.
|
|
17
|
+
*/
|
|
18
|
+
callRoutine<T>(routine: Routine, args?: Record<string, unknown>, ctx?: Transaction): Promise<T>;
|
|
10
19
|
private stripTrailingSemicolon;
|
|
11
20
|
protected transformRawResult<T>(res: any, method: 'all' | 'get' | 'run'): T;
|
|
12
21
|
}
|
package/OracleConnection.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import { AbstractSqlConnection, isRaw, NativeQueryBuilder, OracleDialect, Utils, } from '@mikro-orm/sql';
|
|
2
2
|
import { CompiledQuery } from 'kysely';
|
|
3
3
|
import oracledb from 'oracledb';
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Maps a routine's declared runtime type to an oracledb bind descriptor. Delegates the
|
|
6
|
+
* runtime → DB_TYPE mapping to `OraclePlatform.mapToOracleType`; only the VARCHAR/RAW out-binds
|
|
7
|
+
* need an extra `maxSize` hint.
|
|
8
|
+
*/
|
|
9
|
+
function oracleBindTypeFromRuntime(platform, runtime) {
|
|
10
|
+
const type = platform.mapToOracleType(runtime ?? 'string');
|
|
11
|
+
return type === oracledb.DB_TYPE_VARCHAR || type === oracledb.DB_TYPE_RAW ? { type, maxSize: 4000 } : { type };
|
|
12
|
+
}
|
|
13
|
+
function oracleReturnBind(platform, routine) {
|
|
14
|
+
const returns = routine.returns;
|
|
15
|
+
const runtime = returns && typeof returns === 'object' && 'runtimeType' in returns ? returns.runtimeType : undefined;
|
|
16
|
+
return { dir: oracledb.BIND_OUT, ...oracleBindTypeFromRuntime(platform, runtime) };
|
|
17
|
+
}
|
|
18
|
+
/** Read-only functions can run on a separate Oracle connection inside an EM transaction — write-ish routines would silently auto-commit. */
|
|
19
|
+
function isReadOnlyRoutine(routine) {
|
|
20
|
+
if (routine.type !== 'function') {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
return routine.dataAccess === 'no-sql' || routine.dataAccess === 'reads-sql-data';
|
|
24
|
+
}
|
|
5
25
|
export class OracleConnection extends AbstractSqlConnection {
|
|
26
|
+
oraclePool;
|
|
27
|
+
// Resolves `password` callbacks per acquire so `callRoutine` doesn't bypass password rotation.
|
|
28
|
+
acquireOracleConnection;
|
|
6
29
|
async createKyselyDialect(overrides) {
|
|
7
30
|
const options = this.mapOptions(overrides);
|
|
8
31
|
const password = options.password;
|
|
@@ -19,6 +42,7 @@ export class OracleConnection extends AbstractSqlConnection {
|
|
|
19
42
|
for (let attempt = 1;; attempt++) {
|
|
20
43
|
try {
|
|
21
44
|
pool = await oracledb.createPool(poolOptions);
|
|
45
|
+
this.oraclePool = pool;
|
|
22
46
|
break;
|
|
23
47
|
/* v8 ignore start: transient Oracle pool-creation errors are not reproducible in tests */
|
|
24
48
|
}
|
|
@@ -48,13 +72,13 @@ export class OracleConnection extends AbstractSqlConnection {
|
|
|
48
72
|
return undefined;
|
|
49
73
|
},
|
|
50
74
|
};
|
|
51
|
-
|
|
52
|
-
|
|
75
|
+
this.acquireOracleConnection =
|
|
76
|
+
typeof password === 'function'
|
|
77
|
+
? async () => pool.getConnection({ password: await password() })
|
|
78
|
+
: () => pool.getConnection();
|
|
53
79
|
const wrappedPool = typeof password === 'function'
|
|
54
80
|
? {
|
|
55
|
-
|
|
56
|
-
return pool.getConnection({ password: await password() });
|
|
57
|
-
},
|
|
81
|
+
getConnection: this.acquireOracleConnection,
|
|
58
82
|
close: (drainTime) => pool.close(drainTime),
|
|
59
83
|
}
|
|
60
84
|
: pool;
|
|
@@ -133,6 +157,93 @@ export class OracleConnection extends AbstractSqlConnection {
|
|
|
133
157
|
}
|
|
134
158
|
}
|
|
135
159
|
}
|
|
160
|
+
/**
|
|
161
|
+
* Oracle routines acquire their own pool connection with `autoCommit: true` (refcursor binds
|
|
162
|
+
* and DML need to resolve in one round-trip), so they cannot share the EM's transaction. Wrapping
|
|
163
|
+
* a writing routine in `em.transactional(...)` would silently auto-commit its writes. Read-only
|
|
164
|
+
* functions are allowed through.
|
|
165
|
+
*/
|
|
166
|
+
async callRoutine(routine, args = {}, ctx) {
|
|
167
|
+
/* v8 ignore next 3 */
|
|
168
|
+
if (!this.oraclePool || !this.acquireOracleConnection) {
|
|
169
|
+
throw new Error('Oracle pool not initialised — call connect() before callRoutine().');
|
|
170
|
+
}
|
|
171
|
+
if (ctx && !isReadOnlyRoutine(routine)) {
|
|
172
|
+
throw new Error(`Routine ${routine.name} was invoked inside an EntityManager transaction, but Oracle's callRoutine runs on its own pool connection with autoCommit. Read-only functions are allowed through; for procedures or routines that may write, call em.callRoutine() outside em.transactional(), or mark the routine as 'dataAccess: \\'reads-sql-data\\'' / 'no-sql' if it really is read-only.`);
|
|
173
|
+
}
|
|
174
|
+
const name = routine.name.toUpperCase();
|
|
175
|
+
// Cross-schema needs an `OWNER.NAME` prefix; mirror the schema helper's quoting on both branches.
|
|
176
|
+
const quotedName = this.platform.quoteIdentifier(name);
|
|
177
|
+
/* v8 ignore next 3 — cross-schema invocation isn't reachable from the single-user test DB;
|
|
178
|
+
the qualified DDL path (createRoutine/dropRoutine) is covered by helpers.test.ts. */
|
|
179
|
+
const qualifiedName = routine.schema
|
|
180
|
+
? `${this.platform.quoteIdentifier(routine.schema.toUpperCase())}.${quotedName}`
|
|
181
|
+
: quotedName;
|
|
182
|
+
const oracleConn = await this.acquireOracleConnection();
|
|
183
|
+
try {
|
|
184
|
+
if (routine.type === 'function') {
|
|
185
|
+
const argList = routine.params.map(p => `:${p.name}`).join(', ');
|
|
186
|
+
const block = `BEGIN :mo_ret := ${qualifiedName}(${argList}); END;`;
|
|
187
|
+
const bindings = { mo_ret: oracleReturnBind(this.platform, routine) };
|
|
188
|
+
for (const p of routine.params) {
|
|
189
|
+
bindings[p.name] = {
|
|
190
|
+
dir: oracledb.BIND_IN,
|
|
191
|
+
val: this.convertRoutineInbound(args[p.name], p),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
const result = await oracleConn.execute(block, bindings, { autoCommit: true });
|
|
195
|
+
return this.convertRoutineOutbound(result.outBinds?.mo_ret, routine.returnCustomType);
|
|
196
|
+
}
|
|
197
|
+
const argList = routine.params.map(p => `:${p.name}`).join(', ');
|
|
198
|
+
const block = `BEGIN ${qualifiedName}(${argList}); END;`;
|
|
199
|
+
const bindings = {};
|
|
200
|
+
const refCursorParams = [];
|
|
201
|
+
for (const p of routine.params) {
|
|
202
|
+
const value = this.convertRoutineInbound(args[p.name], p);
|
|
203
|
+
const isRefCursor = typeof p.type === 'string' && /sys_refcursor|ref\s*cursor/i.test(p.type);
|
|
204
|
+
if (p.direction === 'in') {
|
|
205
|
+
bindings[p.name] = { dir: oracledb.BIND_IN, val: value };
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (isRefCursor) {
|
|
209
|
+
bindings[p.name] = { dir: oracledb.BIND_OUT, type: oracledb.DB_TYPE_CURSOR };
|
|
210
|
+
refCursorParams.push(p.name);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const binding = {
|
|
214
|
+
dir: p.direction === 'out' ? oracledb.BIND_OUT : oracledb.BIND_INOUT,
|
|
215
|
+
...oracleBindTypeFromRuntime(this.platform, p.runtimeType),
|
|
216
|
+
};
|
|
217
|
+
if (p.direction === 'inout') {
|
|
218
|
+
binding.val = value;
|
|
219
|
+
}
|
|
220
|
+
bindings[p.name] = binding;
|
|
221
|
+
}
|
|
222
|
+
const result = await oracleConn.execute(block, bindings, {
|
|
223
|
+
autoCommit: true,
|
|
224
|
+
outFormat: oracledb.OUT_FORMAT_OBJECT,
|
|
225
|
+
});
|
|
226
|
+
const outBinds = result.outBinds;
|
|
227
|
+
if (refCursorParams.length > 0 && outBinds) {
|
|
228
|
+
const sets = [];
|
|
229
|
+
for (const name of refCursorParams) {
|
|
230
|
+
const cursor = outBinds[name];
|
|
231
|
+
const rows = await cursor.getRows(0);
|
|
232
|
+
await cursor.close();
|
|
233
|
+
// outBinds ResultSets use raw column metadata (uppercase); lowercase for cross-driver parity.
|
|
234
|
+
sets.push(rows.map(row => Object.fromEntries(Object.entries(row).map(([k, v]) => [k.toLowerCase(), v]))));
|
|
235
|
+
}
|
|
236
|
+
return sets;
|
|
237
|
+
}
|
|
238
|
+
if (outBinds) {
|
|
239
|
+
this.applyRoutineOutParams(outBinds, routine.params.filter(p => p.direction !== 'in'), args);
|
|
240
|
+
}
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
finally {
|
|
244
|
+
await oracleConn.close();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
136
247
|
stripTrailingSemicolon(sql) {
|
|
137
248
|
if (sql.endsWith(';') && !/end(\s+\w+)?;$/i.test(sql)) {
|
|
138
249
|
return sql.slice(0, -1);
|
package/OracleMikroORM.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType, type EntityClass, type AnyEntity, type EntitySchema } from '@mikro-orm/core';
|
|
2
|
-
import type
|
|
1
|
+
import { type MikroORM, type Options, type IDatabaseDriver, type EntityManager, type EntityManagerType, type EntityClass, type AnyEntity, type EntitySchema } from '@mikro-orm/core';
|
|
2
|
+
import { SqlMikroORM, type SqlEntityManager } from '@mikro-orm/sql';
|
|
3
3
|
import { OracleDriver } from './OracleDriver.js';
|
|
4
4
|
/** Configuration options for the Oracle driver. */
|
|
5
5
|
export type OracleOptions<EM extends SqlEntityManager<OracleDriver> = SqlEntityManager<OracleDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> = Partial<Options<OracleDriver, EM, Entities>>;
|
|
@@ -8,7 +8,7 @@ export declare function defineOracleConfig<EM extends SqlEntityManager<OracleDri
|
|
|
8
8
|
/**
|
|
9
9
|
* @inheritDoc
|
|
10
10
|
*/
|
|
11
|
-
export declare class OracleMikroORM<EM extends SqlEntityManager<OracleDriver> = SqlEntityManager<OracleDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends
|
|
11
|
+
export declare class OracleMikroORM<EM extends SqlEntityManager<OracleDriver> = SqlEntityManager<OracleDriver>, Entities extends readonly (string | EntityClass<AnyEntity> | EntitySchema)[] = (string | EntityClass<AnyEntity> | EntitySchema)[]> extends SqlMikroORM<OracleDriver, EM, Entities> {
|
|
12
12
|
/**
|
|
13
13
|
* @inheritDoc
|
|
14
14
|
*/
|
package/OracleMikroORM.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { defineConfig,
|
|
1
|
+
import { defineConfig, } from '@mikro-orm/core';
|
|
2
|
+
import { SqlMikroORM } from '@mikro-orm/sql';
|
|
2
3
|
import { OracleDriver } from './OracleDriver.js';
|
|
3
4
|
/** Creates a type-safe configuration object for the Oracle driver. */
|
|
4
5
|
export function defineOracleConfig(options) {
|
|
@@ -7,7 +8,7 @@ export function defineOracleConfig(options) {
|
|
|
7
8
|
/**
|
|
8
9
|
* @inheritDoc
|
|
9
10
|
*/
|
|
10
|
-
export class OracleMikroORM extends
|
|
11
|
+
export class OracleMikroORM extends SqlMikroORM {
|
|
11
12
|
/**
|
|
12
13
|
* @inheritDoc
|
|
13
14
|
*/
|
package/OraclePlatform.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export declare class OraclePlatform extends AbstractSqlPlatform {
|
|
|
16
16
|
readOnly?: boolean;
|
|
17
17
|
}): string[];
|
|
18
18
|
usesAsKeyword(): boolean;
|
|
19
|
+
/** Oracle 12.2+ identifier limit (pre-12.2 is 30 chars). */
|
|
20
|
+
getMaxIdentifierLength(): number;
|
|
19
21
|
compareUuids(): string;
|
|
20
22
|
convertUuidToJSValue(value: Buffer): string;
|
|
21
23
|
convertUuidToDatabaseValue(value: string): Buffer;
|
package/OraclePlatform.js
CHANGED
|
@@ -3,6 +3,8 @@ import oracledb from 'oracledb';
|
|
|
3
3
|
import { OracleSchemaHelper } from './OracleSchemaHelper.js';
|
|
4
4
|
import { OracleExceptionConverter } from './OracleExceptionConverter.js';
|
|
5
5
|
import { OracleSchemaGenerator } from './OracleSchemaGenerator.js';
|
|
6
|
+
// `bigint` deliberately absent — falls through to DB_TYPE_VARCHAR so oracledb returns a
|
|
7
|
+
// string and the caller doesn't lose precision on values past Number.MAX_SAFE_INTEGER.
|
|
6
8
|
const ORACLE_TYPE_MAP = {
|
|
7
9
|
string: oracledb.DB_TYPE_VARCHAR,
|
|
8
10
|
number: oracledb.DB_TYPE_NUMBER,
|
|
@@ -48,6 +50,10 @@ export class OraclePlatform extends AbstractSqlPlatform {
|
|
|
48
50
|
usesAsKeyword() {
|
|
49
51
|
return false;
|
|
50
52
|
}
|
|
53
|
+
/** Oracle 12.2+ identifier limit (pre-12.2 is 30 chars). */
|
|
54
|
+
getMaxIdentifierLength() {
|
|
55
|
+
return 128;
|
|
56
|
+
}
|
|
51
57
|
compareUuids() {
|
|
52
58
|
return 'any';
|
|
53
59
|
}
|
|
@@ -203,7 +209,7 @@ export class OraclePlatform extends AbstractSqlPlatform {
|
|
|
203
209
|
if (b.length === 0) {
|
|
204
210
|
return raw(`json_equal(${root}, json(?))`, [value]);
|
|
205
211
|
}
|
|
206
|
-
return raw(`json_value(${root},
|
|
212
|
+
return raw(`json_value(${root}, ${this.quoteValue(`$.${b.map(this.quoteJsonKey).join('.')}`)})`);
|
|
207
213
|
}
|
|
208
214
|
processJsonCondition(o, value, path, alias) {
|
|
209
215
|
if (Utils.isPlainObject(value) && !Object.keys(value).some(k => Utils.isOperator(k))) {
|
package/OracleSchemaGenerator.js
CHANGED
|
@@ -48,6 +48,10 @@ export class OracleSchemaGenerator extends SchemaGenerator {
|
|
|
48
48
|
await this.ensureDatabase();
|
|
49
49
|
const metadata = this.getOrderedMetadata(options.schema).reverse();
|
|
50
50
|
const ret = [];
|
|
51
|
+
// Routines before tables — bodies reference columns and Oracle has no CASCADE for them.
|
|
52
|
+
for (const routine of this.getTargetSchema(options.schema).getRoutines()) {
|
|
53
|
+
this.helper.append(ret, this.helper.dropRoutine(routine), true);
|
|
54
|
+
}
|
|
51
55
|
for (const meta of metadata) {
|
|
52
56
|
const schemaName = options.schema ?? this.config.get('schema');
|
|
53
57
|
/* v8 ignore next: wildcard schema branch */
|
package/OracleSchemaHelper.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import { type AbstractSqlConnection, type CheckDef, type Column, type DatabaseSchema, type DatabaseTable, type Dictionary, type ForeignKey, type IndexDef, SchemaHelper, type Table, type TableDifference, type Transaction, type Type } from '@mikro-orm/sql';
|
|
1
|
+
import { type AbstractSqlConnection, type CheckDef, type Column, type DatabaseSchema, type DatabaseTable, type Dictionary, type ForeignKey, type IndexDef, SchemaHelper, type Table, type TableDifference, type Transaction, type Type, type SqlRoutineDef } from '@mikro-orm/sql';
|
|
2
2
|
/** Schema introspection helper for Oracle Database. */
|
|
3
3
|
export declare class OracleSchemaHelper extends SchemaHelper {
|
|
4
4
|
static readonly DEFAULT_VALUES: Record<string, string[]>;
|
|
5
|
+
private static readonly AUTO_NOT_NULL_RE;
|
|
6
|
+
private static readonly PARTIAL_INDEX_RE;
|
|
5
7
|
getDatabaseExistsSQL(name: string): string;
|
|
8
|
+
getSetSchemaSQL(schema: string): string;
|
|
9
|
+
getResetSchemaSQL(defaultSchema: string): string;
|
|
10
|
+
supportsMigrationSchema(): boolean;
|
|
11
|
+
tableExists(connection: AbstractSqlConnection, tableName: string, schemaName: string | undefined, ctx?: Transaction): Promise<boolean>;
|
|
6
12
|
getAllTables(connection: AbstractSqlConnection, schemas?: string[], ctx?: Transaction): Promise<Table[]>;
|
|
7
13
|
getListTablesSQL(schemaName?: string): string;
|
|
8
14
|
getListViewsSQL(): string;
|
|
@@ -19,6 +25,7 @@ export declare class OracleSchemaHelper extends SchemaHelper {
|
|
|
19
25
|
private getEnumDefinitions;
|
|
20
26
|
private getChecksSQL;
|
|
21
27
|
getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, ctx?: Transaction): Promise<Dictionary<CheckDef[]>>;
|
|
28
|
+
getDatabaseCollation(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string | undefined>;
|
|
22
29
|
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
|
|
23
30
|
getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
24
31
|
getPostAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
@@ -35,6 +42,9 @@ export declare class OracleSchemaHelper extends SchemaHelper {
|
|
|
35
42
|
createTableColumn(column: Column, table: DatabaseTable, changedProperties?: Set<string>): string | undefined;
|
|
36
43
|
alterTableColumn(column: Column, table: DatabaseTable, changedProperties: Set<string>): string[];
|
|
37
44
|
getCreateIndexSQL(tableName: string, index: IndexDef, partialExpression?: boolean): string;
|
|
45
|
+
protected getIndexColumns(index: IndexDef): string;
|
|
46
|
+
/** Oracle has no native WHERE clause for indexes; the predicate is folded into CASE-WHEN columns. */
|
|
47
|
+
protected getIndexWhereClause(_index: IndexDef): string;
|
|
38
48
|
createIndex(index: IndexDef, table: DatabaseTable, createPrimary?: boolean): string;
|
|
39
49
|
dropForeignKey(tableName: string, constraintName: string): string;
|
|
40
50
|
dropViewIfExists(name: string, schema?: string): string;
|
|
@@ -43,4 +53,12 @@ export declare class OracleSchemaHelper extends SchemaHelper {
|
|
|
43
53
|
appendComments(table: DatabaseTable): string[];
|
|
44
54
|
inferLengthFromColumnType(type: string): number | undefined;
|
|
45
55
|
protected wrap(val: string | undefined, type: Type<unknown>): string | undefined;
|
|
56
|
+
/** Oracle identifiers are upper-cased before quoting to match `USER_PROCEDURES` introspection. Cross-schema qualifier mirrors `OracleConnection.callRoutine`. */
|
|
57
|
+
private qualifiedOracleRoutineName;
|
|
58
|
+
createRoutine(routine: SqlRoutineDef): string;
|
|
59
|
+
/** Uses `IF EXISTS` (Oracle 23c+); older versions can extend this helper. */
|
|
60
|
+
dropRoutine(routine: SqlRoutineDef): string;
|
|
61
|
+
getAllRoutines(connection: AbstractSqlConnection): Promise<SqlRoutineDef[]>;
|
|
62
|
+
private getAllRoutineParams;
|
|
63
|
+
private unwrapPlSqlBody;
|
|
46
64
|
}
|
package/OracleSchemaHelper.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { DateTimeType, EnumType, SchemaHelper, StringType, TextType, Utils, } from '@mikro-orm/sql';
|
|
2
|
+
function stripTypeLength(type) {
|
|
3
|
+
return type.replace(/\(\s*[^)]*\)\s*$/, '').trim();
|
|
4
|
+
}
|
|
2
5
|
/** Schema introspection helper for Oracle Database. */
|
|
3
6
|
export class OracleSchemaHelper extends SchemaHelper {
|
|
4
7
|
static DEFAULT_VALUES = {
|
|
@@ -7,9 +10,29 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
7
10
|
systimestamp: ['current_timestamp'],
|
|
8
11
|
sysdate: ['current_timestamp'],
|
|
9
12
|
};
|
|
13
|
+
// `stripAutoNotNullFilter` unwraps balanced per-clause parens before calling `.exec`, so we
|
|
14
|
+
// only need to match the bare form here.
|
|
15
|
+
static AUTO_NOT_NULL_RE = /^"?([^"\s()]+)"?\s+is\s+not\s+null$/i;
|
|
16
|
+
// Greedy `(.+)` so nested CASE expressions inside the predicate don't trip the match on
|
|
17
|
+
// an inner `then <col> end`.
|
|
18
|
+
static PARTIAL_INDEX_RE = /^\s*\(?\s*case\s+when\s+(.+)\s+then\s+"?([^"\s)]+)"?\s+end\s*\)?\s*$/is;
|
|
10
19
|
getDatabaseExistsSQL(name) {
|
|
11
20
|
return `select 1 from all_users where username = ${this.platform.quoteValue(name)}`;
|
|
12
21
|
}
|
|
22
|
+
getSetSchemaSQL(schema) {
|
|
23
|
+
return `alter session set current_schema = ${this.quote(schema)}`;
|
|
24
|
+
}
|
|
25
|
+
getResetSchemaSQL(defaultSchema) {
|
|
26
|
+
return `alter session set current_schema = ${this.quote(defaultSchema)}`;
|
|
27
|
+
}
|
|
28
|
+
supportsMigrationSchema() {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
async tableExists(connection, tableName, schemaName, ctx) {
|
|
32
|
+
const schema = schemaName ?? this.platform.getDefaultSchemaName();
|
|
33
|
+
const rows = await connection.execute(`select 1 from all_tables where owner = ${this.platform.quoteValue(schema)} and table_name = ${this.platform.quoteValue(tableName)}`, [], 'all', ctx);
|
|
34
|
+
return rows.length > 0;
|
|
35
|
+
}
|
|
13
36
|
async getAllTables(connection, schemas, ctx) {
|
|
14
37
|
if (!schemas || schemas.length === 0) {
|
|
15
38
|
return connection.execute(this.getListTablesSQL(), [], 'all', ctx);
|
|
@@ -121,7 +144,8 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
121
144
|
atc.char_length as character_maximum_length,
|
|
122
145
|
atc.data_length as data_length,
|
|
123
146
|
atc.identity_column as is_identity,
|
|
124
|
-
atc.column_id as ordinal_position
|
|
147
|
+
atc.column_id as ordinal_position,
|
|
148
|
+
atc.collation as collation_name
|
|
125
149
|
from all_tab_cols atc
|
|
126
150
|
left join all_col_comments acc on atc.owner = acc.owner and atc.table_name = acc.table_name and atc.column_name = acc.column_name
|
|
127
151
|
where atc.hidden_column = 'NO'
|
|
@@ -177,6 +201,11 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
177
201
|
precision: col.numeric_precision,
|
|
178
202
|
scale: col.numeric_scale,
|
|
179
203
|
comment: col.column_comment,
|
|
204
|
+
// `USING_NLS_COMP` is the Oracle sentinel for "inherit from the session NLS settings", so
|
|
205
|
+
// a column without an explicit `COLLATE` clause introspects as `USING_NLS_COMP` rather
|
|
206
|
+
// than NULL. Treat it as "no explicit collation" so the comparator doesn't flag every
|
|
207
|
+
// string column as changed when the database default is something else (e.g. `BINARY`).
|
|
208
|
+
collation: col.collation_name && col.collation_name !== 'USING_NLS_COMP' ? col.collation_name : undefined,
|
|
180
209
|
generated,
|
|
181
210
|
});
|
|
182
211
|
}
|
|
@@ -210,16 +239,19 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
210
239
|
if (isPrimary) {
|
|
211
240
|
continue;
|
|
212
241
|
}
|
|
242
|
+
const partialMatch = typeof index.expression === 'string' ? OracleSchemaHelper.PARTIAL_INDEX_RE.exec(index.expression) : null;
|
|
213
243
|
const indexDef = {
|
|
214
|
-
columnNames: [index.column_name],
|
|
244
|
+
columnNames: [partialMatch ? partialMatch[2] : index.column_name],
|
|
215
245
|
keyName: index.index_name,
|
|
216
246
|
unique: index.is_unique === 'YES',
|
|
217
|
-
primary: false,
|
|
247
|
+
primary: false,
|
|
218
248
|
constraint: isConstraintIndex || index.is_unique === 'YES',
|
|
219
249
|
};
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
250
|
+
/* v8 ignore start: function-based (non-partial) index branches */
|
|
251
|
+
if (partialMatch) {
|
|
252
|
+
indexDef.where = partialMatch[1].trim();
|
|
253
|
+
}
|
|
254
|
+
else if (index.expression) {
|
|
223
255
|
indexDef.expression = index.expression;
|
|
224
256
|
}
|
|
225
257
|
else if (index.column_name?.match(/[(): ,"'`]/)) {
|
|
@@ -231,6 +263,17 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
231
263
|
}
|
|
232
264
|
for (const key of Object.keys(ret)) {
|
|
233
265
|
ret[key] = await this.mapIndexes(ret[key]);
|
|
266
|
+
for (const idx of ret[key]) {
|
|
267
|
+
if (idx.where) {
|
|
268
|
+
const stripped = this.stripAutoNotNullFilter(idx.where, idx.columnNames, OracleSchemaHelper.AUTO_NOT_NULL_RE);
|
|
269
|
+
if (stripped === '') {
|
|
270
|
+
delete idx.where;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
idx.where = stripped;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
234
277
|
}
|
|
235
278
|
return ret;
|
|
236
279
|
}
|
|
@@ -338,6 +381,10 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
338
381
|
}
|
|
339
382
|
return ret;
|
|
340
383
|
}
|
|
384
|
+
async getDatabaseCollation(connection, ctx) {
|
|
385
|
+
const [row] = await connection.execute(`select property_value as collation from database_properties where property_name = 'DEFAULT_COLLATION'`, [], 'all', ctx);
|
|
386
|
+
return row?.collation;
|
|
387
|
+
}
|
|
341
388
|
async loadInformationSchema(schema, connection, tables, schemas, ctx) {
|
|
342
389
|
if (tables.length === 0) {
|
|
343
390
|
return;
|
|
@@ -347,9 +394,11 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
347
394
|
const indexes = await this.getAllIndexes(connection, tablesBySchema, ctx);
|
|
348
395
|
const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
|
|
349
396
|
const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
|
|
397
|
+
const dbCollation = await this.getDatabaseCollation(connection, ctx);
|
|
350
398
|
for (const t of tables) {
|
|
351
399
|
const key = this.getTableKey(t);
|
|
352
400
|
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
401
|
+
table.collation = dbCollation;
|
|
353
402
|
const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
|
|
354
403
|
const enums = this.getEnumDefinitions(checks[key] ?? []);
|
|
355
404
|
table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
|
|
@@ -450,6 +499,7 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
450
499
|
/* v8 ignore next: generated column branch */
|
|
451
500
|
const columnType = column.generated ? `as ${column.generated}` : column.type;
|
|
452
501
|
const col = [this.quote(column.name), columnType];
|
|
502
|
+
Utils.runIfNotEmpty(() => col.push(this.getCollateSQL(column.collation)), column.collation);
|
|
453
503
|
Utils.runIfNotEmpty(() => col.push('generated by default as identity'), column.autoincrement);
|
|
454
504
|
/* v8 ignore next 3: default value branch */
|
|
455
505
|
const useDefault = changedProperties
|
|
@@ -473,8 +523,15 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
473
523
|
const parts = [];
|
|
474
524
|
const quotedTableName = table.getQuotedName();
|
|
475
525
|
// Oracle uses MODIFY for column changes, and always requires the column type
|
|
476
|
-
if (changedProperties.has('type') ||
|
|
526
|
+
if (changedProperties.has('type') ||
|
|
527
|
+
changedProperties.has('nullable') ||
|
|
528
|
+
changedProperties.has('default') ||
|
|
529
|
+
changedProperties.has('collation')) {
|
|
477
530
|
const colParts = [this.quote(column.name), column.type];
|
|
531
|
+
// Oracle's MODIFY restates the column type, so re-emit COLLATE whenever the column has
|
|
532
|
+
// one — even if the trigger was a nullable/default change — so we can't accidentally
|
|
533
|
+
// drop the column collation by omitting it from the new type spec.
|
|
534
|
+
Utils.runIfNotEmpty(() => colParts.push(this.getCollateSQL(column.collation)), column.collation);
|
|
478
535
|
if (changedProperties.has('default')) {
|
|
479
536
|
if (column.default != null && column.default !== 'null') {
|
|
480
537
|
colParts.push(`default ${column.default}`);
|
|
@@ -503,6 +560,16 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
503
560
|
}
|
|
504
561
|
return super.getCreateIndexSQL(tableName, index);
|
|
505
562
|
}
|
|
563
|
+
getIndexColumns(index) {
|
|
564
|
+
if (index.where) {
|
|
565
|
+
return this.emulatePartialIndexColumns(index);
|
|
566
|
+
}
|
|
567
|
+
return super.getIndexColumns(index);
|
|
568
|
+
}
|
|
569
|
+
/** Oracle has no native WHERE clause for indexes; the predicate is folded into CASE-WHEN columns. */
|
|
570
|
+
getIndexWhereClause(_index) {
|
|
571
|
+
return '';
|
|
572
|
+
}
|
|
506
573
|
createIndex(index, table, createPrimary = false) {
|
|
507
574
|
if (index.primary) {
|
|
508
575
|
return '';
|
|
@@ -524,10 +591,21 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
524
591
|
const quotedTableName = table.getQuotedName();
|
|
525
592
|
if (index.unique) {
|
|
526
593
|
const nullableCols = index.columnNames.filter(column => table.getColumn(column)?.nullable);
|
|
594
|
+
const autoNotNull = nullableCols.length
|
|
595
|
+
? nullableCols.map(c => `${this.quote(c)} is not null`).join(' and ')
|
|
596
|
+
: '';
|
|
597
|
+
if (index.where) {
|
|
598
|
+
// Wrap the user predicate in parens before ANDing the auto-NOT-NULL guard — otherwise a
|
|
599
|
+
// disjunctive `a = 1 or b = 2` would rebind as `a = 1 or (b = 2 and <col> is not null)`.
|
|
600
|
+
const predicate = autoNotNull ? `(${index.where}) and ${autoNotNull}` : index.where;
|
|
601
|
+
return `create unique index ${this.quote(index.keyName)} on ${quotedTableName} (${index.columnNames
|
|
602
|
+
.map(c => `case when ${predicate} then ${this.quote(c)} end`)
|
|
603
|
+
.join(', ')})`;
|
|
604
|
+
}
|
|
527
605
|
return `create unique index ${this.quote(index.keyName)} on ${quotedTableName} (${index.columnNames
|
|
528
606
|
.map(c => {
|
|
529
607
|
if (table.getColumn(c)?.nullable) {
|
|
530
|
-
return `case when ${
|
|
608
|
+
return `case when ${autoNotNull} then ${this.quote(c)} end`;
|
|
531
609
|
}
|
|
532
610
|
return this.quote(c);
|
|
533
611
|
})
|
|
@@ -589,4 +667,107 @@ export class OracleSchemaHelper extends SchemaHelper {
|
|
|
589
667
|
const stringType = type instanceof StringType || type instanceof TextType || type instanceof EnumType;
|
|
590
668
|
return typeof val === 'string' && val.length > 0 && stringType ? this.platform.quoteValue(val) : val;
|
|
591
669
|
}
|
|
670
|
+
/** Oracle identifiers are upper-cased before quoting to match `USER_PROCEDURES` introspection. Cross-schema qualifier mirrors `OracleConnection.callRoutine`. */
|
|
671
|
+
qualifiedOracleRoutineName(routine) {
|
|
672
|
+
const name = this.quote(routine.name.toUpperCase());
|
|
673
|
+
const defaultSchema = this.platform.getDefaultSchemaName();
|
|
674
|
+
if (routine.schema && routine.schema !== defaultSchema) {
|
|
675
|
+
return `${this.quote(routine.schema.toUpperCase())}.${name}`;
|
|
676
|
+
}
|
|
677
|
+
return name;
|
|
678
|
+
}
|
|
679
|
+
createRoutine(routine) {
|
|
680
|
+
if (routine.expression) {
|
|
681
|
+
return routine.expression;
|
|
682
|
+
}
|
|
683
|
+
const name = this.qualifiedOracleRoutineName(routine);
|
|
684
|
+
const params = routine.params
|
|
685
|
+
.map(p => {
|
|
686
|
+
const dir = p.direction === 'in' ? 'IN' : p.direction === 'out' ? 'OUT' : 'IN OUT';
|
|
687
|
+
// PL/SQL formal params require unconstrained types — `VARCHAR2`, not `VARCHAR2(255)`.
|
|
688
|
+
return `${this.quote(p.name.toUpperCase())} ${dir} ${stripTypeLength(p.type)}`;
|
|
689
|
+
})
|
|
690
|
+
.join(', ');
|
|
691
|
+
const argsClause = routine.params.length ? `(${params})` : '';
|
|
692
|
+
const body = this.wrapRoutineBody(routine.body ?? '');
|
|
693
|
+
if (routine.type === 'procedure') {
|
|
694
|
+
return `create or replace procedure ${name}${argsClause} as ${body};`;
|
|
695
|
+
}
|
|
696
|
+
const returnType = stripTypeLength(routine.returns?.type ?? 'VARCHAR2');
|
|
697
|
+
return `create or replace function ${name}${argsClause} return ${returnType} as ${body};`;
|
|
698
|
+
}
|
|
699
|
+
/** Uses `IF EXISTS` (Oracle 23c+); older versions can extend this helper. */
|
|
700
|
+
dropRoutine(routine) {
|
|
701
|
+
const kind = routine.type === 'procedure' ? 'procedure' : 'function';
|
|
702
|
+
return `drop ${kind} if exists ${this.qualifiedOracleRoutineName(routine)}`;
|
|
703
|
+
}
|
|
704
|
+
async getAllRoutines(connection) {
|
|
705
|
+
const sql = `
|
|
706
|
+
select
|
|
707
|
+
p.OBJECT_NAME as name,
|
|
708
|
+
p.OBJECT_TYPE as kind,
|
|
709
|
+
(
|
|
710
|
+
select listagg(s.TEXT, '') within group (order by s.LINE)
|
|
711
|
+
from USER_SOURCE s
|
|
712
|
+
where s.NAME = p.OBJECT_NAME and s.TYPE = p.OBJECT_TYPE
|
|
713
|
+
) as source
|
|
714
|
+
from USER_PROCEDURES p
|
|
715
|
+
where p.OBJECT_TYPE in ('PROCEDURE', 'FUNCTION')
|
|
716
|
+
and p.PROCEDURE_NAME is null
|
|
717
|
+
`;
|
|
718
|
+
const [rows, paramsAndReturns] = await Promise.all([
|
|
719
|
+
connection.execute(sql),
|
|
720
|
+
this.getAllRoutineParams(connection),
|
|
721
|
+
]);
|
|
722
|
+
const { params, returns } = paramsAndReturns;
|
|
723
|
+
// Surface the connected user as the schema so the comparator's routineKey matches the
|
|
724
|
+
// metadata side (which fills `schema` from `getDefaultSchemaName()` when not declared).
|
|
725
|
+
const schemaName = this.platform.getDefaultSchemaName();
|
|
726
|
+
return rows.map(row => ({
|
|
727
|
+
name: row.name,
|
|
728
|
+
schema: schemaName,
|
|
729
|
+
type: row.kind.toLowerCase(),
|
|
730
|
+
body: this.unwrapPlSqlBody(row.source ?? ''),
|
|
731
|
+
params: params.get(row.name) ?? [],
|
|
732
|
+
returns: row.kind === 'FUNCTION' ? (returns.get(row.name) ?? { type: 'VARCHAR2', nullable: true }) : undefined,
|
|
733
|
+
}));
|
|
734
|
+
}
|
|
735
|
+
async getAllRoutineParams(connection) {
|
|
736
|
+
// POSITION = 0 / ARGUMENT_NAME = NULL is the function return type; `PACKAGE_NAME is null`
|
|
737
|
+
// restricts to standalone routines so packaged ones don't leak through name collisions.
|
|
738
|
+
const sql = `
|
|
739
|
+
select
|
|
740
|
+
OBJECT_NAME as routine_name,
|
|
741
|
+
ARGUMENT_NAME as param_name,
|
|
742
|
+
DATA_TYPE as type,
|
|
743
|
+
IN_OUT as direction,
|
|
744
|
+
POSITION as position
|
|
745
|
+
from USER_ARGUMENTS
|
|
746
|
+
where PACKAGE_NAME is null
|
|
747
|
+
order by OBJECT_NAME, POSITION
|
|
748
|
+
`;
|
|
749
|
+
const rows = await connection.execute(sql);
|
|
750
|
+
const params = new Map();
|
|
751
|
+
const returns = new Map();
|
|
752
|
+
for (const row of rows) {
|
|
753
|
+
if (row.position === 0 && row.param_name == null) {
|
|
754
|
+
returns.set(row.routine_name, { type: row.type, nullable: true });
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
if (!params.has(row.routine_name)) {
|
|
758
|
+
params.set(row.routine_name, []);
|
|
759
|
+
}
|
|
760
|
+
const direction = row.direction === 'IN/OUT' ? 'inout' : row.direction === 'OUT' ? 'out' : 'in';
|
|
761
|
+
params.get(row.routine_name).push({
|
|
762
|
+
name: row.param_name,
|
|
763
|
+
type: row.type,
|
|
764
|
+
direction,
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
return { params, returns };
|
|
768
|
+
}
|
|
769
|
+
unwrapPlSqlBody(source) {
|
|
770
|
+
const match = /\b(?:as|is)\s+(?:begin\s+)?([\s\S]*?)\s*end\s*;?\s*$/i.exec(source.trim());
|
|
771
|
+
return match ? match[1].trim() : source.trim();
|
|
772
|
+
}
|
|
592
773
|
}
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
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, SQLite (including libSQL), MSSQL and Oracle databases.
|
|
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 (including CockroachDB and PGlite), 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
|
|
|
@@ -19,6 +19,7 @@ Install a driver package for your database:
|
|
|
19
19
|
|
|
20
20
|
```sh
|
|
21
21
|
npm install @mikro-orm/postgresql # PostgreSQL
|
|
22
|
+
npm install @mikro-orm/pglite # PGlite (embedded PostgreSQL in WASM)
|
|
22
23
|
npm install @mikro-orm/mysql # MySQL
|
|
23
24
|
npm install @mikro-orm/mariadb # MariaDB
|
|
24
25
|
npm install @mikro-orm/sqlite # SQLite
|
package/index.d.ts
CHANGED
|
@@ -8,3 +8,7 @@ export * from './OracleSchemaGenerator.js';
|
|
|
8
8
|
export * from './OracleExceptionConverter.js';
|
|
9
9
|
export type { OracleOptions as Options } from './OracleMikroORM.js';
|
|
10
10
|
export { OracleMikroORM as MikroORM, defineOracleConfig as defineConfig } from './OracleMikroORM.js';
|
|
11
|
+
import { type AbstractSqlDriver, SqlEntityManager } from '@mikro-orm/sql';
|
|
12
|
+
import type { OracleDriver } from './OracleDriver.js';
|
|
13
|
+
export type EntityManager<Driver extends AbstractSqlDriver = OracleDriver> = SqlEntityManager<Driver>;
|
|
14
|
+
export declare const EntityManager: typeof SqlEntityManager;
|
package/index.js
CHANGED
|
@@ -7,3 +7,5 @@ export * from './OracleSchemaHelper.js';
|
|
|
7
7
|
export * from './OracleSchemaGenerator.js';
|
|
8
8
|
export * from './OracleExceptionConverter.js';
|
|
9
9
|
export { OracleMikroORM as MikroORM, defineOracleConfig as defineConfig } from './OracleMikroORM.js';
|
|
10
|
+
import { SqlEntityManager } from '@mikro-orm/sql';
|
|
11
|
+
export const EntityManager = SqlEntityManager;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/oracledb",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.1-dev.0",
|
|
4
4
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, 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.1.
|
|
46
|
-
"kysely": "0.
|
|
45
|
+
"@mikro-orm/sql": "7.1.1-dev.0",
|
|
46
|
+
"kysely": "0.29.2",
|
|
47
47
|
"oracledb": "6.10.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@mikro-orm/core": "^7.0
|
|
50
|
+
"@mikro-orm/core": "^7.1.0"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@mikro-orm/core": "7.1.
|
|
53
|
+
"@mikro-orm/core": "7.1.1-dev.0"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|
|
56
56
|
"node": ">= 22.17.0"
|