feat: schema-builder and resolver-builder can handle relations (#2398)

* feat: wip add relation

* feat: add relation for custom and standards objects

* fix: use enum instead of magic string

* fix: remove dead code & fix tests

* fix: typo

* fix: BooleanFilter is missing

* fix: Malformed result error
This commit is contained in:
Jérémy M
2023-11-10 12:32:02 +01:00
committed by GitHub
parent edd152910d
commit 6a700ad1a5
71 changed files with 1842 additions and 1005 deletions

View File

@ -0,0 +1,108 @@
import { forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
import { GraphQLResolveInfo } from 'graphql';
import { FieldMetadataInterface } from 'src/tenant/schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { isCompositeFieldMetadataType } from 'src/tenant/utils/is-composite-field-metadata-type.util';
import { RelationMetadataType } from 'src/metadata/relation-metadata/relation-metadata.entity';
import {
deduceRelationDirection,
RelationDirection,
} from 'src/tenant/utils/deduce-relation-direction.util';
import { getFieldArgumentsByKey } from 'src/tenant/query-builder/utils/get-field-arguments-by-key.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsStringFactory } from './args-string.factory';
@Injectable()
export class CompositeFieldAliasFactory {
private logger = new Logger(CompositeFieldAliasFactory.name);
constructor(
@Inject(forwardRef(() => FieldsStringFactory))
private readonly fieldsStringFactory: FieldsStringFactory,
private readonly argsStringFactory: ArgsStringFactory,
) {}
create(
fieldKey: string,
fieldValue: any,
fieldMetadata: FieldMetadataInterface,
info: GraphQLResolveInfo,
) {
if (!isCompositeFieldMetadataType(fieldMetadata.type)) {
throw new Error(`Field ${fieldMetadata.name} is not a composite field`);
}
switch (fieldMetadata.type) {
case FieldMetadataType.RELATION:
return this.createRelationAlias(
fieldKey,
fieldValue,
fieldMetadata,
info,
);
}
return null;
}
private createRelationAlias(
fieldKey: string,
fieldValue: any,
fieldMetadata: FieldMetadataInterface,
info: GraphQLResolveInfo,
) {
const relationMetadata =
fieldMetadata.fromRelationMetadata ?? fieldMetadata.toRelationMetadata;
if (!relationMetadata) {
throw new Error(
`Relation metadata not found for field ${fieldMetadata.name}`,
);
}
const targetTableName = relationMetadata.toObjectMetadata.targetTableName;
const relationDirection = deduceRelationDirection(
fieldMetadata.objectId,
relationMetadata,
);
// If it's a relation destination is of kind MANY, we need to add the collection suffix and extract the args
if (
relationMetadata.relationType === RelationMetadataType.ONE_TO_MANY &&
relationDirection === RelationDirection.FROM
) {
const args = getFieldArgumentsByKey(info, fieldKey);
const argsString = this.argsStringFactory.create(
args,
relationMetadata.toObjectMetadata.fields,
);
return `
${fieldKey}: ${targetTableName}Collection${
argsString ? `(${argsString})` : ''
} {
${this.fieldsStringFactory.createFieldsStringRecursive(
info,
fieldValue,
relationMetadata.toObjectMetadata.fields,
)}
}
`;
}
// Otherwise it means it's a relation destination is of kind ONE
return `
${fieldKey}: ${targetTableName} {
${this.fieldsStringFactory.createFieldsStringRecursive(
info,
fieldValue,
relationMetadata.toObjectMetadata.fields,
)}
}
`;
}
}