Skip to content

Commit

Permalink
feat(schema): improve orm.schema.execute() to support executing bat…
Browse files Browse the repository at this point in the history
…ches

When you run a batch of queries via `schema.execute()`, they are now grouped based on blank lines - a blank line between groups of statements means they will be executed separately. This is important for some queries that cannot be ran in a single batch, like when you create a database and switch to it.
  • Loading branch information
B4nan committed Apr 3, 2024
1 parent 255f425 commit 3c5a347
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/typings.ts
Expand Up @@ -785,7 +785,7 @@ export interface ISchemaGenerator {
updateSchema(options?: UpdateSchemaOptions): Promise<void>;
getUpdateSchemaSQL(options?: UpdateSchemaOptions): Promise<string>;
getUpdateSchemaMigrationSQL(options?: UpdateSchemaOptions): Promise<{ up: string; down: string }>;
createDatabase(name: string): Promise<void>;
createDatabase(name?: string): Promise<void>;
dropDatabase(name?: string): Promise<void>;
execute(sql: string, options?: { wrap?: boolean }): Promise<void>;
ensureIndexes(): Promise<void>;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/AbstractSchemaGenerator.ts
Expand Up @@ -89,7 +89,7 @@ export abstract class AbstractSchemaGenerator<D extends IDatabaseDriver> impleme
/**
* creates new database and connects to it
*/
async createDatabase(name: string): Promise<void> {
async createDatabase(name?: string): Promise<void> {
this.notImplemented();
}

Expand Down
3 changes: 2 additions & 1 deletion packages/knex/src/schema/SchemaHelper.ts
Expand Up @@ -293,7 +293,8 @@ export abstract class SchemaHelper {
}

getCreateDatabaseSQL(name: string): string {
return `create database ${name}`;
// two line breaks to force separate execution
return `create database ${name};\n\nuse ${name}`;
}

getDropDatabaseSQL(name: string): string {
Expand Down
36 changes: 28 additions & 8 deletions packages/knex/src/schema/SqlSchemaGenerator.ts
Expand Up @@ -11,6 +11,7 @@ import {
type EnsureDatabaseOptions,
type DropSchemaOptions,
type UpdateSchemaOptions,
type Transaction,
} from '@mikro-orm/core';
import type { CheckDef, ForeignKey, IndexDef, SchemaDifference, TableDifference } from '../typings';
import { DatabaseSchema } from './DatabaseSchema';
Expand Down Expand Up @@ -536,11 +537,12 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDrive
/**
* creates new database and connects to it
*/
override async createDatabase(name: string): Promise<void> {
override async createDatabase(name?: string): Promise<void> {
name ??= this.config.get('dbName')!;
const sql = this.helper.getCreateDatabaseSQL('' + this.knex.ref(name));

if (sql) {
await this.driver.execute(sql);
await this.execute(sql);
}

this.config.set('dbName', name);
Expand All @@ -554,21 +556,39 @@ export class SqlSchemaGenerator extends AbstractSchemaGenerator<AbstractSqlDrive
await this.driver.execute(this.helper.getDropDatabaseSQL('' + this.knex.ref(name)));
}

override async execute(sql: string, options: { wrap?: boolean } = {}) {
override async execute(sql: string, options: { wrap?: boolean; ctx?: Transaction } = {}) {
options.wrap ??= false;
const lines = this.wrapSchema(sql, options).split('\n').filter(i => i.trim());
const lines = this.wrapSchema(sql, options).split('\n');
const groups: string[][] = [];
let i = 0;

for (const line of lines) {
if (line.trim() === '') {
if (groups[i]?.length > 0) {
i++;
}

continue;
}

if (lines.length === 0) {
groups[i] ??= [];
groups[i].push(line.trim());
}

if (groups.length === 0) {
return;
}

if (this.platform.supportsMultipleStatements()) {
const query = lines.join('\n');
await this.driver.execute(query);
for (const group of groups) {
const query = group.join('\n');
await this.driver.execute(query);
}

return;
}

await Utils.runSerial(lines, line => this.driver.execute(line));
await Utils.runSerial(groups.flat(), line => this.driver.execute(line));
}

private wrapSchema(sql: string, options: { wrap?: boolean }): string {
Expand Down
4 changes: 4 additions & 0 deletions packages/postgresql/src/PostgreSqlSchemaHelper.ts
Expand Up @@ -29,6 +29,10 @@ export class PostgreSqlSchemaHelper extends SchemaHelper {
return `set names '${charset}';\n${this.disableForeignKeysSQL()}\n\n`;
}

override getCreateDatabaseSQL(name: string): string {
return `create database ${name}`;
}

override getListTablesSQL(): string {
return `select table_name, table_schema as schema_name, `
+ `(select pg_catalog.obj_description(c.oid) from pg_catalog.pg_class c
Expand Down

0 comments on commit 3c5a347

Please sign in to comment.