Add metadata migration setup (#1674)

* Add metadata migration setup

* add migration generator

* fix missing 'mocks'

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
This commit is contained in:
Weiko
2023-09-21 02:27:07 +02:00
committed by GitHub
parent fc820f47b2
commit 19365f6639
14 changed files with 391 additions and 20 deletions
@@ -5,17 +5,19 @@ import {
OnModuleInit,
} from '@nestjs/common';
import { DataSource } from 'typeorm';
import { DataSource, QueryRunner, Table } from 'typeorm';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
import { DataSourceMetadataService } from 'src/tenant/metadata/data-source-metadata/data-source-metadata.service';
import { EntitySchemaGeneratorService } from 'src/tenant/metadata/entity-schema-generator/entity-schema-generator.service';
import { TenantMigration } from 'src/tenant/metadata/migration-generator/tenant-migration.entity';
import { uuidToBase36 } from './data-source.util';
@Injectable()
export class DataSourceService implements OnModuleInit, OnModuleDestroy {
private mainDataSource: DataSource;
private dataSources: Map<string, DataSource> = new Map();
constructor(
private readonly environmentService: EnvironmentService,
@@ -39,7 +41,15 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy {
const schemaName = this.getSchemaName(workspaceId);
const queryRunner = this.mainDataSource.createQueryRunner();
const schemaAlreadyExists = await queryRunner.hasSchema(schemaName);
if (schemaAlreadyExists) {
throw new Error(
`Schema ${schemaName} already exists for workspace ${workspaceId}`,
);
}
await queryRunner.createSchema(schemaName, true);
await this.createMigrationTable(queryRunner, schemaName);
await queryRunner.release();
await this.dataSourceMetadataService.createDataSourceMetadata(
@@ -48,6 +58,40 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy {
);
}
private async createMigrationTable(
queryRunner: QueryRunner,
schemaName: string,
) {
await queryRunner.createTable(
new Table({
name: 'tenant_migrations',
schema: schemaName,
columns: [
{
name: 'id',
type: 'uuid',
isPrimary: true,
default: 'uuid_generate_v4()',
},
{
name: 'migrations',
type: 'jsonb',
},
{
name: 'applied_at',
type: 'timestamp',
isNullable: true,
},
{
name: 'created_at',
type: 'timestamp',
default: 'now()',
},
],
}),
);
}
/**
* Connects to a workspace data source using the workspace metadata. Returns a cached connection if it exists.
* @param workspaceId
@@ -56,10 +100,10 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy {
public async connectToWorkspaceDataSource(
workspaceId: string,
): Promise<DataSource | undefined> {
// if (this.dataSources.has(workspaceId)) {
// const cachedDataSource = this.dataSources.get(workspaceId);
// return cachedDataSource;
// }
if (this.dataSources.has(workspaceId)) {
const cachedDataSource = this.dataSources.get(workspaceId);
return cachedDataSource;
}
const dataSourcesMetadata =
await this.dataSourceMetadataService.getDataSourcesMedataFromWorkspaceId(
@@ -93,16 +137,35 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy {
type: 'postgres',
logging: ['query'],
schema,
entities: entities,
synchronize: true, // TODO: remove this in production
entities: {
TenantMigration,
...entities,
},
});
await workspaceDataSource.initialize();
return workspaceDataSource;
// this.dataSources.set(workspaceId, workspaceDataSource);
this.dataSources.set(workspaceId, workspaceDataSource);
// return this.dataSources.get(workspaceId);
return this.dataSources.get(workspaceId);
}
/**
* Disconnects from a workspace data source.
* @param workspaceId
* @returns Promise<void>
*
*/
public async disconnectFromWorkspaceDataSource(workspaceId: string) {
if (!this.dataSources.has(workspaceId)) {
return;
}
const dataSource = this.dataSources.get(workspaceId);
await dataSource?.destroy();
this.dataSources.delete(workspaceId);
}
/**
@@ -111,7 +174,7 @@ export class DataSourceService implements OnModuleInit, OnModuleDestroy {
* @param workspaceId
* @returns string
*/
private getSchemaName(workspaceId: string): string {
public getSchemaName(workspaceId: string): string {
return `workspace_${uuidToBase36(workspaceId)}`;
}