@mikro-orm/sql 7.0.0-dev.312 → 7.0.0-dev.314
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/AbstractSqlConnection.d.ts +5 -4
- package/AbstractSqlConnection.js +18 -5
- package/AbstractSqlDriver.d.ts +1 -1
- package/AbstractSqlDriver.js +34 -5
- package/AbstractSqlPlatform.d.ts +6 -0
- package/AbstractSqlPlatform.js +8 -0
- package/README.md +2 -1
- package/dialects/index.d.ts +1 -0
- package/dialects/index.js +1 -0
- package/dialects/oracledb/OracleDialect.d.ts +78 -0
- package/dialects/oracledb/OracleDialect.js +166 -0
- package/dialects/oracledb/OracleNativeQueryBuilder.d.ts +19 -0
- package/dialects/oracledb/OracleNativeQueryBuilder.js +249 -0
- package/dialects/oracledb/index.d.ts +2 -0
- package/dialects/oracledb/index.js +2 -0
- package/dialects/postgresql/PostgreSqlSchemaHelper.js +3 -3
- package/package.json +2 -2
- package/query/NativeQueryBuilder.d.ts +3 -3
- package/query/NativeQueryBuilder.js +4 -2
- package/query/QueryBuilder.d.ts +2 -1
- package/query/QueryBuilder.js +36 -1
- package/query/QueryBuilderHelper.d.ts +0 -1
- package/query/QueryBuilderHelper.js +14 -39
- package/schema/SchemaComparator.js +3 -1
- package/schema/SchemaHelper.d.ts +1 -0
- package/schema/SchemaHelper.js +1 -0
- package/schema/SqlSchemaGenerator.d.ts +1 -0
- package/schema/SqlSchemaGenerator.js +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { type ControlledTransaction, type Dialect, Kysely } from 'kysely';
|
|
2
|
-
import { type AnyEntity, Connection, type Dictionary, type EntityData, type IsolationLevel, type LogContext, type LoggingOptions, type QueryResult, RawQueryFragment, type Transaction, type TransactionEventBroadcaster } from '@mikro-orm/core';
|
|
2
|
+
import { type AnyEntity, Connection, type Dictionary, type EntityData, type IsolationLevel, type LogContext, type LoggingOptions, type MaybePromise, type QueryResult, RawQueryFragment, type Transaction, type TransactionEventBroadcaster } from '@mikro-orm/core';
|
|
3
3
|
import type { AbstractSqlPlatform } from './AbstractSqlPlatform.js';
|
|
4
4
|
import { NativeQueryBuilder } from './query/NativeQueryBuilder.js';
|
|
5
5
|
export declare abstract class AbstractSqlConnection extends Connection {
|
|
6
6
|
#private;
|
|
7
7
|
protected platform: AbstractSqlPlatform;
|
|
8
|
-
abstract createKyselyDialect(overrides: Dictionary): Dialect
|
|
8
|
+
abstract createKyselyDialect(overrides: Dictionary): MaybePromise<Dialect>;
|
|
9
9
|
connect(options?: {
|
|
10
10
|
skipOnConnect?: boolean;
|
|
11
11
|
}): Promise<void>;
|
|
12
|
-
createKysely(): void
|
|
12
|
+
createKysely(): MaybePromise<void>;
|
|
13
13
|
/**
|
|
14
14
|
* @inheritDoc
|
|
15
15
|
*/
|
|
@@ -29,6 +29,7 @@ export declare abstract class AbstractSqlConnection extends Connection {
|
|
|
29
29
|
error?: Error;
|
|
30
30
|
}>;
|
|
31
31
|
getClient<T = any>(): Kysely<T>;
|
|
32
|
+
initClient(): Promise<void>;
|
|
32
33
|
transactional<T>(cb: (trx: Transaction<ControlledTransaction<any, any>>) => Promise<T>, options?: {
|
|
33
34
|
isolationLevel?: IsolationLevel;
|
|
34
35
|
readOnly?: boolean;
|
|
@@ -50,6 +51,6 @@ export declare abstract class AbstractSqlConnection extends Connection {
|
|
|
50
51
|
stream<T extends EntityData<AnyEntity>>(query: string | NativeQueryBuilder | RawQueryFragment, params?: readonly unknown[], ctx?: Transaction<Kysely<any>>, loggerContext?: LoggingOptions): AsyncIterableIterator<T>;
|
|
51
52
|
/** @inheritDoc */
|
|
52
53
|
executeDump(dump: string): Promise<void>;
|
|
53
|
-
|
|
54
|
+
protected getSql(query: string, formatted: string, context?: LogContext): string;
|
|
54
55
|
protected transformRawResult<T>(res: any, method?: 'all' | 'get' | 'run'): T;
|
|
55
56
|
}
|
package/AbstractSqlConnection.js
CHANGED
|
@@ -4,7 +4,7 @@ import { NativeQueryBuilder } from './query/NativeQueryBuilder.js';
|
|
|
4
4
|
export class AbstractSqlConnection extends Connection {
|
|
5
5
|
#client;
|
|
6
6
|
async connect(options) {
|
|
7
|
-
this.
|
|
7
|
+
await this.initClient();
|
|
8
8
|
this.connected = true;
|
|
9
9
|
if (options?.skipOnConnect !== true) {
|
|
10
10
|
await this.onConnect();
|
|
@@ -24,9 +24,13 @@ export class AbstractSqlConnection extends Connection {
|
|
|
24
24
|
this.#client = new Kysely({ dialect: driverOptions });
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const dialect = this.createKyselyDialect(driverOptions);
|
|
28
|
+
if (dialect instanceof Promise) {
|
|
29
|
+
return dialect.then(d => {
|
|
30
|
+
this.#client = new Kysely({ dialect: d });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
this.#client = new Kysely({ dialect });
|
|
30
34
|
}
|
|
31
35
|
}
|
|
32
36
|
/**
|
|
@@ -62,10 +66,19 @@ export class AbstractSqlConnection extends Connection {
|
|
|
62
66
|
}
|
|
63
67
|
getClient() {
|
|
64
68
|
if (!this.#client) {
|
|
65
|
-
this.createKysely();
|
|
69
|
+
const maybePromise = this.createKysely();
|
|
70
|
+
/* v8 ignore next */
|
|
71
|
+
if (maybePromise instanceof Promise) {
|
|
72
|
+
throw new Error('Current driver requires async initialization, use `MikroORM.init()` instead of the constructor');
|
|
73
|
+
}
|
|
66
74
|
}
|
|
67
75
|
return this.#client;
|
|
68
76
|
}
|
|
77
|
+
async initClient() {
|
|
78
|
+
if (!this.#client) {
|
|
79
|
+
await this.createKysely();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
69
82
|
async transactional(cb, options = {}) {
|
|
70
83
|
const trx = await this.begin(options);
|
|
71
84
|
try {
|
package/AbstractSqlDriver.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ export declare abstract class AbstractSqlDriver<Connection extends AbstractSqlCo
|
|
|
53
53
|
nativeInsert<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T>): Promise<QueryResult<T>>;
|
|
54
54
|
nativeInsertMany<T extends object>(entityName: EntityName<T>, data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T>, transform?: (sql: string) => string): Promise<QueryResult<T>>;
|
|
55
55
|
nativeUpdate<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>, data: EntityDictionary<T>, options?: NativeInsertUpdateOptions<T> & UpsertOptions<T>): Promise<QueryResult<T>>;
|
|
56
|
-
nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T
|
|
56
|
+
nativeUpdateMany<T extends object>(entityName: EntityName<T>, where: FilterQuery<T>[], data: EntityDictionary<T>[], options?: NativeInsertUpdateManyOptions<T> & UpsertManyOptions<T>, transform?: (sql: string, params: any[]) => string): Promise<QueryResult<T>>;
|
|
57
57
|
nativeDelete<T extends object>(entityName: EntityName<T>, where: FilterQuery<T> | string | any, options?: DeleteOptions<T>): Promise<QueryResult<T>>;
|
|
58
58
|
/**
|
|
59
59
|
* Fast comparison for collection snapshots that are represented by PK arrays.
|
package/AbstractSqlDriver.js
CHANGED
|
@@ -200,7 +200,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
200
200
|
if (type === QueryType.COUNT) {
|
|
201
201
|
native.clear('select').clear('limit').clear('offset').count();
|
|
202
202
|
}
|
|
203
|
-
|
|
203
|
+
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
|
|
204
|
+
native.from(raw(`(${expression})${asKeyword}${this.platform.quoteIdentifier(qb.alias)}`));
|
|
204
205
|
const query = native.compile();
|
|
205
206
|
const res = await this.execute(query.sql, query.params, 'all', options.ctx);
|
|
206
207
|
if (type === QueryType.COUNT) {
|
|
@@ -215,7 +216,8 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
215
216
|
const qb = await this.createQueryBuilderFromOptions(meta, where, this.forceBalancedStrategy(options));
|
|
216
217
|
qb.unsetFlag(QueryFlag.DISABLE_PAGINATE);
|
|
217
218
|
const native = qb.getNativeQuery(false);
|
|
218
|
-
|
|
219
|
+
const asKeyword = this.platform.usesAsKeyword() ? ' as ' : ' ';
|
|
220
|
+
native.from(raw(`(${expression})${asKeyword}${this.platform.quoteIdentifier(qb.alias)}`));
|
|
219
221
|
const query = native.compile();
|
|
220
222
|
const connectionType = this.resolveConnectionType({ ctx: options.ctx, connectionType: options.connectionType });
|
|
221
223
|
const res = this.getConnection(connectionType).stream(query.sql, query.params, options.ctx, options.loggerContext);
|
|
@@ -556,7 +558,12 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
556
558
|
else {
|
|
557
559
|
/* v8 ignore next */
|
|
558
560
|
res.insertId = data[meta.primaryKeys[0]] ?? res.insertId ?? res.row[meta.primaryKeys[0]];
|
|
559
|
-
|
|
561
|
+
if (options.convertCustomTypes && meta?.getPrimaryProp().customType) {
|
|
562
|
+
pk = [meta.getPrimaryProp().customType.convertToDatabaseValue(res.insertId, this.platform)];
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
pk = [res.insertId];
|
|
566
|
+
}
|
|
560
567
|
}
|
|
561
568
|
await this.processManyToMany(meta, pk, collections, false, options);
|
|
562
569
|
return res;
|
|
@@ -780,7 +787,7 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
780
787
|
await this.processManyToMany(meta, pk, collections, true, options);
|
|
781
788
|
return res;
|
|
782
789
|
}
|
|
783
|
-
async nativeUpdateMany(entityName, where, data, options = {}) {
|
|
790
|
+
async nativeUpdateMany(entityName, where, data, options = {}, transform) {
|
|
784
791
|
options.processCollections ??= true;
|
|
785
792
|
options.convertCustomTypes ??= true;
|
|
786
793
|
const meta = this.metadata.get(entityName);
|
|
@@ -923,6 +930,9 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
923
930
|
? ` returning ${returningFields.map(field => this.platform.quoteIdentifier(field)).join(', ')}`
|
|
924
931
|
: '';
|
|
925
932
|
}
|
|
933
|
+
if (transform) {
|
|
934
|
+
sql = transform(sql, params);
|
|
935
|
+
}
|
|
926
936
|
const res = await this.rethrow(this.execute(sql, params, 'run', options.ctx, options.loggerContext));
|
|
927
937
|
for (let i = 0; i < collections.length; i++) {
|
|
928
938
|
await this.processManyToMany(meta, where[i], collections[i], false, options);
|
|
@@ -1050,8 +1060,17 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1050
1060
|
const pivotProp1 = pivotMeta.relations[prop.owner ? 1 : 0];
|
|
1051
1061
|
const pivotProp2 = pivotMeta.relations[prop.owner ? 0 : 1];
|
|
1052
1062
|
const ownerMeta = pivotProp2.targetMeta;
|
|
1063
|
+
// The pivot query builder doesn't convert custom types, so we need to manually
|
|
1064
|
+
// convert owner PKs to DB format for the query and convert result FKs back to
|
|
1065
|
+
// JS format for consistent key hashing in buildPivotResultMap.
|
|
1066
|
+
const pkProp = ownerMeta.properties[ownerMeta.primaryKeys[0]];
|
|
1067
|
+
const needsConversion = pkProp?.customType?.ensureComparable(ownerMeta, pkProp) && !ownerMeta.compositePK;
|
|
1068
|
+
let ownerPks = ownerMeta.compositePK ? owners : owners.map(o => o[0]);
|
|
1069
|
+
if (needsConversion) {
|
|
1070
|
+
ownerPks = ownerPks.map(v => pkProp.customType.convertToDatabaseValue(v, this.platform, { mode: 'query' }));
|
|
1071
|
+
}
|
|
1053
1072
|
const cond = {
|
|
1054
|
-
[pivotProp2.name]: { $in:
|
|
1073
|
+
[pivotProp2.name]: { $in: ownerPks },
|
|
1055
1074
|
};
|
|
1056
1075
|
if (!Utils.isEmpty(where)) {
|
|
1057
1076
|
cond[pivotProp1.name] = { ...where };
|
|
@@ -1084,6 +1103,16 @@ export class AbstractSqlDriver extends DatabaseDriver {
|
|
|
1084
1103
|
_populateWhere: 'infer',
|
|
1085
1104
|
populateFilter: this.wrapPopulateFilter(options, pivotProp2.name),
|
|
1086
1105
|
});
|
|
1106
|
+
// Convert result FK values back to JS format so key hashing
|
|
1107
|
+
// in buildPivotResultMap is consistent with the owner keys.
|
|
1108
|
+
if (needsConversion) {
|
|
1109
|
+
for (const item of res) {
|
|
1110
|
+
const fk = item[pivotProp2.name];
|
|
1111
|
+
if (fk != null) {
|
|
1112
|
+
item[pivotProp2.name] = pkProp.customType.convertToJSValue(fk, this.platform);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1087
1116
|
return this.buildPivotResultMap(owners, res, pivotProp2.name, pivotProp1.name);
|
|
1088
1117
|
}
|
|
1089
1118
|
/**
|
package/AbstractSqlPlatform.d.ts
CHANGED
|
@@ -42,4 +42,10 @@ export declare abstract class AbstractSqlPlatform extends Platform {
|
|
|
42
42
|
quoteCollation(collation: string): string;
|
|
43
43
|
/** @internal */
|
|
44
44
|
protected validateCollationName(collation: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Maps a runtime type name (e.g. 'string', 'number') to a driver-specific bind type constant.
|
|
47
|
+
* Used by NativeQueryBuilder for output bindings.
|
|
48
|
+
* @internal
|
|
49
|
+
*/
|
|
50
|
+
mapToBindType(type: string): unknown;
|
|
45
51
|
}
|
package/AbstractSqlPlatform.js
CHANGED
|
@@ -116,4 +116,12 @@ export class AbstractSqlPlatform extends Platform {
|
|
|
116
116
|
throw new Error(`Invalid collation name: '${collation}'. Collation names must contain only word characters.`);
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Maps a runtime type name (e.g. 'string', 'number') to a driver-specific bind type constant.
|
|
121
|
+
* Used by NativeQueryBuilder for output bindings.
|
|
122
|
+
* @internal
|
|
123
|
+
*/
|
|
124
|
+
mapToBindType(type) {
|
|
125
|
+
return type;
|
|
126
|
+
}
|
|
119
127
|
}
|
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
|
|
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
|
|
|
@@ -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
|
```
|
package/dialects/index.d.ts
CHANGED
package/dialects/index.js
CHANGED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type AliasNode, CompiledQuery, type DatabaseConnection, type DatabaseIntrospector, DefaultQueryCompiler, type Dialect, DialectAdapterBase, type Driver, type Kysely, type QueryCompiler, type QueryResult, type TransactionSettings } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Subset of oracledb's Pool interface used by the dialect.
|
|
4
|
+
* We define our own interface to avoid importing the `oracledb` package directly.
|
|
5
|
+
*/
|
|
6
|
+
export interface OraclePool {
|
|
7
|
+
getConnection(): Promise<OraclePoolConnection>;
|
|
8
|
+
close(drainTime?: number): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Subset of oracledb's Connection interface used by the dialect.
|
|
12
|
+
*/
|
|
13
|
+
export interface OraclePoolConnection {
|
|
14
|
+
execute<R>(sql: string, params: unknown[], options?: Record<string, unknown>): Promise<{
|
|
15
|
+
rows?: R[];
|
|
16
|
+
rowsAffected?: number;
|
|
17
|
+
resultSet?: OracleResultSet<R>;
|
|
18
|
+
outBinds?: unknown;
|
|
19
|
+
}>;
|
|
20
|
+
commit(): Promise<void>;
|
|
21
|
+
rollback(): Promise<void>;
|
|
22
|
+
close(): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
interface OracleResultSet<R> {
|
|
25
|
+
getRow(): Promise<R>;
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
declare class OracleQueryCompiler extends DefaultQueryCompiler {
|
|
29
|
+
protected getLeftIdentifierWrapper(): string;
|
|
30
|
+
protected getRightIdentifierWrapper(): string;
|
|
31
|
+
protected visitAlias(node: AliasNode): void;
|
|
32
|
+
}
|
|
33
|
+
declare class OracleAdapter extends DialectAdapterBase {
|
|
34
|
+
#private;
|
|
35
|
+
get supportsReturning(): boolean;
|
|
36
|
+
get supportsTransactionalDdl(): boolean;
|
|
37
|
+
acquireMigrationLock(_: Kysely<any>): Promise<void>;
|
|
38
|
+
releaseMigrationLock(_: Kysely<any>): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
declare class OracleConnection implements DatabaseConnection {
|
|
41
|
+
#private;
|
|
42
|
+
readonly id: number;
|
|
43
|
+
constructor(connection: OraclePoolConnection, executeOptions?: Record<string, unknown>);
|
|
44
|
+
executeQuery<R>(compiledQuery: CompiledQuery): Promise<QueryResult<R>>;
|
|
45
|
+
formatQuery(query: CompiledQuery): {
|
|
46
|
+
sql: string;
|
|
47
|
+
bindParams: unknown[];
|
|
48
|
+
};
|
|
49
|
+
streamQuery<R>(compiledQuery: CompiledQuery, _chunkSize?: number): AsyncIterableIterator<QueryResult<R>>;
|
|
50
|
+
get connection(): OraclePoolConnection;
|
|
51
|
+
}
|
|
52
|
+
declare class OracleDriver implements Driver {
|
|
53
|
+
#private;
|
|
54
|
+
constructor(config: OracleDialectConfig);
|
|
55
|
+
init(): Promise<void>;
|
|
56
|
+
acquireConnection(): Promise<OracleConnection>;
|
|
57
|
+
savepoint(connection: OracleConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
|
|
58
|
+
rollbackToSavepoint(connection: OracleConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
|
|
59
|
+
releaseSavepoint(connection: OracleConnection, savepointName: string, compileQuery: QueryCompiler['compileQuery']): Promise<void>;
|
|
60
|
+
beginTransaction(connection: OracleConnection, settings: TransactionSettings): Promise<void>;
|
|
61
|
+
commitTransaction(connection: OracleConnection): Promise<void>;
|
|
62
|
+
rollbackTransaction(connection: OracleConnection): Promise<void>;
|
|
63
|
+
releaseConnection(connection: OracleConnection): Promise<void>;
|
|
64
|
+
destroy(): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
export interface OracleDialectConfig {
|
|
67
|
+
pool: OraclePool;
|
|
68
|
+
executeOptions?: Record<string, unknown>;
|
|
69
|
+
}
|
|
70
|
+
export declare class OracleDialect implements Dialect {
|
|
71
|
+
#private;
|
|
72
|
+
constructor(config: OracleDialectConfig);
|
|
73
|
+
createDriver(): OracleDriver;
|
|
74
|
+
createAdapter(): OracleAdapter;
|
|
75
|
+
createIntrospector(db: Kysely<any>): DatabaseIntrospector;
|
|
76
|
+
createQueryCompiler(): OracleQueryCompiler;
|
|
77
|
+
}
|
|
78
|
+
export {};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// inlined https://github.com/griffiths-waite/kysely-oracledb with minor adjustments
|
|
2
|
+
/* v8 ignore start: internal Kysely driver integration, tested through the main Oracle driver */
|
|
3
|
+
import { CompiledQuery, createQueryId, DefaultQueryCompiler, DialectAdapterBase, IdentifierNode, RawNode, } from 'kysely';
|
|
4
|
+
function parseSavepointCommand(command, savepointName) {
|
|
5
|
+
return RawNode.createWithChildren([
|
|
6
|
+
RawNode.createWithSql(`${command} `),
|
|
7
|
+
IdentifierNode.create(savepointName), // ensures savepointName gets sanitized
|
|
8
|
+
]);
|
|
9
|
+
}
|
|
10
|
+
class OracleQueryCompiler extends DefaultQueryCompiler {
|
|
11
|
+
getLeftIdentifierWrapper() {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
getRightIdentifierWrapper() {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
visitAlias(node) {
|
|
18
|
+
this.visitNode(node.node);
|
|
19
|
+
this.append(' ');
|
|
20
|
+
this.visitNode(node.alias);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
class OracleAdapter extends DialectAdapterBase {
|
|
24
|
+
#supportsReturning = false;
|
|
25
|
+
#supportsTransactionalDdl = false;
|
|
26
|
+
get supportsReturning() {
|
|
27
|
+
return this.#supportsReturning;
|
|
28
|
+
}
|
|
29
|
+
get supportsTransactionalDdl() {
|
|
30
|
+
return this.#supportsTransactionalDdl;
|
|
31
|
+
}
|
|
32
|
+
async acquireMigrationLock(_) {
|
|
33
|
+
throw new Error('Not implemented');
|
|
34
|
+
}
|
|
35
|
+
async releaseMigrationLock(_) {
|
|
36
|
+
throw new Error('Not implemented');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const OUT_FORMAT_OBJECT = 4002;
|
|
40
|
+
let i = 0;
|
|
41
|
+
class OracleConnection {
|
|
42
|
+
id = i++;
|
|
43
|
+
#executeOptions;
|
|
44
|
+
#connection;
|
|
45
|
+
constructor(connection, executeOptions) {
|
|
46
|
+
this.#executeOptions = executeOptions ?? {};
|
|
47
|
+
this.#connection = connection;
|
|
48
|
+
}
|
|
49
|
+
async executeQuery(compiledQuery) {
|
|
50
|
+
const { sql, bindParams } = this.formatQuery(compiledQuery);
|
|
51
|
+
const result = await this.#connection.execute(sql, bindParams, {
|
|
52
|
+
autoCommit: compiledQuery.autoCommit,
|
|
53
|
+
outFormat: OUT_FORMAT_OBJECT,
|
|
54
|
+
...this.#executeOptions,
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
rows: result?.rows || [],
|
|
58
|
+
numAffectedRows: result.rowsAffected ? BigInt(result.rowsAffected) : undefined,
|
|
59
|
+
// @ts-ignore internal extension for Oracle returning clause
|
|
60
|
+
outBinds: result.outBinds,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
formatQuery(query) {
|
|
64
|
+
return {
|
|
65
|
+
sql: query.sql.replace(/\$(\d+)/g, (_match, p1) => `:${parseInt(p1, 10) - 1}`), // Format bind params in Oracle syntax :0, :1, etc.
|
|
66
|
+
bindParams: query.parameters,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async *streamQuery(compiledQuery, _chunkSize) {
|
|
70
|
+
const { sql, bindParams } = this.formatQuery(compiledQuery);
|
|
71
|
+
const result = await this.#connection.execute(sql, bindParams, {
|
|
72
|
+
resultSet: true,
|
|
73
|
+
autoCommit: compiledQuery.autoCommit,
|
|
74
|
+
outFormat: OUT_FORMAT_OBJECT,
|
|
75
|
+
...this.#executeOptions,
|
|
76
|
+
});
|
|
77
|
+
const rs = result.resultSet;
|
|
78
|
+
try {
|
|
79
|
+
let row;
|
|
80
|
+
while ((row = await rs.getRow())) {
|
|
81
|
+
yield { rows: [row] };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
await rs.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
get connection() {
|
|
89
|
+
return this.#connection;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
class OracleDriver {
|
|
93
|
+
#config;
|
|
94
|
+
#connections = new Set();
|
|
95
|
+
constructor(config) {
|
|
96
|
+
this.#config = config;
|
|
97
|
+
}
|
|
98
|
+
async init() {
|
|
99
|
+
//
|
|
100
|
+
}
|
|
101
|
+
async acquireConnection() {
|
|
102
|
+
const connection = new OracleConnection(await this.#config.pool.getConnection(), this.#config.executeOptions);
|
|
103
|
+
this.#connections.add(connection);
|
|
104
|
+
return connection;
|
|
105
|
+
}
|
|
106
|
+
async savepoint(connection, savepointName, compileQuery) {
|
|
107
|
+
await connection.executeQuery(compileQuery(parseSavepointCommand('savepoint', savepointName), createQueryId()));
|
|
108
|
+
}
|
|
109
|
+
async rollbackToSavepoint(connection, savepointName, compileQuery) {
|
|
110
|
+
await connection.executeQuery(compileQuery(parseSavepointCommand('rollback to savepoint', savepointName), createQueryId()));
|
|
111
|
+
}
|
|
112
|
+
async releaseSavepoint(connection, savepointName, compileQuery) {
|
|
113
|
+
//
|
|
114
|
+
}
|
|
115
|
+
async beginTransaction(connection, settings) {
|
|
116
|
+
if (settings.accessMode) {
|
|
117
|
+
await connection.executeQuery(CompiledQuery.raw(`set transaction ${settings.accessMode}`));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (settings.isolationLevel) {
|
|
121
|
+
await connection.executeQuery(CompiledQuery.raw(`set transaction isolation level ${settings.isolationLevel}`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async commitTransaction(connection) {
|
|
125
|
+
await connection.connection.commit();
|
|
126
|
+
}
|
|
127
|
+
async rollbackTransaction(connection) {
|
|
128
|
+
await connection.connection.rollback();
|
|
129
|
+
}
|
|
130
|
+
async releaseConnection(connection) {
|
|
131
|
+
try {
|
|
132
|
+
await connection.connection.close();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
//
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
this.#connections.delete(connection);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async destroy() {
|
|
142
|
+
for (const connection of this.#connections) {
|
|
143
|
+
await this.releaseConnection(connection);
|
|
144
|
+
}
|
|
145
|
+
await this.#config.pool?.close(0);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export class OracleDialect {
|
|
149
|
+
#config;
|
|
150
|
+
constructor(config) {
|
|
151
|
+
this.#config = config;
|
|
152
|
+
}
|
|
153
|
+
createDriver() {
|
|
154
|
+
return new OracleDriver(this.#config);
|
|
155
|
+
}
|
|
156
|
+
createAdapter() {
|
|
157
|
+
return new OracleAdapter();
|
|
158
|
+
}
|
|
159
|
+
createIntrospector(db) {
|
|
160
|
+
throw new Error('Not implemented');
|
|
161
|
+
}
|
|
162
|
+
createQueryCompiler() {
|
|
163
|
+
return new OracleQueryCompiler();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/* v8 ignore stop */
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Dictionary } from '@mikro-orm/core';
|
|
2
|
+
import { NativeQueryBuilder } from '../../query/NativeQueryBuilder.js';
|
|
3
|
+
/** @internal */
|
|
4
|
+
export declare function markOutBindings(obj: Dictionary): void;
|
|
5
|
+
/** @internal */
|
|
6
|
+
export declare class OracleNativeQueryBuilder extends NativeQueryBuilder {
|
|
7
|
+
as(alias: string): this;
|
|
8
|
+
compile(): {
|
|
9
|
+
sql: string;
|
|
10
|
+
params: unknown[];
|
|
11
|
+
};
|
|
12
|
+
protected compileTruncate(): void;
|
|
13
|
+
protected combineParts(): {
|
|
14
|
+
sql: string;
|
|
15
|
+
params: unknown[];
|
|
16
|
+
};
|
|
17
|
+
private compileUpsert;
|
|
18
|
+
protected compileSelect(): void;
|
|
19
|
+
}
|