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