mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
fix: Too many API calls fired from the suggested relationships component
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/8708 GitOrigin-RevId: 9d917b9015053e5653d2277f3dcdf69168bd1eff
This commit is contained in:
parent
1ad1e08959
commit
ed8be7dd69
@ -102,12 +102,12 @@ export const ManageTrackedRelationships: React.VFC<
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Tabs.Content value="tracked" className="px-md">
|
||||
<TrackedRelationshipsContainer dataSourceName={dataSourceName} />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="untracked" className="px-md">
|
||||
<UntrackedRelationships dataSourceName={dataSourceName} />
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="tracked" className="px-md">
|
||||
<TrackedRelationshipsContainer dataSourceName={dataSourceName} />
|
||||
</Tabs.Content>
|
||||
</>
|
||||
)}
|
||||
</Tabs.Root>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useSuggestedRelationships } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships';
|
||||
import { useAllSuggestedRelationships } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
|
||||
import { useTrackedRelationships } from './hooks/useTrackedRelationships';
|
||||
import { ManageTrackedRelationships } from './ManageTrackedRelationships';
|
||||
|
||||
@ -13,9 +13,9 @@ export const ManageTrackedRelationshipsContainer = ({
|
||||
} = useTrackedRelationships(dataSourceName);
|
||||
|
||||
const { suggestedRelationships, isLoadingSuggestedRelationships } =
|
||||
useSuggestedRelationships({
|
||||
useAllSuggestedRelationships({
|
||||
dataSourceName,
|
||||
existingRelationships: [],
|
||||
omitTracked: true,
|
||||
isEnabled: true,
|
||||
});
|
||||
|
||||
|
@ -23,14 +23,13 @@ import {
|
||||
generateDeleteLocalRelationshipRequest,
|
||||
generateRemoteRelationshipDeleteRequest,
|
||||
} from '../../../DatabaseRelationships/utils/generateRequest';
|
||||
import { generateQueryKeys } from '../../../DatabaseRelationships/utils/queryClientUtils';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { exportMetadata } from '../../../DataSource';
|
||||
import { useHttpClient } from '../../../Network';
|
||||
import { IndicatorCard } from '../../../../new-components/IndicatorCard';
|
||||
import { MetadataDataSource } from '../../../../metadata/types';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { getSuggestedRelationshipsCacheQuery } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships';
|
||||
import { generateQueryKeys } from '../../../DatabaseRelationships/utils/queryClientUtils';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { useCheckRows } from '../../../DatabaseRelationships/hooks/useCheckRows';
|
||||
|
||||
const getQueryFunction = (relationship: Relationship) => {
|
||||
@ -59,7 +58,7 @@ interface TrackedRelationshipsProps {
|
||||
dataSourceName: string;
|
||||
driver?: MetadataDataSource['kind'];
|
||||
isLoading: boolean;
|
||||
onRefetchMetadata: () => void;
|
||||
onUpdate: () => void;
|
||||
relationships: Relationship[];
|
||||
}
|
||||
|
||||
@ -67,12 +66,13 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
|
||||
dataSourceName,
|
||||
driver,
|
||||
isLoading,
|
||||
onRefetchMetadata,
|
||||
onUpdate,
|
||||
relationships,
|
||||
}) => {
|
||||
const httpClient = useHttpClient();
|
||||
const { mutateAsync } = useMetadataMigration();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [isTrackingSelectedRelationships, setTrackingSelectedRelationships] =
|
||||
useState(false);
|
||||
|
||||
@ -118,50 +118,41 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
|
||||
);
|
||||
|
||||
if (driver) {
|
||||
for (let i = 0; i < selectedRelationships.length; i++) {
|
||||
const selectedRelationship = selectedRelationships[i];
|
||||
const mutationOptions = {
|
||||
const recentMetadata = await exportMetadata({ httpClient });
|
||||
|
||||
const queries = selectedRelationships.map(relationship => {
|
||||
const queryFunction = getQueryFunction(relationship);
|
||||
|
||||
const query = queryFunction
|
||||
? queryFunction({
|
||||
driver,
|
||||
resource_version: recentMetadata.resource_version,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
relationship,
|
||||
})
|
||||
: {};
|
||||
return query;
|
||||
});
|
||||
|
||||
await mutateAsync(
|
||||
{
|
||||
query: {
|
||||
type: 'bulk',
|
||||
args: queries,
|
||||
},
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries(generateQueryKeys.metadata());
|
||||
|
||||
queryClient.invalidateQueries(
|
||||
generateQueryKeys.suggestedRelationships({
|
||||
dataSourceName,
|
||||
table: selectedRelationship.fromTable,
|
||||
})
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
const queryFunction = getQueryFunction(selectedRelationship);
|
||||
if (queryFunction) {
|
||||
const recentMetadata = await exportMetadata({ httpClient });
|
||||
await mutateAsync(
|
||||
{
|
||||
query: queryFunction({
|
||||
driver,
|
||||
resource_version: recentMetadata.resource_version,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
relationship: selectedRelationship,
|
||||
}),
|
||||
},
|
||||
mutationOptions
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
getSuggestedRelationshipsCacheQuery(
|
||||
dataSourceName,
|
||||
selectedRelationship.fromTable
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onRefetchMetadata();
|
||||
onUpdate();
|
||||
|
||||
const relationshipLabel =
|
||||
selectedRelationships.length > 1 ? 'Relationships' : 'Relationship';
|
||||
const toastMessage = `${selectedRelationships.length} ${relationshipLabel} untracked`;
|
||||
const plural = selectedRelationships.length > 1 ? 's' : '';
|
||||
const toastMessage = `${selectedRelationships.length} relationship${plural} untracked`;
|
||||
|
||||
hasuraToast({
|
||||
title: 'Success',
|
||||
@ -170,6 +161,7 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setTrackingSelectedRelationships(false);
|
||||
}
|
||||
reset();
|
||||
@ -200,6 +192,7 @@ export const TrackedRelationships: React.VFC<TrackedRelationshipsProps> = ({
|
||||
};
|
||||
|
||||
const onRelationshipActionSuccess = () => {
|
||||
onUpdate();
|
||||
if (mode)
|
||||
fireNotification({
|
||||
type: 'success',
|
||||
|
@ -47,10 +47,9 @@ export const TrackedRelationshipsContainer: React.VFC<
|
||||
dataSourceName={dataSourceName}
|
||||
isLoading={isLoadingRelationships || isLoadingMetadata}
|
||||
relationships={relationships}
|
||||
onRefetchMetadata={() => {
|
||||
refetchMetadata().then(() => {
|
||||
refetchRelationships();
|
||||
});
|
||||
onUpdate={async () => {
|
||||
await refetchMetadata();
|
||||
await refetchRelationships();
|
||||
}}
|
||||
driver={driver}
|
||||
/>
|
||||
|
@ -9,27 +9,39 @@ import { DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE } from '../constants';
|
||||
import { paginate } from '../utils';
|
||||
import { SearchBar } from './SearchBar';
|
||||
import { Badge } from '../../../../new-components/Badge';
|
||||
import {
|
||||
SuggestedRelationshipWithName,
|
||||
useSuggestedRelationships,
|
||||
} from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships';
|
||||
import { SuggestedRelationshipWithName } from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useSuggestedRelationships';
|
||||
import { RelationshipRow } from './RelationshipRow';
|
||||
import { SuggestedRelationshipTrackModal } from '../../../DatabaseRelationships/components/SuggestedRelationshipTrackModal/SuggestedRelationshipTrackModal';
|
||||
import { hasuraToast } from '../../../../new-components/Toasts';
|
||||
import Skeleton from 'react-loading-skeleton';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { getTrackedRelationshipsCacheKey } from './hooks/useTrackedRelationships';
|
||||
import {
|
||||
AddSuggestedRelationship,
|
||||
useAllSuggestedRelationships,
|
||||
} from '../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
|
||||
import { useCheckRows } from '../../../DatabaseRelationships/hooks/useCheckRows';
|
||||
|
||||
interface UntrackedRelationshipsProps {
|
||||
dataSourceName: string;
|
||||
}
|
||||
|
||||
const adaptTrackRelationship = (
|
||||
relationship: SuggestedRelationshipWithName
|
||||
): AddSuggestedRelationship => {
|
||||
const isObjectRelationship = !!relationship.from?.constraint_name;
|
||||
return {
|
||||
name: relationship.constraintName,
|
||||
columnNames: isObjectRelationship
|
||||
? relationship.from.columns
|
||||
: relationship.to.columns,
|
||||
relationshipType: isObjectRelationship ? 'object' : 'array',
|
||||
toTable: isObjectRelationship ? undefined : relationship.to.table,
|
||||
fromTable: relationship.from.table,
|
||||
};
|
||||
};
|
||||
|
||||
export const UntrackedRelationships: React.VFC<UntrackedRelationshipsProps> = ({
|
||||
dataSourceName,
|
||||
}) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [pageNumber, setPageNumber] = useState(DEFAULT_PAGE_NUMBER);
|
||||
const [pageSize, setPageSize] = useState(DEFAULT_PAGE_SIZE);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
@ -41,12 +53,11 @@ export const UntrackedRelationships: React.VFC<UntrackedRelationshipsProps> = ({
|
||||
const {
|
||||
suggestedRelationships,
|
||||
isLoadingSuggestedRelationships,
|
||||
onAddSuggestedRelationship,
|
||||
refetchSuggestedRelationships,
|
||||
} = useSuggestedRelationships({
|
||||
onAddMultipleSuggestedRelationships,
|
||||
} = useAllSuggestedRelationships({
|
||||
dataSourceName,
|
||||
existingRelationships: [],
|
||||
isEnabled: true,
|
||||
omitTracked: true,
|
||||
});
|
||||
|
||||
const checkboxRef = React.useRef<HTMLInputElement>(null);
|
||||
@ -82,19 +93,9 @@ export const UntrackedRelationships: React.VFC<UntrackedRelationshipsProps> = ({
|
||||
}, [inputStatus]);
|
||||
|
||||
const onTrackRelationship = (relationship: SuggestedRelationshipWithName) => {
|
||||
const isObjectRelationship = !!relationship.from?.constraint_name;
|
||||
|
||||
return onAddSuggestedRelationship({
|
||||
name: relationship.constraintName,
|
||||
columnNames: isObjectRelationship
|
||||
? relationship.from.columns
|
||||
: relationship.to.columns,
|
||||
relationshipType: isObjectRelationship ? 'object' : 'array',
|
||||
toTable: isObjectRelationship ? undefined : relationship.to.table,
|
||||
fromTable: relationship.from.table,
|
||||
}).then(() => {
|
||||
refetchSuggestedRelationships();
|
||||
});
|
||||
return onAddMultipleSuggestedRelationships([
|
||||
adaptTrackRelationship(relationship),
|
||||
]);
|
||||
};
|
||||
|
||||
const [isTrackingSelectedRelationships, setTrackingSelectedRelationships] =
|
||||
@ -106,24 +107,21 @@ export const UntrackedRelationships: React.VFC<UntrackedRelationshipsProps> = ({
|
||||
checkedIds.includes(rel.constraintName)
|
||||
);
|
||||
|
||||
for (const selectedRelationship of selectedRelationships) {
|
||||
await onTrackRelationship(selectedRelationship);
|
||||
}
|
||||
const trackRelationships: AddSuggestedRelationship[] =
|
||||
selectedRelationships.map(adaptTrackRelationship);
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getTrackedRelationshipsCacheKey(dataSourceName),
|
||||
});
|
||||
await onAddMultipleSuggestedRelationships(trackRelationships);
|
||||
|
||||
const plural = selectedRelationships.length > 1 ? 's' : '';
|
||||
hasuraToast({
|
||||
title: 'Success',
|
||||
message: 'Relationships tracked',
|
||||
message: `${selectedRelationships.length} relationship${plural} tracked`,
|
||||
type: 'success',
|
||||
});
|
||||
} catch (err) {
|
||||
setTrackingSelectedRelationships(false);
|
||||
}
|
||||
reset();
|
||||
refetchSuggestedRelationships();
|
||||
setTrackingSelectedRelationships(false);
|
||||
};
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { useQuery } from 'react-query';
|
||||
import { useAllSuggestedRelationships } from '../../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
|
||||
import { tableRelationships as getTableRelationships } from '../../../../DatabaseRelationships/utils/tableRelationships';
|
||||
import { DataSource } from '../../../../DataSource';
|
||||
import {
|
||||
useMetadata,
|
||||
MetadataSelectors,
|
||||
} from '../../../../hasura-metadata-api';
|
||||
import { exportMetadata } from '../../../../DataSource';
|
||||
import { useHttpClient } from '../../../../Network';
|
||||
|
||||
export const getTrackedRelationshipsCacheKey = (dataSourceName: string) => [
|
||||
@ -15,29 +12,28 @@ export const getTrackedRelationshipsCacheKey = (dataSourceName: string) => [
|
||||
export const useTrackedRelationships = (dataSourceName: string) => {
|
||||
const httpClient = useHttpClient();
|
||||
|
||||
const {
|
||||
data: metadataTables,
|
||||
isFetching: isMetadataPending,
|
||||
isLoading: isMetadataLoading,
|
||||
error: metadataError,
|
||||
refetch: refetchMetadata,
|
||||
} = useMetadata(MetadataSelectors.getTables(dataSourceName));
|
||||
const { suggestedRelationships } = useAllSuggestedRelationships({
|
||||
dataSourceName,
|
||||
isEnabled: true,
|
||||
omitTracked: false,
|
||||
});
|
||||
|
||||
const fetchRelationships = async () => {
|
||||
const _tableRelationships = [];
|
||||
if (metadataTables && !isMetadataLoading) {
|
||||
for (const metadataTable of metadataTables) {
|
||||
const fkConstraints = await DataSource(
|
||||
httpClient
|
||||
).getTableFkRelationships({
|
||||
dataSourceName,
|
||||
table: metadataTable.table,
|
||||
});
|
||||
const { metadata } = await exportMetadata({ httpClient });
|
||||
|
||||
const currentMetadataSource = metadata.sources?.find(
|
||||
source => source.name === dataSourceName
|
||||
);
|
||||
|
||||
const metadataTables = currentMetadataSource?.tables || [];
|
||||
|
||||
const _tableRelationships = [];
|
||||
if (metadataTables) {
|
||||
for (const metadataTable of metadataTables) {
|
||||
const tableRelationships = getTableRelationships(
|
||||
metadataTable,
|
||||
dataSourceName,
|
||||
fkConstraints
|
||||
suggestedRelationships
|
||||
);
|
||||
_tableRelationships.push(...tableRelationships);
|
||||
}
|
||||
@ -51,6 +47,7 @@ export const useTrackedRelationships = (dataSourceName: string) => {
|
||||
isLoading: isLoadingRelationships,
|
||||
isFetching: isFetchingRelationships,
|
||||
refetch: refetchRelationships,
|
||||
error,
|
||||
} = useQuery({
|
||||
queryFn: fetchRelationships,
|
||||
queryKey: getTrackedRelationshipsCacheKey(dataSourceName),
|
||||
@ -58,10 +55,9 @@ export const useTrackedRelationships = (dataSourceName: string) => {
|
||||
|
||||
return {
|
||||
data: relationships || [],
|
||||
isFetching: isMetadataPending || isFetchingRelationships,
|
||||
isLoading: isMetadataLoading || isLoadingRelationships,
|
||||
error: [metadataError],
|
||||
isFetching: isFetchingRelationships,
|
||||
isLoading: isLoadingRelationships,
|
||||
error: [error],
|
||||
refetchRelationships,
|
||||
refetchMetadata,
|
||||
};
|
||||
};
|
||||
|
@ -0,0 +1,155 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useQuery, useQueryClient } from 'react-query';
|
||||
import { LocalRelationship } from '../../../types';
|
||||
import { getDriverPrefix, runMetadataQuery } from '../../../../DataSource';
|
||||
import { MetadataSelectors } from '../../../../hasura-metadata-api';
|
||||
import { useMetadata } from '../../../../hasura-metadata-api/useMetadata';
|
||||
import { useHttpClient } from '../../../../Network';
|
||||
import {
|
||||
addConstraintName,
|
||||
SuggestedRelationshipsResponse,
|
||||
} from './useSuggestedRelationships';
|
||||
import { useMetadataMigration } from '../../../../MetadataAPI';
|
||||
import { NamingConvention, Table } from '../../../../hasura-metadata-types';
|
||||
import { getTrackedRelationshipsCacheKey } from '../../../../Data/TrackResources/components/hooks/useTrackedRelationships';
|
||||
|
||||
export type AddSuggestedRelationship = {
|
||||
name: string;
|
||||
columnNames: string[];
|
||||
relationshipType: 'object' | 'array';
|
||||
toTable?: Table;
|
||||
fromTable?: Table;
|
||||
};
|
||||
|
||||
type UseSuggestedRelationshipsArgs = {
|
||||
dataSourceName: string;
|
||||
existingRelationships?: LocalRelationship[];
|
||||
isEnabled: boolean;
|
||||
omitTracked: boolean;
|
||||
};
|
||||
|
||||
export const getAllSuggestedRelationshipsCacheQuery = (
|
||||
dataSourceName: string,
|
||||
omitTracked: boolean
|
||||
) => ['all_suggested_relationships', dataSourceName, omitTracked];
|
||||
|
||||
export const useAllSuggestedRelationships = ({
|
||||
dataSourceName,
|
||||
isEnabled,
|
||||
omitTracked,
|
||||
}: UseSuggestedRelationshipsArgs) => {
|
||||
const { data: metadataSource, isFetching } = useMetadata(
|
||||
MetadataSelectors.findSource(dataSourceName)
|
||||
);
|
||||
|
||||
const dataSourcePrefix = metadataSource?.kind
|
||||
? getDriverPrefix(metadataSource?.kind)
|
||||
: undefined;
|
||||
|
||||
const namingConvention: NamingConvention =
|
||||
metadataSource?.customization?.naming_convention || 'hasura-default';
|
||||
|
||||
const httpClient = useHttpClient();
|
||||
|
||||
const {
|
||||
data,
|
||||
refetch: refetchAllSuggestedRelationships,
|
||||
isLoading: isLoadingAllSuggestedRelationships,
|
||||
isFetching: isFetchingAllSuggestedRelationships,
|
||||
...rest
|
||||
} = useQuery({
|
||||
queryKey: getAllSuggestedRelationshipsCacheQuery(
|
||||
dataSourceName,
|
||||
omitTracked
|
||||
),
|
||||
queryFn: async () => {
|
||||
const body = {
|
||||
type: `${dataSourcePrefix}_suggest_relationships`,
|
||||
args: {
|
||||
omit_tracked: omitTracked,
|
||||
source: dataSourceName,
|
||||
},
|
||||
};
|
||||
const result = await runMetadataQuery<SuggestedRelationshipsResponse>({
|
||||
httpClient,
|
||||
body,
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
enabled: isEnabled && !isFetching,
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (dataSourcePrefix) {
|
||||
refetchAllSuggestedRelationships();
|
||||
}
|
||||
}, [dataSourcePrefix]);
|
||||
|
||||
const rawSuggestedRelationships = data?.relationships || [];
|
||||
|
||||
const metadataMutation = useMetadataMigration({});
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const onAddMultipleSuggestedRelationships = async (
|
||||
relationships: AddSuggestedRelationship[]
|
||||
) => {
|
||||
const queries = relationships.map(relationship => {
|
||||
return {
|
||||
type: `${dataSourcePrefix}_create_${relationship.relationshipType}_relationship`,
|
||||
args: {
|
||||
table: relationship.fromTable,
|
||||
name: relationship.name,
|
||||
source: dataSourceName,
|
||||
using: {
|
||||
foreign_key_constraint_on:
|
||||
relationship.relationshipType === 'object'
|
||||
? relationship.columnNames
|
||||
: {
|
||||
table: relationship.toTable,
|
||||
columns: relationship.columnNames,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
await metadataMutation.mutateAsync(
|
||||
{
|
||||
query: {
|
||||
type: 'bulk',
|
||||
args: queries,
|
||||
},
|
||||
},
|
||||
{
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getAllSuggestedRelationshipsCacheQuery(
|
||||
dataSourceName,
|
||||
omitTracked
|
||||
),
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: getTrackedRelationshipsCacheKey(dataSourceName),
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const relationshipsWithConstraintName = addConstraintName(
|
||||
rawSuggestedRelationships,
|
||||
namingConvention
|
||||
);
|
||||
|
||||
return {
|
||||
suggestedRelationships: relationshipsWithConstraintName,
|
||||
isLoadingSuggestedRelationships: isLoadingAllSuggestedRelationships,
|
||||
isFetchingSuggestedRelationships: isFetchingAllSuggestedRelationships,
|
||||
refetchSuggestedRelationships: refetchAllSuggestedRelationships,
|
||||
onAddMultipleSuggestedRelationships,
|
||||
...rest,
|
||||
};
|
||||
};
|
@ -145,6 +145,14 @@ export const removeExistingRelationships = ({
|
||||
return false;
|
||||
});
|
||||
|
||||
type AddSuggestedRelationship = {
|
||||
name: string;
|
||||
columnNames: string[];
|
||||
relationshipType: 'object' | 'array';
|
||||
toTable?: Table;
|
||||
fromTable?: Table;
|
||||
};
|
||||
|
||||
export const getSuggestedRelationshipsCacheQuery = (
|
||||
dataSourceName: string,
|
||||
table: Table
|
||||
@ -208,13 +216,7 @@ export const useSuggestedRelationships = ({
|
||||
relationshipType,
|
||||
toTable,
|
||||
fromTable,
|
||||
}: {
|
||||
name: string;
|
||||
columnNames: string[];
|
||||
relationshipType: 'object' | 'array';
|
||||
toTable?: Table;
|
||||
fromTable?: Table;
|
||||
}) => {
|
||||
}: AddSuggestedRelationship) => {
|
||||
setAddingSuggestedRelationship(true);
|
||||
|
||||
await metadataMutation.mutateAsync({
|
||||
|
@ -1,36 +1,7 @@
|
||||
import { DataSource } from '../../DataSource';
|
||||
import { Table } from '../../hasura-metadata-types';
|
||||
import { useHttpClient } from '../../Network';
|
||||
import { useQuery } from 'react-query';
|
||||
import { useMetadata, MetadataSelectors } from '../../hasura-metadata-api';
|
||||
import {
|
||||
DEFAULT_STALE_TIME,
|
||||
generateQueryKeys,
|
||||
} from '../utils/queryClientUtils';
|
||||
import { tableRelationships } from '../utils/tableRelationships';
|
||||
|
||||
const useFkConstraints = ({
|
||||
dataSourceName,
|
||||
table,
|
||||
}: {
|
||||
dataSourceName: string;
|
||||
table: Table;
|
||||
}) => {
|
||||
const httpClient = useHttpClient();
|
||||
|
||||
return useQuery({
|
||||
queryKey: generateQueryKeys.fkConstraints({ table, dataSourceName }),
|
||||
queryFn: async () => {
|
||||
const result = await DataSource(httpClient).getTableFkRelationships({
|
||||
dataSourceName,
|
||||
table,
|
||||
});
|
||||
return result;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
staleTime: DEFAULT_STALE_TIME,
|
||||
});
|
||||
};
|
||||
import { useAllSuggestedRelationships } from '../components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
|
||||
|
||||
export const useListAllDatabaseRelationships = ({
|
||||
dataSourceName,
|
||||
@ -47,16 +18,24 @@ export const useListAllDatabaseRelationships = ({
|
||||
} = useMetadata(MetadataSelectors.findTable(dataSourceName, table));
|
||||
|
||||
const {
|
||||
data: fkConstraints,
|
||||
isFetching: isDALIntrospectionPending,
|
||||
isLoading: isDALIntrospectionLoading,
|
||||
error: dalError,
|
||||
} = useFkConstraints({ dataSourceName, table });
|
||||
suggestedRelationships,
|
||||
isLoadingSuggestedRelationships,
|
||||
isFetchingSuggestedRelationships,
|
||||
error,
|
||||
} = useAllSuggestedRelationships({
|
||||
dataSourceName,
|
||||
isEnabled: true,
|
||||
omitTracked: false,
|
||||
});
|
||||
|
||||
return {
|
||||
data: tableRelationships(metadataTable, dataSourceName, fkConstraints),
|
||||
isFetching: isMetadataPending || isDALIntrospectionPending,
|
||||
isLoading: isMetadataLoading || isDALIntrospectionLoading,
|
||||
error: [metadataError, dalError],
|
||||
data: tableRelationships(
|
||||
metadataTable,
|
||||
dataSourceName,
|
||||
suggestedRelationships
|
||||
),
|
||||
isFetching: isMetadataPending || isFetchingSuggestedRelationships,
|
||||
isLoading: isMetadataLoading || isLoadingSuggestedRelationships,
|
||||
error: [metadataError, error],
|
||||
};
|
||||
};
|
||||
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
isSameTableObjectRelationship,
|
||||
TableFkRelationships,
|
||||
} from '../../DataSource';
|
||||
import { isSameTableObjectRelationship } from '../../DataSource';
|
||||
import { areTablesEqual } from '../../hasura-metadata-api';
|
||||
import {
|
||||
Legacy_SourceToRemoteSchemaRelationship,
|
||||
@ -19,6 +16,7 @@ import {
|
||||
LocalRelationship,
|
||||
RemoteDatabaseRelationship,
|
||||
RemoteSchemaRelationship,
|
||||
SuggestedRelationship,
|
||||
} from '../types';
|
||||
|
||||
const getKeyValuePair = (arr1: string[], arr2: string[]) => {
|
||||
@ -35,7 +33,7 @@ const getFkDefinition = (
|
||||
| SameTableObjectRelationship
|
||||
| LocalTableObjectRelationship
|
||||
| LocalTableArrayRelationship,
|
||||
fkConstraints: TableFkRelationships[]
|
||||
suggestedRelationships: SuggestedRelationship[]
|
||||
): { toTable: Table; mapping: Record<string, string> } => {
|
||||
if (isSameTableObjectRelationship(relationship)) {
|
||||
const fromTable = table;
|
||||
@ -45,18 +43,18 @@ const getFkDefinition = (
|
||||
? relationship.using.foreign_key_constraint_on
|
||||
: [relationship.using.foreign_key_constraint_on];
|
||||
|
||||
const matchingFkConstraint = fkConstraints.find(
|
||||
fkConstraint =>
|
||||
areTablesEqual(fromTable, fkConstraint.from.table) &&
|
||||
isEqual(fromColumns.sort(), fkConstraint.from.column)
|
||||
const matchingFkConstraint = suggestedRelationships.find(
|
||||
suggestedRelationship =>
|
||||
areTablesEqual(fromTable, suggestedRelationship.from.table) &&
|
||||
isEqual(fromColumns.sort(), suggestedRelationship.from.columns)
|
||||
);
|
||||
|
||||
return {
|
||||
toTable: matchingFkConstraint?.to.table,
|
||||
mapping: matchingFkConstraint
|
||||
? getKeyValuePair(
|
||||
matchingFkConstraint.from.column,
|
||||
matchingFkConstraint.to.column
|
||||
matchingFkConstraint.from.columns,
|
||||
matchingFkConstraint.to.columns
|
||||
)
|
||||
: {},
|
||||
};
|
||||
@ -68,17 +66,18 @@ const getFkDefinition = (
|
||||
? [relationship.using.foreign_key_constraint_on.column]
|
||||
: relationship.using.foreign_key_constraint_on.columns;
|
||||
|
||||
const matchingFkConstraint = fkConstraints.find(
|
||||
fkConstraint =>
|
||||
areTablesEqual(toTable, fkConstraint.to.table) &&
|
||||
isEqual(toColumn.sort(), fkConstraint.to.column)
|
||||
const matchingFkConstraint = suggestedRelationships.find(
|
||||
suggestedRelationship =>
|
||||
areTablesEqual(toTable, suggestedRelationship.to.table) &&
|
||||
isEqual(toColumn.sort(), suggestedRelationship.to.columns)
|
||||
);
|
||||
|
||||
return {
|
||||
toTable: matchingFkConstraint?.from.table,
|
||||
mapping: matchingFkConstraint
|
||||
? getKeyValuePair(
|
||||
matchingFkConstraint.to.column,
|
||||
matchingFkConstraint.from.column
|
||||
matchingFkConstraint.to.columns,
|
||||
matchingFkConstraint.from.columns
|
||||
)
|
||||
: {},
|
||||
};
|
||||
@ -110,12 +109,12 @@ export const adaptLocalObjectRelationshipWithFkConstraint = ({
|
||||
table,
|
||||
dataSourceName,
|
||||
relationship,
|
||||
fkConstraints,
|
||||
suggestedRelationships,
|
||||
}: {
|
||||
table: Table;
|
||||
dataSourceName: string;
|
||||
relationship: SameTableObjectRelationship | LocalTableObjectRelationship;
|
||||
fkConstraints: TableFkRelationships[];
|
||||
suggestedRelationships: SuggestedRelationship[];
|
||||
}): LocalRelationship => {
|
||||
return {
|
||||
name: relationship.name,
|
||||
@ -123,7 +122,7 @@ export const adaptLocalObjectRelationshipWithFkConstraint = ({
|
||||
fromTable: table,
|
||||
relationshipType: 'Object',
|
||||
type: 'localRelationship',
|
||||
definition: getFkDefinition(table, relationship, fkConstraints),
|
||||
definition: getFkDefinition(table, relationship, suggestedRelationships),
|
||||
};
|
||||
};
|
||||
|
||||
@ -153,12 +152,12 @@ export const adaptLocalArrayRelationshipWithFkConstraint = ({
|
||||
table,
|
||||
dataSourceName,
|
||||
relationship,
|
||||
fkConstraints,
|
||||
suggestedRelationships,
|
||||
}: {
|
||||
table: Table;
|
||||
dataSourceName: string;
|
||||
relationship: LocalTableArrayRelationship;
|
||||
fkConstraints: TableFkRelationships[];
|
||||
suggestedRelationships: SuggestedRelationship[];
|
||||
}): LocalRelationship => {
|
||||
return {
|
||||
name: relationship.name,
|
||||
@ -166,7 +165,7 @@ export const adaptLocalArrayRelationshipWithFkConstraint = ({
|
||||
fromTable: table,
|
||||
relationshipType: 'Array',
|
||||
type: 'localRelationship',
|
||||
definition: getFkDefinition(table, relationship, fkConstraints),
|
||||
definition: getFkDefinition(table, relationship, suggestedRelationships),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,6 @@ import {
|
||||
isManualArrayRelationship,
|
||||
isManualObjectRelationship,
|
||||
isRemoteSchemaRelationship,
|
||||
TableFkRelationships,
|
||||
} from '../../DataSource';
|
||||
import { MetadataTable } from '../../hasura-metadata-types';
|
||||
import {
|
||||
@ -11,6 +10,7 @@ import {
|
||||
Relationship,
|
||||
RemoteDatabaseRelationship,
|
||||
RemoteSchemaRelationship,
|
||||
SuggestedRelationship,
|
||||
} from '../types';
|
||||
import {
|
||||
adaptLegacyRemoteSchemaRelationship,
|
||||
@ -25,7 +25,7 @@ import {
|
||||
export function tableRelationships(
|
||||
metadataTable: MetadataTable | undefined,
|
||||
dataSourceName: string,
|
||||
fkConstraints: TableFkRelationships[] | undefined
|
||||
suggestedRelationships: SuggestedRelationship[]
|
||||
): Relationship[] {
|
||||
const table = metadataTable?.table;
|
||||
// adapt local array relationships
|
||||
@ -43,7 +43,7 @@ export function tableRelationships(
|
||||
table,
|
||||
dataSourceName,
|
||||
relationship,
|
||||
fkConstraints: fkConstraints ?? [],
|
||||
suggestedRelationships,
|
||||
});
|
||||
});
|
||||
|
||||
@ -61,7 +61,7 @@ export function tableRelationships(
|
||||
table,
|
||||
dataSourceName,
|
||||
relationship,
|
||||
fkConstraints: fkConstraints ?? [],
|
||||
suggestedRelationships,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { areTablesEqual } from '../../../../../hasura-metadata-api';
|
||||
import { tableRelationships } from '../../../../../DatabaseRelationships/utils/tableRelationships';
|
||||
import { useTablesFkConstraints } from './useTablesFkConstraints';
|
||||
import { useTablesWithColumns } from './useTablesWithColumns';
|
||||
import { useSources } from '../../../../../MetadataAPI';
|
||||
import { Tables } from '../components';
|
||||
import { useAllSuggestedRelationships } from '../../../../../DatabaseRelationships/components/SuggestedRelationships/hooks/useAllSuggestedRelationships';
|
||||
|
||||
export const usePermissionTables = ({
|
||||
dataSourceName,
|
||||
@ -14,23 +13,26 @@ export const usePermissionTables = ({
|
||||
const { data: tables, isLoading: isLoadingTables } = useTablesWithColumns({
|
||||
dataSourceName,
|
||||
});
|
||||
const { data: fkConstraints, isLoading: isDALIntrospectionLoading } =
|
||||
useTablesFkConstraints({ dataSourceName, tables });
|
||||
if (isLoadingTables || isDALIntrospectionLoading || isLoadingSources)
|
||||
|
||||
const { suggestedRelationships, isLoadingSuggestedRelationships } =
|
||||
useAllSuggestedRelationships({
|
||||
dataSourceName,
|
||||
isEnabled: true,
|
||||
omitTracked: false,
|
||||
});
|
||||
|
||||
if (isLoadingTables || isLoadingSuggestedRelationships || isLoadingSources)
|
||||
return [];
|
||||
|
||||
return (
|
||||
tables?.map(({ metadataTable, columns }) => {
|
||||
const relationships = fkConstraints?.find(({ table }) =>
|
||||
areTablesEqual(table, metadataTable.table)
|
||||
)?.relationships;
|
||||
return {
|
||||
table: metadataTable.table,
|
||||
dataSource: sources?.find(source => source.name === dataSourceName),
|
||||
relationships: tableRelationships(
|
||||
metadataTable,
|
||||
dataSourceName,
|
||||
relationships
|
||||
suggestedRelationships
|
||||
),
|
||||
columns,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user