Fix update remote field metadata (#5638)

Closes #5610.

& update fetch-policy when fetching database on the remote databases
show page to get freshest status.
This commit is contained in:
Marie
2024-05-28 18:01:05 +02:00
committed by GitHub
parent ebb1aa0377
commit 5bb205bd6a
9 changed files with 146 additions and 25 deletions

View File

@ -1,4 +1,4 @@
import { useQuery } from '@apollo/client';
import { useQuery, WatchQueryFetchPolicy } from '@apollo/client';
import { GET_ONE_DATABASE_CONNECTION } from '@/databases/graphql/queries/findOneDatabaseConnection';
import { getForeignDataWrapperType } from '@/databases/utils/getForeignDataWrapperType';
@ -12,16 +12,20 @@ type UseGetDatabaseConnectionParams = {
databaseKey: string;
connectionId: string;
skip?: boolean;
fetchPolicy?: WatchQueryFetchPolicy;
};
export const useGetDatabaseConnection = ({
databaseKey,
connectionId,
skip,
fetchPolicy,
}: UseGetDatabaseConnectionParams) => {
const apolloMetadataClient = useApolloMetadataClient();
const foreignDataWrapperType = getForeignDataWrapperType(databaseKey);
const fetchPolicyOption = fetchPolicy ? { fetchPolicy: fetchPolicy } : {};
const { data, loading } = useQuery<
GetOneDatabaseConnectionQuery,
GetOneDatabaseConnectionQueryVariables
@ -33,6 +37,7 @@ export const useGetDatabaseConnection = ({
id: connectionId,
},
},
...fetchPolicyOption,
});
const connection = data?.findOneRemoteServerById ?? null;

View File

@ -1,4 +1,4 @@
import { useQuery } from '@apollo/client';
import { useQuery, WatchQueryFetchPolicy } from '@apollo/client';
import { GET_MANY_REMOTE_TABLES } from '@/databases/graphql/queries/findManyRemoteTables';
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
@ -11,15 +11,19 @@ type UseGetDatabaseConnectionTablesParams = {
connectionId: string;
skip?: boolean;
shouldFetchPendingSchemaUpdates?: boolean;
fetchPolicy?: WatchQueryFetchPolicy;
};
export const useGetDatabaseConnectionTables = ({
connectionId,
skip,
shouldFetchPendingSchemaUpdates,
fetchPolicy,
}: UseGetDatabaseConnectionTablesParams) => {
const apolloMetadataClient = useApolloMetadataClient();
const fetchPolicyOption = fetchPolicy ? { fetchPolicy: fetchPolicy } : {};
const { data, error } = useQuery<
GetManyRemoteTablesQuery,
GetManyRemoteTablesQueryVariables
@ -32,6 +36,7 @@ export const useGetDatabaseConnectionTables = ({
shouldFetchPendingSchemaUpdates,
},
},
...fetchPolicyOption,
});
return {

View File

@ -1,9 +1,12 @@
import { useCallback } from 'react';
import { ApolloClient, useMutation } from '@apollo/client';
import { ApolloClient, useApolloClient, useMutation } from '@apollo/client';
import { SYNC_REMOTE_TABLE_SCHEMA_CHANGES } from '@/databases/graphql/mutations/syncRemoteTableSchemaChanges';
import { modifyRemoteTableFromCache } from '@/databases/utils/modifyRemoteTableFromCache';
import { useApolloMetadataClient } from '@/object-metadata/hooks/useApolloMetadataClient';
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useFindManyRecordsQuery } from '@/object-record/hooks/useFindManyRecordsQuery';
import {
RemoteTableInput,
SyncRemoteTableSchemaChangesMutation,
@ -13,6 +16,14 @@ import { isDefined } from '~/utils/isDefined';
export const useSyncRemoteTableSchemaChanges = () => {
const apolloMetadataClient = useApolloMetadataClient();
const apolloClient = useApolloClient();
const { refetch: refetchObjectMetadataItems } =
useFindManyObjectMetadataItems();
const { findManyRecordsQuery: findManyViewsQuery } = useFindManyRecordsQuery({
objectNameSingular: CoreObjectNameSingular.View,
});
const [mutate, mutationInformation] = useMutation<
SyncRemoteTableSchemaChangesMutation,
@ -42,9 +53,16 @@ export const useSyncRemoteTableSchemaChanges = () => {
},
});
await refetchObjectMetadataItems();
await apolloClient.query({
query: findManyViewsQuery,
fetchPolicy: 'network-only',
});
return remoteTable;
},
[mutate],
[mutate, refetchObjectMetadataItems, findManyViewsQuery, apolloClient],
);
return {

View File

@ -13,7 +13,7 @@ import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
export const SettingsIntegrationDatabaseConnectionShowContainer = () => {
const navigate = useNavigate();
const { connection, integration, databaseKey, tables } =
useDatabaseConnection();
useDatabaseConnection({ fetchPolicy: 'network-only' });
const { deleteOneDatabaseConnection } = useDeleteOneDatabaseConnection();

View File

@ -3,7 +3,7 @@ import { useDatabaseConnection } from '@/settings/integrations/database-connecti
export const SettingsIntegrationEditDatabaseConnectionContainer = () => {
const { connection, integration, databaseKey, tables } =
useDatabaseConnection();
useDatabaseConnection({});
if (!connection || !integration) return null;

View File

@ -1,5 +1,6 @@
import { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { WatchQueryFetchPolicy } from '@apollo/client';
import { useGetDatabaseConnection } from '@/databases/hooks/useGetDatabaseConnection';
import { useGetDatabaseConnectionTables } from '@/databases/hooks/useGetDatabaseConnectionTables';
@ -7,7 +8,11 @@ import { useIsSettingsIntegrationEnabled } from '@/settings/integrations/hooks/u
import { useSettingsIntegrationCategories } from '@/settings/integrations/hooks/useSettingsIntegrationCategories';
import { AppPath } from '@/types/AppPath';
export const useDatabaseConnection = () => {
export const useDatabaseConnection = ({
fetchPolicy,
}: {
fetchPolicy?: WatchQueryFetchPolicy;
}) => {
const { databaseKey = '', connectionId = '' } = useParams();
const navigate = useNavigate();
@ -24,6 +29,7 @@ export const useDatabaseConnection = () => {
databaseKey,
connectionId,
skip: !isIntegrationAvailable,
fetchPolicy,
});
useEffect(() => {
@ -43,6 +49,7 @@ export const useDatabaseConnection = () => {
connectionId,
skip: !connection,
shouldFetchPendingSchemaUpdates: true,
fetchPolicy,
});
return { connection, integration, databaseKey, tables };

View File

@ -110,9 +110,9 @@ export class DistantTableService {
return distantTables;
}
private async getDistantTablesFromStaticSchema(
private getDistantTablesFromStaticSchema(
remoteServer: RemoteServerEntity<RemoteServerType>,
): Promise<DistantTables> {
): DistantTables {
switch (remoteServer.foreignDataWrapperType) {
case RemoteServerType.STRIPE_FDW:
return STRIPE_DISTANT_TABLES;

View File

@ -99,7 +99,7 @@ export class ForeignTableService {
public async updateForeignTable(
foreignTableName: string,
workspaceId: string,
columnsUpdates?: WorkspaceMigrationColumnAction[],
columnsUpdates: WorkspaceMigrationColumnAction[],
) {
const workspaceMigration =
await this.workspaceMigrationService.createCustomMigration(

View File

@ -14,15 +14,14 @@ import {
RemoteTableStatus,
} from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table.dto';
import {
mapUdtNameToFieldType,
mapUdtNameToFieldSettings,
mapUdtNameToFieldType,
} from 'src/engine/metadata-modules/remote-server/remote-table/utils/udt-name-mapper.util';
import { RemoteTableInput } from 'src/engine/metadata-modules/remote-server/remote-table/dtos/remote-table-input';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service';
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { WorkspaceCacheVersionService } from 'src/engine/metadata-modules/workspace-cache-version/workspace-cache-version.service';
import { camelCase } from 'src/utils/camel-case';
import { camelToTitleCase } from 'src/utils/camel-to-title-case';
@ -35,6 +34,12 @@ import { fetchTableColumns } from 'src/engine/metadata-modules/remote-server/rem
import { ForeignTableService } from 'src/engine/metadata-modules/remote-server/remote-table/foreign-table/foreign-table.service';
import { RemoteTableSchemaUpdateService } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-schema-update/remote-table-schema-update.service';
import { sortDistantTables } from 'src/engine/metadata-modules/remote-server/remote-table/distant-table/utils/sort-distant-tables.util';
import {
WorkspaceMigrationColumnAction,
WorkspaceMigrationColumnActionType,
} from 'src/engine/metadata-modules/workspace-migration/workspace-migration.entity';
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
export class RemoteTableService {
private readonly logger = new Logger(RemoteTableService.name);
@ -353,7 +358,7 @@ export class RemoteTableService {
};
}
const updatedTable = await this.foreignTableService.updateForeignTable(
const updatedTable = await this.updateForeignTableAndFieldsMetadata(
remoteTable.localTableName,
workspaceId,
columnsUpdates,
@ -436,18 +441,12 @@ export class RemoteTableService {
// TODO: return error to the user when a column cannot be managed
try {
const field = await this.fieldMetadataService.createOne({
name: columnName,
label: camelToTitleCase(columnName),
description: 'Field of remote',
type: mapUdtNameToFieldType(column.udtName),
workspaceId: workspaceId,
objectMetadataId: objectMetadata.id,
isRemoteCreation: true,
isNullable: true,
icon: 'IconPlug',
settings: mapUdtNameToFieldSettings(column.udtName),
} satisfies CreateFieldInput);
const field = await this.createFieldMetadataForForeignTableColumn(
workspaceId,
columnName,
column.udtName,
objectMetadata.id,
);
if (columnName === 'id') {
await this.objectMetadataService.updateOne(objectMetadata.id, {
@ -489,4 +488,91 @@ export class RemoteTableService {
return [...distantTablesWithUpdates, ...deletedTables];
}
private async updateForeignTableAndFieldsMetadata(
foreignTableName: string,
workspaceId: string,
columnsUpdates: WorkspaceMigrationColumnAction[],
) {
const updatedForeignTable =
await this.foreignTableService.updateForeignTable(
foreignTableName,
workspaceId,
columnsUpdates,
);
const objectMetadata =
await this.objectMetadataService.findOneWithinWorkspace(workspaceId, {
where: { nameSingular: foreignTableName },
});
if (!objectMetadata) {
throw new NotFoundException(
`Cannot find associated object for table ${foreignTableName}`,
);
}
for (const columnUpdate of columnsUpdates) {
this.updateFieldMetadataFromColumnUpdate(
columnUpdate,
workspaceId,
objectMetadata.id,
);
}
return updatedForeignTable;
}
private async updateFieldMetadataFromColumnUpdate(
columnUpdate: WorkspaceMigrationColumnAction,
workspaceId: string,
objectMetadataId: string,
) {
if (columnUpdate.action === WorkspaceMigrationColumnActionType.CREATE) {
await this.createFieldMetadataForForeignTableColumn(
workspaceId,
columnUpdate.columnName,
columnUpdate.columnType,
objectMetadataId,
);
}
if (columnUpdate.action === WorkspaceMigrationColumnActionType.DROP) {
const columnName = columnUpdate.columnName;
const fieldMetadataToDelete =
await this.fieldMetadataService.findOneWithinWorkspace(workspaceId, {
where: {
objectMetadataId: objectMetadataId,
name: columnName,
},
});
if (!fieldMetadataToDelete) {
throw new NotFoundException(
`Cannot find associated field metadata for column ${columnName}`,
);
}
await this.fieldMetadataService.deleteOne(fieldMetadataToDelete.id);
}
}
private async createFieldMetadataForForeignTableColumn(
workspaceId: string,
columnName: string,
columnType: string,
objectMetadataId: string,
): Promise<FieldMetadataEntity<'default'>> {
return this.fieldMetadataService.createOne({
name: columnName,
label: camelToTitleCase(columnName),
description: 'Field of remote',
type: mapUdtNameToFieldType(columnType),
workspaceId: workspaceId,
objectMetadataId: objectMetadataId,
isRemoteCreation: true,
isNullable: true,
icon: 'IconPlug',
settings: mapUdtNameToFieldSettings(columnType),
} satisfies CreateFieldInput);
}
}