Sync table from frontend (#4894)

This PR:
- separates the existing updateSyncStatus endpoint into 2 endpoints
- creates mutations and hooks that will call those endpoints
- trigger the hook on toggle
- removes form logic and add a separated component for toggling

---------

Co-authored-by: Thomas Trompette <thomast@twenty.com>
This commit is contained in:
Thomas Trompette
2024-04-11 11:51:49 +02:00
committed by GitHub
parent bea6d4173c
commit aecf8783a0
20 changed files with 372 additions and 149 deletions

View File

@ -126,11 +126,10 @@ export class RemoteServerService<T extends RemoteServerType> {
if (remoteTablesToRemove.length) {
for (const remoteTable of remoteTablesToRemove) {
await this.remoteTableService.updateRemoteTableSyncStatus(
await this.remoteTableService.unsyncRemoteTable(
{
remoteServerId: id,
name: remoteTable.name,
status: RemoteTableStatus.NOT_SYNCED,
},
workspaceId,
);

View File

@ -1,9 +1,5 @@
import { InputType, Field, ID } from '@nestjs/graphql';
import { IsEnum } from 'class-validator';
import { RemoteTableStatus } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto';
@InputType()
export class RemoteTableInput {
@Field(() => ID)
@ -12,10 +8,6 @@ export class RemoteTableInput {
@Field(() => String)
name: string;
@IsEnum(RemoteTableStatus)
@Field(() => RemoteTableStatus)
status: RemoteTableStatus;
@Field(() => String)
schema?: string;
}

View File

@ -22,5 +22,5 @@ export class RemoteTableDTO {
status: RemoteTableStatus;
@Field(() => String)
schema: string;
schema?: string;
}

View File

@ -40,14 +40,11 @@ export class RemotePostgresTableService {
await dataSource.destroy();
return columns.map(
(column) =>
({
columnName: column.column_name,
dataType: column.data_type,
udtName: column.udt_name,
}) as RemoteTableColumn,
);
return columns.map((column) => ({
columnName: column.column_name,
dataType: column.data_type,
udtName: column.udt_name,
}));
}
public async fetchTablesFromRemotePostgresSchema(
@ -78,12 +75,9 @@ export class RemotePostgresTableService {
await dataSource.destroy();
return remotePostgresTables.map(
(table) =>
({
tableName: table.table_name,
tableSchema: table.table_schema,
}) as RemoteTable,
);
return remotePostgresTables.map((table) => ({
tableName: table.table_name,
tableSchema: table.table_schema,
}));
}
}

View File

@ -10,7 +10,7 @@ import { RemoteTableDTO } from 'src/engine/metadata-modules/remote-server/remote
import { RemoteTableService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table.service';
@UseGuards(JwtAuthGuard)
@Resolver(() => RemoteTableDTO)
@Resolver()
export class RemoteTableResolver {
constructor(private readonly remoteTableService: RemoteTableService) {}
@ -26,13 +26,18 @@ export class RemoteTableResolver {
}
@Mutation(() => RemoteTableDTO)
async updateRemoteTableSyncStatus(
async syncRemoteTable(
@Args('input') input: RemoteTableInput,
@AuthWorkspace() { id: workspaceId }: Workspace,
) {
return this.remoteTableService.updateRemoteTableSyncStatus(
input,
workspaceId,
);
return this.remoteTableService.syncRemoteTable(input, workspaceId);
}
@Mutation(() => RemoteTableDTO)
async unsyncRemoteTable(
@Args('input') input: RemoteTableInput,
@AuthWorkspace() { id: workspaceId }: Workspace,
) {
return this.remoteTableService.unsyncRemoteTable(input, workspaceId);
}
}

View File

@ -7,7 +7,10 @@ import {
RemoteServerType,
RemoteServerEntity,
} from 'src/engine/metadata-modules/remote-server/remote-server.entity';
import { RemoteTableStatus } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto';
import {
RemoteTableDTO,
RemoteTableStatus,
} from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto';
import {
isPostgreSQLIntegrationEnabled,
mapUdtNameToFieldType,
@ -86,10 +89,7 @@ export class RemoteTableService {
}));
}
public async updateRemoteTableSyncStatus(
input: RemoteTableInput,
workspaceId: string,
) {
public async syncRemoteTable(input: RemoteTableInput, workspaceId: string) {
const remoteServer = await this.remoteServerRepository.findOne({
where: {
id: input.remoteServerId,
@ -101,31 +101,33 @@ export class RemoteTableService {
throw new NotFoundException('Remote server does not exist');
}
switch (input.status) {
case RemoteTableStatus.SYNCED:
await this.createForeignTableAndMetadata(
input,
remoteServer,
workspaceId,
);
break;
case RemoteTableStatus.NOT_SYNCED:
await this.removeForeignTableAndMetadata(input, workspaceId);
break;
default:
throw new Error('Unsupported remote table status');
}
const remoteTable = await this.createForeignTableAndMetadata(
input,
remoteServer,
workspaceId,
);
await this.workspaceCacheVersionService.incrementVersion(workspaceId);
return input;
return remoteTable;
}
public async unsyncRemoteTable(input: RemoteTableInput, workspaceId: string) {
const remoteTable = await this.removeForeignTableAndMetadata(
input,
workspaceId,
);
await this.workspaceCacheVersionService.incrementVersion(workspaceId);
return remoteTable;
}
private async createForeignTableAndMetadata(
input: RemoteTableInput,
remoteServer: RemoteServerEntity<RemoteServerType>,
workspaceId: string,
) {
): Promise<RemoteTableDTO> {
if (!input.schema) {
throw new Error('Schema is required for syncing remote table');
}
@ -198,7 +200,7 @@ export class RemoteTableService {
icon: 'IconUser',
isRemote: true,
remoteTablePrimaryKeyColumnType: remoteTableIdColumn.udtName,
} as CreateObjectInput);
} satisfies CreateObjectInput);
for (const column of remoteTableColumns) {
const field = await this.fieldMetadataService.createOne({
@ -212,7 +214,7 @@ export class RemoteTableService {
isRemoteCreation: true,
isNullable: true,
icon: 'IconUser',
} as CreateFieldInput);
} satisfies CreateFieldInput);
if (column.columnName === 'id') {
await this.objectMetadataService.updateOne(objectMetadata.id, {
@ -220,12 +222,18 @@ export class RemoteTableService {
});
}
}
return {
name: input.name,
schema: input.schema,
status: RemoteTableStatus.SYNCED,
};
}
private async removeForeignTableAndMetadata(
input: RemoteTableInput,
workspaceId: string,
) {
): Promise<RemoteTableDTO> {
const remoteTableName = getRemoteTableName(input.name);
const currentForeignTableNames =
@ -261,6 +269,12 @@ export class RemoteTableService {
await this.workspaceMigrationRunnerService.executeMigrationFromPendingMigrations(
workspaceId,
);
return {
name: input.name,
schema: input.schema,
status: RemoteTableStatus.NOT_SYNCED,
};
}
private async fetchTableColumnsSchema(