feat: add findAll and findUnique resolver for universal objects (#1576)
* wip: refacto and start creating custom resolver * feat: findMany & findUnique of a custom entity * feat: wip pagination * feat: initial metadata migration * feat: universal findAll with pagination * fix: clean small stuff in pagination * fix: test * fix: miss file * feat: rename custom into universal * feat: create metadata schema in default database --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -6,9 +6,16 @@
|
||||
* @returns
|
||||
*/
|
||||
export function uuidToBase36(uuid: string): string {
|
||||
let devId = false;
|
||||
|
||||
if (uuid.startsWith('twenty-')) {
|
||||
devId = true;
|
||||
// Clean dev uuids (twenty-)
|
||||
uuid = uuid.replace('twenty-', '');
|
||||
}
|
||||
const hexString = uuid.replace(/-/g, '');
|
||||
const base10Number = BigInt('0x' + hexString);
|
||||
const base36String = base10Number.toString(36);
|
||||
|
||||
return base36String;
|
||||
return `${devId ? 'twenty_' : ''}${base36String}`;
|
||||
}
|
||||
|
||||
@ -4,4 +4,12 @@ export const baseColumns = {
|
||||
type: 'uuid',
|
||||
generated: 'uuid',
|
||||
},
|
||||
createdAt: {
|
||||
type: 'timestamp',
|
||||
createDate: true,
|
||||
},
|
||||
updatedAt: {
|
||||
type: 'timestamp',
|
||||
updateDate: true,
|
||||
},
|
||||
} as const;
|
||||
|
||||
@ -9,6 +9,7 @@ import { JwtAuthGuard } from 'src/guards/jwt.auth.guard';
|
||||
import { DataSourceMetadataService } from './data-source-metadata/data-source-metadata.service';
|
||||
import { EntitySchemaGeneratorService } from './entity-schema-generator/entity-schema-generator.service';
|
||||
import { DataSourceService } from './data-source/data-source.service';
|
||||
import { uuidToBase36 } from './data-source/data-source.util';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('metadata')
|
||||
@ -39,6 +40,10 @@ export class MetadataController {
|
||||
entities.push(...dataSourceEntities);
|
||||
}
|
||||
|
||||
this.dataSourceService.createWorkspaceSchema(workspace.id);
|
||||
|
||||
console.log('entities', uuidToBase36(workspace.id), workspace.id);
|
||||
|
||||
this.dataSourceService.connectToWorkspaceDataSource(workspace.id);
|
||||
|
||||
return entities;
|
||||
|
||||
25
server/src/tenant/metadata/metadata.datasource.ts
Normal file
25
server/src/tenant/metadata/metadata.datasource.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
|
||||
import { DataSource, DataSourceOptions } from 'typeorm';
|
||||
import { config } from 'dotenv';
|
||||
|
||||
config();
|
||||
|
||||
const configService = new ConfigService();
|
||||
|
||||
export const typeORMMetadataModuleOptions: TypeOrmModuleOptions = {
|
||||
url: configService.get<string>('PG_DATABASE_URL')!,
|
||||
type: 'postgres',
|
||||
logging: false,
|
||||
schema: 'metadata',
|
||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||
synchronize: false,
|
||||
migrationsRun: true,
|
||||
migrationsTableName: '_typeorm_migrations',
|
||||
migrations: [__dirname + '/migrations/**/*{.ts,.js}'],
|
||||
};
|
||||
|
||||
export const connectionSource = new DataSource(
|
||||
typeORMMetadataModuleOptions as DataSourceOptions,
|
||||
);
|
||||
@ -1,36 +1,24 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
|
||||
|
||||
import { EnvironmentService } from 'src/integrations/environment/environment.service';
|
||||
|
||||
import { MetadataService } from './metadata.service';
|
||||
import { MetadataController } from './metadata.controller';
|
||||
import { typeORMMetadataModuleOptions } from './metadata.datasource';
|
||||
|
||||
import { DataSourceModule } from './data-source/data-source.module';
|
||||
import { DataSourceMetadataModule } from './data-source-metadata/data-source-metadata.module';
|
||||
import { FieldMetadataModule } from './field-metadata/field-metadata.module';
|
||||
import { ObjectMetadataModule } from './object-metadata/object-metadata.module';
|
||||
import { EntitySchemaGeneratorModule } from './entity-schema-generator/entity-schema-generator.module';
|
||||
import { DataSourceMetadata } from './data-source-metadata/data-source-metadata.entity';
|
||||
import { FieldMetadata } from './field-metadata/field-metadata.entity';
|
||||
import { ObjectMetadata } from './object-metadata/object-metadata.entity';
|
||||
|
||||
const typeORMFactory = async (
|
||||
environmentService: EnvironmentService,
|
||||
): Promise<TypeOrmModuleOptions> => ({
|
||||
url: environmentService.getPGDatabaseUrl(),
|
||||
type: 'postgres',
|
||||
logging: false,
|
||||
schema: 'metadata',
|
||||
entities: [DataSourceMetadata, FieldMetadata, ObjectMetadata],
|
||||
synchronize: true,
|
||||
const typeORMFactory = async (): Promise<TypeOrmModuleOptions> => ({
|
||||
...typeORMMetadataModuleOptions,
|
||||
});
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRootAsync({
|
||||
useFactory: typeORMFactory,
|
||||
inject: [EnvironmentService],
|
||||
name: 'metadata',
|
||||
}),
|
||||
DataSourceModule,
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class Migrations1695198840363 implements MigrationInterface {
|
||||
name = 'Migrations1695198840363';
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "metadata"."data_source_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "url" character varying, "schema" character varying, "type" "metadata"."data_source_metadata_type_enum" NOT NULL DEFAULT 'postgres', "name" character varying, "is_remote" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_923752b7e62a300a4969bd0e038" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "metadata"."field_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "object_id" uuid NOT NULL, "type" character varying NOT NULL, "name" character varying NOT NULL, "is_custom" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_c75db587904cad6af109b5c65f1" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`CREATE TABLE "metadata"."object_metadata" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "data_source_id" character varying NOT NULL, "name" character varying NOT NULL, "is_custom" boolean NOT NULL DEFAULT false, "workspace_id" character varying NOT NULL, "created_at" TIMESTAMP NOT NULL DEFAULT now(), "updated_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_c8c5f885767b356949c18c201c1" PRIMARY KEY ("id"))`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."field_metadata" ADD CONSTRAINT "FK_38179b299795e48887fc99f937a" FOREIGN KEY ("object_id") REFERENCES "metadata"."object_metadata"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "metadata"."field_metadata" DROP CONSTRAINT "FK_38179b299795e48887fc99f937a"`,
|
||||
);
|
||||
await queryRunner.query(`DROP TABLE "metadata"."object_metadata"`);
|
||||
await queryRunner.query(`DROP TABLE "metadata"."field_metadata"`);
|
||||
await queryRunner.query(`DROP TABLE "metadata"."data_source_metadata"`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user