Skip to content

Commit

Permalink
feat: add sync schema blacklist
Browse files Browse the repository at this point in the history
  • Loading branch information
etienne-bechara committed Apr 20, 2021
1 parent 815d649 commit 6a8ccdc
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 113 deletions.
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,15 @@ ORM_PORT=3306
ORM_USERNAME='root'
ORM_PASSWORD='1234'
ORM_DATABASE='test'
ORM_SYNC_SCHEMA=true
ORM_SYNC_SAFE=false
```

It is recommended that you have a local database in order to test connectivity.

3\. Import `OrmModule` and `OrmConfig` into you boot script and configure asynchronously:

```ts
import { AppModule } from '@bechara/nestjs-core';
import { OrmConfig } from '@bechara/nestjs-orm';
import { OrmModule } from '@bechara/nestjs-orm';
import { AppEnvironment, AppModule } from '@bechara/nestjs-core';
import { OrmConfig. OrmModule } from '@bechara/nestjs-orm';

void AppModule.bootServer({
configs: [ OrmConfig ],
Expand All @@ -62,8 +59,10 @@ void AppModule.bootServer({
database: ormConfig.ORM_DATABASE,
username: ormConfig.ORM_USERNAME,
password: ormConfig.ORM_PASSWORD,
schemaSync: ormConfig.ORM_SYNC_SCHEMA,
safeSync: ormConfig.ORM_SYNC_SAFE,
sync: {
enable: true,
safe: ormConfig.NODE_ENV === AppEnvironment.PRODUCTION,
},
}),
}),
],
Expand Down
8 changes: 0 additions & 8 deletions source/orm/orm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,4 @@ export class OrmConfig {
@IsString() @IsNotEmpty()
public readonly ORM_DATABASE: string;

@InjectSecret()
@Transform((o) => o.value === 'true')
public readonly ORM_SYNC_SCHEMA: boolean;

@InjectSecret()
@Transform((o) => o.value === 'true')
public readonly ORM_SYNC_SAFE: boolean;

}
5 changes: 3 additions & 2 deletions source/orm/orm.interface/orm.module.options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { ModuleMetadata } from '@bechara/nestjs-core';
import { MikroOrmModuleOptions } from '@mikro-orm/nestjs';

import { SyncModuleOptions } from '../../sync/sync.interface';

export interface OrmAsyncModuleOptions extends Pick<ModuleMetadata, 'imports'> {
disableEntityScan?: boolean;
entities?: any[];
Expand All @@ -15,7 +17,6 @@ export interface OrmModuleOptions {
username: string;
password?: string;
database?: string;
schemaSync?: boolean;
safeSync?: boolean;
sync?: SyncModuleOptions;
extras?: MikroOrmModuleOptions;
}
18 changes: 9 additions & 9 deletions source/orm/orm.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { AppConfig, AppEnvironment, DynamicModule, LoggerService, Module, UtilMo
import { MikroORMOptions } from '@mikro-orm/core';
import { MikroOrmModule } from '@mikro-orm/nestjs';

import { SchemaModuleOptions } from '../schema/schema.interface';
import { SchemaModule } from '../schema/schema.module';
import { SyncModuleOptions } from '../sync/sync.interface';
import { SyncModule } from '../sync/sync.module';
import { OrmIdEntity, OrmTimestampEntity, OrmUuidEntity } from './orm.entity';
import { OrmInjectionToken } from './orm.enum';
import { OrmAsyncModuleOptions, OrmModuleOptions } from './orm.interface';
Expand Down Expand Up @@ -35,19 +35,21 @@ export class OrmModule {

return {
module: OrmModule,

imports: [
MikroOrmModule.forRootAsync({
inject: [ OrmInjectionToken.ORM_PROVIDER_OPTIONS ],
useFactory: (mikroOrmOptions: OrmModuleOptions) => ({ ...mikroOrmOptions }),
useFactory: (mikroOrmOptions: OrmModuleOptions) => mikroOrmOptions,
}),

SchemaModule.registerAsync({
SyncModule.registerAsync({
inject: [ OrmInjectionToken.ORM_SCHEMA_OPTIONS ],
useFactory: (schemaModuleOptions: SchemaModuleOptions) => ({ ...schemaModuleOptions }),
useFactory: (syncModuleOptions: SyncModuleOptions) => syncModuleOptions,
}),

MikroOrmModule.forFeature({ entities }),
],

providers: [
AppConfig,
{
Expand Down Expand Up @@ -78,12 +80,10 @@ export class OrmModule {
{
provide: OrmInjectionToken.ORM_SCHEMA_OPTIONS,
inject: [ OrmInjectionToken.ORM_MODULE_OPTIONS ],
useFactory: (ormModuleOptions: OrmModuleOptions): SchemaModuleOptions => ({
safeSync: ormModuleOptions.safeSync,
schemaSync: ormModuleOptions.schemaSync,
}),
useFactory: (ormModuleOptions: OrmModuleOptions): SyncModuleOptions => ormModuleOptions.sync,
},
],

exports: [
OrmInjectionToken.ORM_PROVIDER_OPTIONS,
OrmInjectionToken.ORM_SCHEMA_OPTIONS,
Expand Down
1 change: 0 additions & 1 deletion source/schema/schema.enum/index.ts

This file was deleted.

1 change: 0 additions & 1 deletion source/schema/schema.interface/index.ts

This file was deleted.

11 changes: 0 additions & 11 deletions source/schema/schema.interface/schema.module.options.ts

This file was deleted.

55 changes: 0 additions & 55 deletions source/schema/schema.service.ts

This file was deleted.

1 change: 1 addition & 0 deletions source/sync/sync.enum/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sync.injection.token';
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum SchemaInjectionToken {
export enum SyncInjectionToken {
MODULE_ID = 'MODULE_ID',
MODULE_OPTIONS = 'MODULE_OPTIONS',
}
1 change: 1 addition & 0 deletions source/sync/sync.interface/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './sync.module.options';
12 changes: 12 additions & 0 deletions source/sync/sync.interface/sync.module.options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ModuleMetadata } from '@bechara/nestjs-core';

export interface SyncAsyncModuleOptions extends Pick<ModuleMetadata, 'imports'> {
inject?: any[];
useFactory?: (...args: any[]) => Promise<SyncModuleOptions> | SyncModuleOptions;
}

export interface SyncModuleOptions {
enable?: boolean;
safe?: boolean;
blacklist?: string[];
}
30 changes: 15 additions & 15 deletions source/schema/schema.module.ts → source/sync/sync.module.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import { DynamicModule, LoggerModule, Module } from '@bechara/nestjs-core';
import { v4 } from 'uuid';

import { SchemaInjectionToken } from './schema.enum';
import { SchemaAsyncModuleOptions, SchemaModuleOptions } from './schema.interface';
import { SchemaService } from './schema.service';
import { SyncInjectionToken } from './sync.enum';
import { SyncAsyncModuleOptions, SyncModuleOptions } from './sync.interface';
import { SyncService } from './sync.service';

@Module({
imports: [ LoggerModule ],
providers: [
SchemaService,
SyncService,
{
provide: SchemaInjectionToken.MODULE_OPTIONS,
provide: SyncInjectionToken.MODULE_OPTIONS,
useValue: { },
},
],
exports: [
SchemaService,
SyncService,
],
})
export class SchemaModule {
export class SyncModule {

/**
* Registers underlying service with provided options.
* @param options
*/
public static register(options: SchemaModuleOptions): DynamicModule {
public static register(options: SyncModuleOptions): DynamicModule {
return {
module: SchemaModule,
module: SyncModule,
providers: [
{
provide: SchemaInjectionToken.MODULE_ID,
provide: SyncInjectionToken.MODULE_ID,
useValue: v4(),
},
{
provide: SchemaInjectionToken.MODULE_OPTIONS,
provide: SyncInjectionToken.MODULE_OPTIONS,
useValue: options,
},
],
Expand All @@ -44,17 +44,17 @@ export class SchemaModule {
* Register underlying service with provided options asynchronously.
* @param options
*/
public static registerAsync(options: SchemaAsyncModuleOptions = { }): DynamicModule {
public static registerAsync(options: SyncAsyncModuleOptions = { }): DynamicModule {
return {
module: SchemaModule,
module: SyncModule,
imports: options.imports,
providers: [
{
provide: SchemaInjectionToken.MODULE_ID,
provide: SyncInjectionToken.MODULE_ID,
useValue: v4(),
},
{
provide: SchemaInjectionToken.MODULE_OPTIONS,
provide: SyncInjectionToken.MODULE_OPTIONS,
inject: options.inject,
useFactory: options.useFactory,
},
Expand Down
70 changes: 70 additions & 0 deletions source/sync/sync.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Inject, Injectable, LoggerService } from '@bechara/nestjs-core';
import { MikroORM } from '@mikro-orm/core';

import { SyncInjectionToken } from './sync.enum';
import { SyncModuleOptions } from './sync.interface';

@Injectable()
export class SyncService {

public constructor(
@Inject(SyncInjectionToken.MODULE_OPTIONS)
private readonly syncModuleOptions: SyncModuleOptions,
private readonly mikroOrm: MikroORM,
private readonly loggerService: LoggerService,
) {
const options = this.syncModuleOptions;

if (options.enable) {
void this.syncSync(options);
}
}

/**
* Remove from schema queries that has been blacklisted.
* @param queries
* @param options
*/
private removeBlacklistedQueries(queries: string, options: SyncModuleOptions): string {
options.blacklist ??= [ ];
queries = queries.replace(/\n+/g, '\n');
return queries.split('\n').filter((q) => !options.blacklist.includes(q)).join('\n');
}

/**
* Automatically sync current database schema with
* configured entities.
* @param options
*/
public async syncSync(options: SyncModuleOptions): Promise<void> {
this.loggerService.info('[OrmService] Starting database schema sync...');

const generator = this.mikroOrm.getSchemaGenerator();
let syncDump = await generator.getUpdateSchemaSQL(false, options.safe);
syncDump = this.removeBlacklistedQueries(syncDump, options);

if (syncDump.length === 0) {
return this.loggerService.notice('[OrmService] Database schema is up to date');
}

let syncQueries = await generator.getUpdateSchemaSQL(true, options.safe);
syncQueries = this.removeBlacklistedQueries(syncQueries, options);
await generator.execute(syncQueries);

this.loggerService.notice('[OrmService] Database schema successfully updated');
}

/**
* Erase current database schema and recreate it.
*/
public async resetSync(): Promise<void> {
this.loggerService.info('[OrmService] Starting database schema reset...');

const generator = this.mikroOrm.getSchemaGenerator();
await generator.dropSchema();
await generator.createSchema();

this.loggerService.notice('[OrmService] Database schema successfully reset');
}

}
8 changes: 5 additions & 3 deletions source/test/test.main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AppModule } from '@bechara/nestjs-core';
import { AppEnvironment, AppModule } from '@bechara/nestjs-core';

import { OrmConfig } from '../orm/orm.config';
import { OrmModule } from '../orm/orm.module';
Expand Down Expand Up @@ -38,8 +38,10 @@ void AppModule.bootServer({
database: ormConfig.ORM_DATABASE,
username: ormConfig.ORM_USERNAME,
password: ormConfig.ORM_PASSWORD,
schemaSync: ormConfig.ORM_SYNC_SCHEMA,
safeSync: ormConfig.ORM_SYNC_SAFE,
sync: {
enable: true,
safe: ormConfig.NODE_ENV === AppEnvironment.PRODUCTION,
},
}),
}),
],
Expand Down

0 comments on commit 6a8ccdc

Please sign in to comment.