Implement eager load relations on graphqlQueries (#4391)
* Implement eager load relations on graphqlQueries * Fix tests * Fixes * Fixes
This commit is contained in:
@ -0,0 +1,329 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const formatGQLString = (inputString: string) =>
|
||||
inputString.replace(/^\s*[\r\n]/gm, '');
|
||||
|
||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
);
|
||||
|
||||
if (!personObjectMetadataItem) {
|
||||
throw new Error('ObjectMetadataItem not found');
|
||||
}
|
||||
|
||||
describe('mapFieldMetadataToGraphQLQuery', () => {
|
||||
it('should return fieldName if simpleValue', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'id',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual('id');
|
||||
});
|
||||
it('should return fieldName if composite', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'name',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}`);
|
||||
});
|
||||
it('should not return relation if depth is < 1', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
relationFieldDepth: 0,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual('');
|
||||
});
|
||||
|
||||
it('should return relation if it matches depth', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
relationFieldDepth: 1,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`company
|
||||
{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
domainName
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}`);
|
||||
});
|
||||
it('should return relation with all sub relations if it matches depth', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
relationFieldDepth: 2,
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`company
|
||||
{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
accountOwner
|
||||
{
|
||||
__typename
|
||||
colorScheme
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
locale
|
||||
userId
|
||||
avatarUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
id
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
attachments
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
updatedAt
|
||||
createdAt
|
||||
name
|
||||
personId
|
||||
activityId
|
||||
companyId
|
||||
id
|
||||
authorId
|
||||
type
|
||||
fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
domainName
|
||||
opportunities
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
personId
|
||||
pointOfContactId
|
||||
updatedAt
|
||||
companyId
|
||||
pipelineStepId
|
||||
probability
|
||||
closeDate
|
||||
amount
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
activityTargets
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
updatedAt
|
||||
createdAt
|
||||
personId
|
||||
activityId
|
||||
companyId
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
favorites
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
id
|
||||
companyId
|
||||
createdAt
|
||||
personId
|
||||
position
|
||||
workspaceMemberId
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
people
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
city
|
||||
email
|
||||
jobTitle
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
phone
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
updatedAt
|
||||
avatarUrl
|
||||
companyId
|
||||
}
|
||||
}
|
||||
}
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}`);
|
||||
});
|
||||
|
||||
it('should return eagerLoaded relations', async () => {
|
||||
const res = mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
relationFieldDepth: 2,
|
||||
relationFieldEagerLoad: { accountOwner: true, people: true },
|
||||
field: personObjectMetadataItem.fields.find(
|
||||
(field) => field.name === 'company',
|
||||
)!,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`company
|
||||
{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
accountOwner
|
||||
{
|
||||
__typename
|
||||
colorScheme
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
locale
|
||||
userId
|
||||
avatarUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
id
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
domainName
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
people
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
city
|
||||
email
|
||||
jobTitle
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
phone
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
updatedAt
|
||||
avatarUrl
|
||||
companyId
|
||||
}
|
||||
}
|
||||
}
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,281 @@
|
||||
import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
|
||||
const mockObjectMetadataItems = getObjectMetadataItemsMock();
|
||||
|
||||
const formatGQLString = (inputString: string) =>
|
||||
inputString.replace(/^\s*[\r\n]/gm, '');
|
||||
|
||||
const personObjectMetadataItem = mockObjectMetadataItems.find(
|
||||
(item) => item.nameSingular === 'person',
|
||||
);
|
||||
|
||||
if (!personObjectMetadataItem) {
|
||||
throw new Error('ObjectMetadataItem not found');
|
||||
}
|
||||
|
||||
describe('mapObjectMetadataToGraphQLQuery', () => {
|
||||
it('should return typename if depth < 0', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
depth: -1,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`{
|
||||
__typename
|
||||
}`);
|
||||
});
|
||||
|
||||
it('should return depth 0 if depth = 0', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
depth: 0,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
city
|
||||
email
|
||||
jobTitle
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
phone
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
updatedAt
|
||||
avatarUrl
|
||||
companyId
|
||||
}`);
|
||||
});
|
||||
|
||||
it('should return depth 1 if depth = 1', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
depth: 1,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`{
|
||||
__typename
|
||||
opportunities
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
personId
|
||||
pointOfContactId
|
||||
updatedAt
|
||||
companyId
|
||||
pipelineStepId
|
||||
probability
|
||||
closeDate
|
||||
amount
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
id
|
||||
pointOfContactForOpportunities
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
personId
|
||||
pointOfContactId
|
||||
updatedAt
|
||||
companyId
|
||||
pipelineStepId
|
||||
probability
|
||||
closeDate
|
||||
amount
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
createdAt
|
||||
company
|
||||
{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
domainName
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}
|
||||
city
|
||||
email
|
||||
activityTargets
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
updatedAt
|
||||
createdAt
|
||||
personId
|
||||
activityId
|
||||
companyId
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
jobTitle
|
||||
favorites
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
id
|
||||
companyId
|
||||
createdAt
|
||||
personId
|
||||
position
|
||||
workspaceMemberId
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
attachments
|
||||
{
|
||||
edges {
|
||||
node {
|
||||
__typename
|
||||
updatedAt
|
||||
createdAt
|
||||
name
|
||||
personId
|
||||
activityId
|
||||
companyId
|
||||
id
|
||||
authorId
|
||||
type
|
||||
fullPath
|
||||
}
|
||||
}
|
||||
}
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
phone
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
updatedAt
|
||||
avatarUrl
|
||||
companyId
|
||||
}`);
|
||||
});
|
||||
|
||||
it('should eager load only specified relations', async () => {
|
||||
const res = mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems: mockObjectMetadataItems,
|
||||
objectMetadataItem: personObjectMetadataItem,
|
||||
eagerLoadedRelations: { company: true },
|
||||
depth: 1,
|
||||
});
|
||||
expect(formatGQLString(res)).toEqual(`{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
id
|
||||
createdAt
|
||||
company
|
||||
{
|
||||
__typename
|
||||
xLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
domainName
|
||||
annualRecurringRevenue
|
||||
{
|
||||
amountMicros
|
||||
currencyCode
|
||||
}
|
||||
createdAt
|
||||
address
|
||||
updatedAt
|
||||
name
|
||||
accountOwnerId
|
||||
employees
|
||||
id
|
||||
idealCustomerProfile
|
||||
}
|
||||
city
|
||||
email
|
||||
jobTitle
|
||||
name
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
phone
|
||||
linkedinLink
|
||||
{
|
||||
label
|
||||
url
|
||||
}
|
||||
updatedAt
|
||||
avatarUrl
|
||||
companyId
|
||||
}`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,117 @@
|
||||
import { shouldFieldBeQueried } from '@/object-metadata/utils/shouldFieldBeQueried';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
describe('shouldFieldBeQueried', () => {
|
||||
describe('if field is not relation', () => {
|
||||
it('should be queried if depth is undefined', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Boolean },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should be queried depth = 0', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 0,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Boolean },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should be queried depth > 0', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 1,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Boolean },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should NOT be queried depth < 0', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: -1,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Boolean },
|
||||
});
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
it('should not depends on eagerLoadedRelation', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 0,
|
||||
eagerLoadedRelations: {
|
||||
fieldName: true,
|
||||
},
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Boolean },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('if field is relation', () => {
|
||||
it('should be queried if eagerLoadedRelation and depth are undefined', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should be queried if eagerLoadedRelation is undefined and depth = 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 1,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should be queried if eagerLoadedRelation is undefined and depth > 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 2,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should NOT be queried if eagerLoadedRelation is undefined and depth < 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 0,
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
it('should be queried if eagerLoadedRelation is matching and depth > 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 1,
|
||||
eagerLoadedRelations: { fieldName: true },
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(true);
|
||||
});
|
||||
|
||||
it('should NOT be queried if eagerLoadedRelation is matching and depth < 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 0,
|
||||
eagerLoadedRelations: { fieldName: true },
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
it('should NOT be queried if eagerLoadedRelation is not matching (falsy) and depth < 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 1,
|
||||
eagerLoadedRelations: { fieldName: false },
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
|
||||
it('should NOT be queried if eagerLoadedRelation is not matching and depth < 1', () => {
|
||||
const res = shouldFieldBeQueried({
|
||||
depth: 0,
|
||||
eagerLoadedRelations: { anotherFieldName: true },
|
||||
field: { name: 'fieldName', type: FieldMetadataType.Relation },
|
||||
});
|
||||
expect(res).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,112 @@
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapObjectMetadataToGraphQLQuery } from '@/object-metadata/utils/mapObjectMetadataToGraphQLQuery';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { FieldMetadataItem } from '../types/FieldMetadataItem';
|
||||
|
||||
export const mapFieldMetadataToGraphQLQuery = ({
|
||||
objectMetadataItems,
|
||||
field,
|
||||
relationFieldDepth = 0,
|
||||
relationFieldEagerLoad,
|
||||
}: {
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
field: Pick<
|
||||
FieldMetadataItem,
|
||||
'name' | 'type' | 'toRelationMetadata' | 'fromRelationMetadata'
|
||||
>;
|
||||
relationFieldDepth?: number;
|
||||
relationFieldEagerLoad?: Record<string, any>;
|
||||
}): any => {
|
||||
const fieldType = field.type;
|
||||
|
||||
const fieldIsSimpleValue = (
|
||||
[
|
||||
'UUID',
|
||||
'TEXT',
|
||||
'PHONE',
|
||||
'DATE_TIME',
|
||||
'EMAIL',
|
||||
'NUMBER',
|
||||
'BOOLEAN',
|
||||
'RATING',
|
||||
'SELECT',
|
||||
'POSITION',
|
||||
] as FieldMetadataType[]
|
||||
).includes(fieldType);
|
||||
|
||||
if (fieldIsSimpleValue) {
|
||||
return field.name;
|
||||
} else if (
|
||||
fieldType === 'RELATION' &&
|
||||
field.toRelationMetadata?.relationType === 'ONE_TO_MANY' &&
|
||||
relationFieldDepth > 0
|
||||
) {
|
||||
const relationMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id ===
|
||||
(field.toRelationMetadata as any)?.fromObjectMetadata?.id,
|
||||
);
|
||||
|
||||
if (isUndefined(relationMetadataItem)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `${field.name}
|
||||
${mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems,
|
||||
objectMetadataItem: relationMetadataItem,
|
||||
eagerLoadedRelations: relationFieldEagerLoad,
|
||||
depth: relationFieldDepth - 1,
|
||||
})}`;
|
||||
} else if (
|
||||
fieldType === 'RELATION' &&
|
||||
field.fromRelationMetadata?.relationType === 'ONE_TO_MANY' &&
|
||||
relationFieldDepth > 0
|
||||
) {
|
||||
const relationMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id ===
|
||||
(field.fromRelationMetadata as any)?.toObjectMetadata?.id,
|
||||
);
|
||||
|
||||
if (isUndefined(relationMetadataItem)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return `${field.name}
|
||||
{
|
||||
edges {
|
||||
node ${mapObjectMetadataToGraphQLQuery({
|
||||
objectMetadataItems,
|
||||
objectMetadataItem: relationMetadataItem,
|
||||
eagerLoadedRelations: relationFieldEagerLoad,
|
||||
depth: relationFieldDepth - 1,
|
||||
})}
|
||||
}
|
||||
}`;
|
||||
} 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 '';
|
||||
};
|
||||
@ -0,0 +1,37 @@
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { mapFieldMetadataToGraphQLQuery } from '@/object-metadata/utils/mapFieldMetadataToGraphQLQuery';
|
||||
import { shouldFieldBeQueried } from '@/object-metadata/utils/shouldFieldBeQueried';
|
||||
|
||||
export const mapObjectMetadataToGraphQLQuery = ({
|
||||
objectMetadataItems,
|
||||
objectMetadataItem,
|
||||
depth = 1,
|
||||
eagerLoadedRelations,
|
||||
}: {
|
||||
objectMetadataItems: ObjectMetadataItem[];
|
||||
objectMetadataItem: Pick<ObjectMetadataItem, 'fields'>;
|
||||
depth?: number;
|
||||
eagerLoadedRelations?: Record<string, any>;
|
||||
}): any => {
|
||||
return `{
|
||||
__typename
|
||||
${(objectMetadataItem?.fields ?? [])
|
||||
.filter((field) => field.isActive)
|
||||
.filter((field) =>
|
||||
shouldFieldBeQueried({ field, depth, eagerLoadedRelations }),
|
||||
)
|
||||
.map((field) =>
|
||||
mapFieldMetadataToGraphQLQuery({
|
||||
objectMetadataItems,
|
||||
field,
|
||||
relationFieldDepth: depth,
|
||||
relationFieldEagerLoad: isUndefined(eagerLoadedRelations)
|
||||
? undefined
|
||||
: eagerLoadedRelations[field.name] ?? undefined,
|
||||
}),
|
||||
)
|
||||
.join('\n')}
|
||||
}`;
|
||||
};
|
||||
@ -0,0 +1,36 @@
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
|
||||
import { FieldType } from '@/object-record/record-field/types/FieldType';
|
||||
|
||||
import { FieldMetadataItem } from '../types/FieldMetadataItem';
|
||||
|
||||
export const shouldFieldBeQueried = ({
|
||||
field,
|
||||
depth,
|
||||
eagerLoadedRelations,
|
||||
}: {
|
||||
field: Pick<FieldMetadataItem, 'name' | 'type'>;
|
||||
depth?: number;
|
||||
eagerLoadedRelations?: Record<string, boolean>;
|
||||
}): any => {
|
||||
const fieldType = field.type as FieldType;
|
||||
|
||||
if (!isUndefined(depth) && depth < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isUndefined(depth) && depth < 1 && fieldType === 'RELATION') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
fieldType === 'RELATION' &&
|
||||
!isUndefined(eagerLoadedRelations) &&
|
||||
(isUndefined(eagerLoadedRelations[field.name]) ||
|
||||
!eagerLoadedRelations[field.name])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
Reference in New Issue
Block a user