Implement eager load relations on graphqlQueries (#4391)
* Implement eager load relations on graphqlQueries * Fix tests * Fixes * Fixes
This commit is contained in:
@ -1,180 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { RecoilRoot, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useMapFieldMetadataToGraphQLQuery } from '@/object-metadata/hooks/useMapFieldMetadataToGraphQLQuery';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { RelationMetadataType } from '~/generated/graphql';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const formatGQLString = (inputString: string) =>
|
||||
inputString.replace(/^\s*[\r\n]/gm, '');
|
||||
|
||||
const getOneToManyRelation = () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'opportunity',
|
||||
)!;
|
||||
|
||||
return {
|
||||
field: objectMetadataItem.fields.find((field) => field.name === 'company')!,
|
||||
res: `company
|
||||
{
|
||||
__typename
|
||||
id
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
domainName
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}`,
|
||||
};
|
||||
};
|
||||
|
||||
const getOneToOneRelationField = () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'opportunity',
|
||||
)!;
|
||||
|
||||
const oneToManyfield = objectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!;
|
||||
|
||||
const field: FieldMetadataItem = {
|
||||
...oneToManyfield,
|
||||
toRelationMetadata: {
|
||||
...oneToManyfield.toRelationMetadata!,
|
||||
relationType: RelationMetadataType.OneToOne,
|
||||
},
|
||||
};
|
||||
|
||||
return field;
|
||||
};
|
||||
|
||||
const getOneToManyFromRelationField = () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const field = objectMetadataItem.fields.find(
|
||||
(field) => field.name === 'opportunities',
|
||||
)!;
|
||||
|
||||
return {
|
||||
field,
|
||||
res: `opportunities
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
id
|
||||
personId
|
||||
pointOfContactId
|
||||
updatedAt
|
||||
companyId
|
||||
pipelineStepId
|
||||
probability
|
||||
closeDate
|
||||
amount
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
||||
};
|
||||
|
||||
const getFullNameRelation = () => {
|
||||
const objectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
)!;
|
||||
|
||||
const field = objectMetadataItem.fields.find(
|
||||
(field) => field.name === 'name',
|
||||
)!;
|
||||
|
||||
return {
|
||||
field,
|
||||
res: `\n name\n {\n firstName\n lastName\n }\n `,
|
||||
};
|
||||
};
|
||||
|
||||
describe('useMapFieldMetadataToGraphQLQuery', () => {
|
||||
it('should work as expected', async () => {
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const setMetadataItems = useSetRecoilState(objectMetadataItemsState());
|
||||
setMetadataItems(mockObjectMetadataItems);
|
||||
|
||||
return {
|
||||
mapFieldMetadataToGraphQLQuery: useMapFieldMetadataToGraphQLQuery(),
|
||||
};
|
||||
},
|
||||
{
|
||||
wrapper: RecoilRoot,
|
||||
},
|
||||
);
|
||||
|
||||
const oneToManyRelation = getOneToManyRelation();
|
||||
|
||||
const { mapFieldMetadataToGraphQLQuery } = result.current;
|
||||
|
||||
const oneToManyRelationFieldRes = mapFieldMetadataToGraphQLQuery({
|
||||
field: oneToManyRelation.field,
|
||||
});
|
||||
|
||||
expect(formatGQLString(oneToManyRelationFieldRes)).toEqual(
|
||||
oneToManyRelation.res,
|
||||
);
|
||||
|
||||
const oneToOneRelation = getOneToOneRelationField();
|
||||
|
||||
const oneToOneRelationFieldRes = mapFieldMetadataToGraphQLQuery({
|
||||
field: oneToOneRelation,
|
||||
});
|
||||
|
||||
expect(formatGQLString(oneToOneRelationFieldRes)).toEqual(
|
||||
oneToManyRelation.res,
|
||||
);
|
||||
|
||||
const oneToManyFromRelation = getOneToManyFromRelationField();
|
||||
const oneToManyFromRelationFieldRes = mapFieldMetadataToGraphQLQuery({
|
||||
field: oneToManyFromRelation.field,
|
||||
});
|
||||
|
||||
expect(formatGQLString(oneToManyFromRelationFieldRes)).toEqual(
|
||||
oneToManyFromRelation.res,
|
||||
);
|
||||
|
||||
const fullNameRelation = getFullNameRelation();
|
||||
const fullNameFieldRes = mapFieldMetadataToGraphQLQuery({
|
||||
field: fullNameRelation.field,
|
||||
});
|
||||
|
||||
expect(fullNameFieldRes).toEqual(fullNameRelation.res);
|
||||
});
|
||||
});
|
||||
@ -1,151 +0,0 @@
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { FieldType } from '@/object-record/record-field/types/FieldType';
|
||||
|
||||
import { FieldMetadataItem } from '../types/FieldMetadataItem';
|
||||
|
||||
export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState());
|
||||
|
||||
const mapFieldMetadataToGraphQLQuery = ({
|
||||
field,
|
||||
depth = 2,
|
||||
}: {
|
||||
field: FieldMetadataItem;
|
||||
depth?: number;
|
||||
}): any => {
|
||||
// TODO: parse
|
||||
const fieldType = field.type as FieldType;
|
||||
|
||||
const fieldIsSimpleValue = (
|
||||
[
|
||||
'UUID',
|
||||
'TEXT',
|
||||
'PHONE',
|
||||
'DATE_TIME',
|
||||
'EMAIL',
|
||||
'NUMBER',
|
||||
'BOOLEAN',
|
||||
'RATING',
|
||||
'SELECT',
|
||||
'POSITION',
|
||||
] as FieldType[]
|
||||
).includes(fieldType);
|
||||
|
||||
if (fieldIsSimpleValue) {
|
||||
return field.name;
|
||||
} else if (
|
||||
fieldType === 'RELATION' &&
|
||||
field.toRelationMetadata?.relationType === 'ONE_TO_MANY'
|
||||
) {
|
||||
const relationMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id ===
|
||||
(field.toRelationMetadata as any)?.fromObjectMetadata?.id,
|
||||
);
|
||||
|
||||
if (depth > 1) {
|
||||
return `${field.name}
|
||||
{
|
||||
__typename
|
||||
id
|
||||
${(relationMetadataItem?.fields ?? [])
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery({
|
||||
field,
|
||||
depth: depth - 1,
|
||||
}),
|
||||
)
|
||||
.join('\n')}
|
||||
}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else if (
|
||||
fieldType === 'RELATION' &&
|
||||
field.toRelationMetadata?.relationType === 'ONE_TO_ONE'
|
||||
) {
|
||||
const relationMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id ===
|
||||
(field.toRelationMetadata as any)?.fromObjectMetadata?.id,
|
||||
);
|
||||
|
||||
if (depth > 1) {
|
||||
return `${field.name}
|
||||
{
|
||||
__typename
|
||||
id
|
||||
${(relationMetadataItem?.fields ?? [])
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery({
|
||||
field,
|
||||
depth: depth - 1,
|
||||
}),
|
||||
)
|
||||
.join('\n')}
|
||||
}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else if (
|
||||
fieldType === 'RELATION' &&
|
||||
field.fromRelationMetadata?.relationType === 'ONE_TO_MANY'
|
||||
) {
|
||||
const relationMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id ===
|
||||
(field.fromRelationMetadata as any)?.toObjectMetadata?.id,
|
||||
);
|
||||
|
||||
if (depth > 1) {
|
||||
return `${field.name}
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
id
|
||||
${(relationMetadataItem?.fields ?? [])
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery({
|
||||
field,
|
||||
depth: depth - 1,
|
||||
}),
|
||||
)
|
||||
.join('\n')}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
} else if (fieldType === 'LINK') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
`;
|
||||
} else if (fieldType === 'CURRENCY') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
`;
|
||||
} else if (fieldType === 'FULL_NAME') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
return mapFieldMetadataToGraphQLQuery;
|
||||
};
|
||||
@ -40,6 +40,7 @@ export const EMPTY_MUTATION = gql`
|
||||
export const useObjectMetadataItem = (
|
||||
{ objectNameSingular }: ObjectMetadataItemIdentifier,
|
||||
depth?: number,
|
||||
eagerLoadedRelations?: Record<string, any>,
|
||||
) => {
|
||||
const currentWorkspace = useRecoilValue(currentWorkspaceState());
|
||||
|
||||
@ -90,6 +91,7 @@ export const useObjectMetadataItem = (
|
||||
const findManyRecordsQuery = generateFindManyRecordsQuery({
|
||||
objectMetadataItem,
|
||||
depth,
|
||||
eagerLoadedRelations,
|
||||
});
|
||||
|
||||
const generateFindDuplicateRecordsQuery =
|
||||
|
||||
Reference in New Issue
Block a user