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:
Jérémy M
2023-09-21 02:24:13 +02:00
committed by GitHub
parent dafe08ef78
commit b1171e22a3
41 changed files with 1043 additions and 29 deletions

View File

@ -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}`;
}

View File

@ -4,4 +4,12 @@ export const baseColumns = {
type: 'uuid',
generated: 'uuid',
},
createdAt: {
type: 'timestamp',
createDate: true,
},
updatedAt: {
type: 'timestamp',
updateDate: true,
},
} as const;

View File

@ -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;

View 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,
);

View File

@ -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,

View File

@ -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"`);
}
}