@mikro-orm/oracledb 7.3.0-dev.12 → 7.3.0-dev.14

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.
@@ -8,6 +8,8 @@ export declare class OracleSchemaGenerator extends SchemaGenerator {
8
8
  /** Tracks whether the main user has been granted DBA (or equivalent) privileges. */
9
9
  private hasDbaGrant;
10
10
  static register(orm: MikroORM): void;
11
+ /** Ends the batch after a PL/SQL block (e.g. `create trigger ... end;`), so the `;\n` statement split keeps its closing `;`. */
12
+ protected startsBatch(_statement: string, previous: string): boolean;
11
13
  /**
12
14
  * creates new database and connects to it
13
15
  */
@@ -6,6 +6,10 @@ export class OracleSchemaGenerator extends SchemaGenerator {
6
6
  static register(orm) {
7
7
  orm.config.registerExtension('@mikro-orm/schema-generator', () => new OracleSchemaGenerator(orm.em));
8
8
  }
9
+ /** Ends the batch after a PL/SQL block (e.g. `create trigger ... end;`), so the `;\n` statement split keeps its closing `;`. */
10
+ startsBatch(_statement, previous) {
11
+ return /\bend;$/i.test(previous);
12
+ }
9
13
  /**
10
14
  * creates new database and connects to it
11
15
  */
@@ -1,4 +1,4 @@
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';
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, type SqlTriggerDef } 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[]>;
@@ -27,6 +27,7 @@ export declare class OracleSchemaHelper extends SchemaHelper {
27
27
  getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, ctx?: Transaction): Promise<Dictionary<CheckDef[]>>;
28
28
  getDatabaseCollation(connection: AbstractSqlConnection, ctx?: Transaction): Promise<string | undefined>;
29
29
  loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[], ctx?: Transaction): Promise<void>;
30
+ getAllTriggers(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, ctx?: Transaction): Promise<Dictionary<SqlTriggerDef[]>>;
30
31
  getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
31
32
  getPostAlterTable(tableDiff: TableDifference, safe: boolean): string[];
32
33
  getCreateNamespaceSQL(name: string): string;
@@ -49,6 +50,11 @@ export declare class OracleSchemaHelper extends SchemaHelper {
49
50
  dropForeignKey(tableName: string, constraintName: string): string;
50
51
  dropViewIfExists(name: string, schema?: string): string;
51
52
  dropTableIfExists(name: string, schema?: string): string;
53
+ /** Oracle supports multiple events and both row and statement level in one trigger, but `instead of` works only on views and there is no `truncate` DML event. */
54
+ createTrigger(table: DatabaseTable, trigger: SqlTriggerDef): string;
55
+ /** Uses `IF EXISTS` (Oracle 23c+), same as the other drop statements. */
56
+ dropTrigger(table: DatabaseTable, trigger: SqlTriggerDef): string;
57
+ private getTriggerName;
52
58
  getAddColumnsSQL(table: DatabaseTable, columns: Column[]): string[];
53
59
  appendComments(table: DatabaseTable): string[];
54
60
  inferLengthFromColumnType(type: string): number | undefined;
@@ -390,6 +390,7 @@ export class OracleSchemaHelper extends SchemaHelper {
390
390
  const indexes = await this.getAllIndexes(connection, tablesBySchema, ctx);
391
391
  const checks = await this.getAllChecks(connection, tablesBySchema, ctx);
392
392
  const fks = await this.getAllForeignKeys(connection, tablesBySchema, ctx);
393
+ const triggers = await this.getAllTriggers(connection, tablesBySchema, ctx);
393
394
  const dbCollation = await this.getDatabaseCollation(connection, ctx);
394
395
  for (const t of tables) {
395
396
  const key = this.getTableKey(t);
@@ -398,7 +399,34 @@ export class OracleSchemaHelper extends SchemaHelper {
398
399
  const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
399
400
  const enums = this.getEnumDefinitions(checks[key] ?? []);
400
401
  table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
402
+ if (triggers[key]) {
403
+ table.setTriggers(triggers[key]);
404
+ }
405
+ }
406
+ }
407
+ async getAllTriggers(connection, tablesBySchemas, ctx) {
408
+ // `trigger_body` is a LONG column, which node-oracledb fetches as a string
409
+ const sql = `select trigger_name, table_owner as schema_name, table_name, trigger_type, triggering_event, when_clause, trigger_body
410
+ from all_triggers
411
+ where base_object_type = 'TABLE'
412
+ and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(', ')}) and table_owner = ${this.platform.quoteValue(schema)})`).join(' or ')})
413
+ order by table_owner, table_name, trigger_name`;
414
+ const allTriggers = await connection.execute(sql, [], 'all', ctx);
415
+ const ret = {};
416
+ for (const row of allTriggers) {
417
+ const key = this.getTableKey(row);
418
+ ret[key] ??= [];
419
+ ret[key].push({
420
+ name: row.trigger_name,
421
+ // e.g. `BEFORE EACH ROW`, `AFTER STATEMENT`
422
+ timing: row.trigger_type.replace(/\s+(each row|statement)$/i, '').toLowerCase(),
423
+ events: row.triggering_event.toLowerCase().split(/\s+or\s+/),
424
+ forEach: /\beach row$/i.test(row.trigger_type) ? 'row' : 'statement',
425
+ body: this.stripRoutineBody(row.trigger_body),
426
+ when: row.when_clause?.trim() || undefined,
427
+ });
401
428
  }
429
+ return ret;
402
430
  }
403
431
  getPreAlterTable(tableDiff, safe) {
404
432
  const ret = [];
@@ -626,6 +654,34 @@ export class OracleSchemaHelper extends SchemaHelper {
626
654
  }
627
655
  return `drop table if exists ${this.quote(schema, name)} cascade constraint`;
628
656
  }
657
+ /** Oracle supports multiple events and both row and statement level in one trigger, but `instead of` works only on views and there is no `truncate` DML event. */
658
+ createTrigger(table, trigger) {
659
+ if (trigger.expression) {
660
+ return trigger.expression;
661
+ }
662
+ if (trigger.timing === 'instead of') {
663
+ throw new Error(`Oracle supports INSTEAD OF triggers only on views. Use BEFORE or AFTER for trigger "${trigger.name}".`);
664
+ }
665
+ if (trigger.events.includes('truncate')) {
666
+ throw new Error(`Oracle does not support TRUNCATE triggers. Remove the TRUNCATE event from trigger "${trigger.name}".`);
667
+ }
668
+ if (trigger.when && trigger.forEach === 'statement') {
669
+ throw new Error(`Oracle supports WHEN conditions only on row-level triggers (trigger "${trigger.name}").`);
670
+ }
671
+ const timing = trigger.timing.toUpperCase();
672
+ const events = trigger.events.map(e => e.toUpperCase()).join(' OR ');
673
+ const forEach = trigger.forEach === 'statement' ? '' : ' for each row';
674
+ const when = trigger.when ? ` when (${trigger.when})` : '';
675
+ return `create or replace trigger ${this.getTriggerName(table, trigger)} ${timing} ${events} on ${table.getQuotedName()}${forEach}${when} begin ${this.normalizeTriggerBody(trigger.body)} end;`;
676
+ }
677
+ /** Uses `IF EXISTS` (Oracle 23c+), same as the other drop statements. */
678
+ dropTrigger(table, trigger) {
679
+ return `drop trigger if exists ${this.getTriggerName(table, trigger)}`;
680
+ }
681
+ getTriggerName(table, trigger) {
682
+ const schema = table.schema === this.platform.getDefaultSchemaName() ? undefined : table.schema;
683
+ return this.quote(schema, trigger.name);
684
+ }
629
685
  getAddColumnsSQL(table, columns) {
630
686
  const adds = columns
631
687
  .map(column => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mikro-orm/oracledb",
3
- "version": "7.3.0-dev.12",
3
+ "version": "7.3.0-dev.14",
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,7 +42,7 @@
42
42
  "copy": "node ../../scripts/copy.mjs"
43
43
  },
44
44
  "dependencies": {
45
- "@mikro-orm/sql": "7.3.0-dev.12",
45
+ "@mikro-orm/sql": "7.3.0-dev.14",
46
46
  "kysely": "0.29.6",
47
47
  "oracledb": "7.0.1"
48
48
  },
@@ -50,7 +50,7 @@
50
50
  "@mikro-orm/core": "^7.2.3"
51
51
  },
52
52
  "peerDependencies": {
53
- "@mikro-orm/core": "7.3.0-dev.12"
53
+ "@mikro-orm/core": "7.3.0-dev.14"
54
54
  },
55
55
  "engines": {
56
56
  "node": ">= 22.17.0"