feat: Adding support for new FieldMetadataType with Postgres enums (#2674)

* feat: add enum type (RATING, SELECT, MULTI_SELECT)

feat: wip enum type

feat: try to alter enum

feat: wip enum

feat: wip enum

feat: schema-builder can handle enum

fix: return default value in field metadata response

* fix: create fieldMedata with options

* fix: lint issues

* fix: rename abstract factory

* feat: drop `PHONE` and `EMAIL` fieldMetadata types

* feat: drop `VARCHAR` fieldMetadata type and rely on `TEXT`

* Revert "feat: drop `PHONE` and `EMAIL` fieldMetadata types"

This reverts commit 3857539f7d42f17c81f6ab92a6db950140b3c8e5.
This commit is contained in:
Jérémy M
2023-11-30 15:24:26 +01:00
committed by GitHub
parent c2131a29b8
commit 6e6f0af26e
92 changed files with 1371 additions and 484 deletions
@@ -3,7 +3,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLFieldConfigMap, GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
@@ -3,7 +3,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLOutputType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import {
TypeMapperService,
@@ -3,7 +3,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLFieldConfigMap, GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
@@ -3,7 +3,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLOutputType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import {
TypeMapperService,
@@ -0,0 +1,85 @@
import { Injectable, Logger } from '@nestjs/common';
import { GraphQLEnumType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
import {
FieldMetadataComplexOptions,
FieldMetadataDefaultOptions,
} from 'src/metadata/field-metadata/dtos/options.input';
import { isEnumFieldMetadataType } from 'src/metadata/field-metadata/utils/is-enum-field-metadata-type.util';
export interface EnumTypeDefinition {
target: string;
type: GraphQLEnumType;
}
@Injectable()
export class EnumTypeDefinitionFactory {
private readonly logger = new Logger(EnumTypeDefinitionFactory.name);
public create(
objectMetadata: ObjectMetadataInterface,
options: WorkspaceBuildSchemaOptions,
): EnumTypeDefinition[] {
const enumTypeDefinitions: EnumTypeDefinition[] = [];
for (const fieldMetadata of objectMetadata.fields) {
if (!isEnumFieldMetadataType(fieldMetadata.type)) {
continue;
}
enumTypeDefinitions.push({
target: fieldMetadata.id,
type: this.generateEnum(
objectMetadata.nameSingular,
fieldMetadata,
options,
),
});
}
return enumTypeDefinitions;
}
private generateEnum(
objectName: string,
fieldMetadata: FieldMetadataInterface,
options: WorkspaceBuildSchemaOptions,
): GraphQLEnumType {
// FixMe: It's a hack until Typescript get fixed on union types for reduce function
// https://github.com/microsoft/TypeScript/issues/36390
const enumOptions = fieldMetadata.options as Array<
FieldMetadataDefaultOptions | FieldMetadataComplexOptions
>;
if (!enumOptions) {
this.logger.error(
`Enum options are not defined for ${fieldMetadata.name}`,
{
fieldMetadata,
options,
},
);
throw new Error(`Enum options are not defined for ${fieldMetadata.name}`);
}
return new GraphQLEnumType({
name: `${pascalCase(objectName)}${pascalCase(fieldMetadata.name)}Enum`,
description: fieldMetadata.description,
values: enumOptions.reduce((acc, enumOption) => {
acc[enumOption.value] = {
value: enumOption.value,
description: enumOption.label,
};
return acc;
}, {} as { [key: string]: { value: string; description: string } }),
});
}
}
@@ -7,13 +7,13 @@ import {
} from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { objectContainsCompositeField } from 'src/workspace/workspace-schema-builder/utils/object-contains-composite-field';
import { objectContainsRelationField } from 'src/workspace/workspace-schema-builder/utils/object-contains-relation-field';
import { getResolverArgs } from 'src/workspace/workspace-schema-builder/utils/get-resolver-args.util';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
import {
RelationDirection,
deduceRelationDirection,
@@ -54,7 +54,7 @@ export class ExtendObjectTypeDefinitionFactory {
objectMetadata.id,
kind,
);
const containsCompositeField = objectContainsCompositeField(objectMetadata);
const containsRelationField = objectContainsRelationField(objectMetadata);
if (!gqlType) {
this.logger.error(
@@ -71,7 +71,7 @@ export class ExtendObjectTypeDefinitionFactory {
}
// Security check to avoid extending an object that does not need to be extended
if (!containsCompositeField) {
if (!containsRelationField) {
this.logger.error(
`This object does not need to be extended: ${objectMetadata.id.toString()}`,
{
@@ -109,8 +109,8 @@ export class ExtendObjectTypeDefinitionFactory {
const fields: GraphQLFieldConfigMap<any, any> = {};
for (const fieldMetadata of objectMetadata.fields) {
// Ignore non composite fields as they are already defined
if (!isCompositeFieldMetadataType(fieldMetadata.type)) {
// Ignore relation fields as they are already defined
if (!isRelationFieldMetadataType(fieldMetadata.type)) {
continue;
}
@@ -1,3 +1,5 @@
import { EnumTypeDefinitionFactory } from 'src/workspace/workspace-schema-builder/factories/enum-type-definition.factory';
import { ArgsFactory } from './args.factory';
import { InputTypeFactory } from './input-type.factory';
import { InputTypeDefinitionFactory } from './input-type-definition.factory';
@@ -24,6 +26,7 @@ export const workspaceSchemaBuilderFactories = [
InputTypeDefinitionFactory,
OutputTypeFactory,
ObjectTypeDefinitionFactory,
EnumTypeDefinitionFactory,
RelationTypeFactory,
ExtendObjectTypeDefinitionFactory,
FilterTypeFactory,
@@ -3,11 +3,11 @@ import { Injectable } from '@nestjs/common';
import { GraphQLInputFieldConfigMap, GraphQLInputObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
import { TypeMapperService } from 'src/workspace/workspace-schema-builder/services/type-mapper.service';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
import { FilterTypeFactory } from './filter-type.factory';
import {
@@ -68,8 +68,8 @@ export class FilterTypeDefinitionFactory {
const fields: GraphQLInputFieldConfigMap = {};
for (const fieldMetadata of objectMetadata.fields) {
// Composite field types are generated during extension of object type definition
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
// Relation types are generated during extension of object type definition
if (isRelationFieldMetadataType(fieldMetadata.type)) {
//continue;
}
@@ -1,15 +1,23 @@
import { Injectable, Logger } from '@nestjs/common';
import { GraphQLInputType } from 'graphql';
import {
GraphQLInputObjectType,
GraphQLInputType,
GraphQLList,
GraphQLScalarType,
} from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import {
TypeMapperService,
TypeOptions,
} from 'src/workspace/workspace-schema-builder/services/type-mapper.service';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { isCompositeFieldMetadataType } from 'src/metadata/field-metadata/utils/is-composite-field-metadata-type.util';
import { isEnumFieldMetadataType } from 'src/metadata/field-metadata/utils/is-enum-field-metadata-type.util';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { InputTypeDefinitionKind } from './input-type-definition.factory';
@@ -27,34 +35,68 @@ export class FilterTypeFactory {
buildOtions: WorkspaceBuildSchemaOptions,
typeOptions: TypeOptions,
): GraphQLInputType {
let filterType = this.typeMapperService.mapToFilterType(
fieldMetadata.type,
buildOtions.dateScalarMode,
buildOtions.numberScalarMode,
);
const target = isCompositeFieldMetadataType(fieldMetadata.type)
? fieldMetadata.type.toString()
: fieldMetadata.id;
let filterType: GraphQLInputObjectType | GraphQLScalarType | undefined =
undefined;
if (!filterType) {
filterType = this.typeDefinitionsStorage.getInputTypeByKey(
fieldMetadata.type.toString(),
InputTypeDefinitionKind.Filter,
if (isEnumFieldMetadataType(fieldMetadata.type)) {
filterType = this.createEnumFilterType(fieldMetadata);
} else {
filterType = this.typeMapperService.mapToFilterType(
fieldMetadata.type,
buildOtions.dateScalarMode,
buildOtions.numberScalarMode,
);
if (!filterType) {
this.logger.error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
{
fieldMetadata,
buildOtions,
typeOptions,
},
);
filterType ??= this.typeDefinitionsStorage.getInputTypeByKey(
target,
InputTypeDefinitionKind.Filter,
);
}
throw new Error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
);
}
if (!filterType) {
this.logger.error(`Could not find a GraphQL type for ${target}`, {
fieldMetadata,
buildOtions,
typeOptions,
});
throw new Error(`Could not find a GraphQL type for ${target}`);
}
return this.typeMapperService.mapToGqlType(filterType, typeOptions);
}
private createEnumFilterType(
fieldMetadata: FieldMetadataInterface,
): GraphQLInputObjectType {
const enumType = this.typeDefinitionsStorage.getEnumTypeByKey(
fieldMetadata.id,
);
if (!enumType) {
this.logger.error(
`Could not find a GraphQL enum type for ${fieldMetadata.id}`,
{
fieldMetadata,
},
);
throw new Error(
`Could not find a GraphQL enum type for ${fieldMetadata.id}`,
);
}
return new GraphQLInputObjectType({
name: `${enumType.name}Filter`,
fields: () => ({
eq: { type: enumType },
neq: { type: enumType },
in: { type: new GraphQLList(enumType) },
is: { type: FilterIs },
}),
});
}
}
@@ -3,10 +3,11 @@ import { Injectable } from '@nestjs/common';
import { GraphQLInputFieldConfigMap, GraphQLInputObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { InputTypeFactory } from './input-type.factory';
@@ -53,14 +54,15 @@ export class InputTypeDefinitionFactory {
const fields: GraphQLInputFieldConfigMap = {};
for (const fieldMetadata of objectMetadata.fields) {
// Composite field types are generated during extension of object type definition
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
// Relation field types are generated during extension of object type definition
if (isRelationFieldMetadataType(fieldMetadata.type)) {
//continue;
}
const type = this.inputTypeFactory.create(fieldMetadata, kind, options, {
nullable: fieldMetadata.isNullable,
defaultValue: fieldMetadata.defaultValue,
isArray: fieldMetadata.type === FieldMetadataType.MULTI_SELECT,
});
fields[fieldMetadata.name] = {
@@ -3,13 +3,14 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLInputType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import {
TypeMapperService,
TypeOptions,
} from 'src/workspace/workspace-schema-builder/services/type-mapper.service';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { isCompositeFieldMetadataType } from 'src/metadata/field-metadata/utils/is-composite-field-metadata-type.util';
import { InputTypeDefinitionKind } from './input-type-definition.factory';
@@ -28,6 +29,9 @@ export class InputTypeFactory {
buildOtions: WorkspaceBuildSchemaOptions,
typeOptions: TypeOptions,
): GraphQLInputType {
const target = isCompositeFieldMetadataType(fieldMetadata.type)
? fieldMetadata.type.toString()
: fieldMetadata.id;
let inputType: GraphQLInputType | undefined =
this.typeMapperService.mapToScalarType(
fieldMetadata.type,
@@ -35,27 +39,19 @@ export class InputTypeFactory {
buildOtions.numberScalarMode,
);
inputType ??= this.typeDefinitionsStorage.getInputTypeByKey(target, kind);
inputType ??= this.typeDefinitionsStorage.getEnumTypeByKey(target);
if (!inputType) {
inputType = this.typeDefinitionsStorage.getInputTypeByKey(
fieldMetadata.type.toString(),
this.logger.error(`Could not find a GraphQL type for ${target}`, {
fieldMetadata,
kind,
);
buildOtions,
typeOptions,
});
if (!inputType) {
this.logger.error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
{
fieldMetadata,
kind,
buildOtions,
typeOptions,
},
);
throw new Error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
);
}
throw new Error(`Could not find a GraphQL type for ${target}`);
}
return this.typeMapperService.mapToGqlType(inputType, typeOptions);
@@ -4,7 +4,7 @@ import { GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { WorkspaceResolverBuilderMutationMethodNames } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { ObjectTypeName, RootTypeFactory } from './root-type.factory';
@@ -3,10 +3,11 @@ import { Injectable } from '@nestjs/common';
import { GraphQLFieldConfigMap, GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { OutputTypeFactory } from './output-type.factory';
@@ -50,13 +51,14 @@ export class ObjectTypeDefinitionFactory {
const fields: GraphQLFieldConfigMap<any, any> = {};
for (const fieldMetadata of objectMetadata.fields) {
// Composite field types are generated during extension of object type definition
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
// Relation field types are generated during extension of object type definition
if (isRelationFieldMetadataType(fieldMetadata.type)) {
continue;
}
const type = this.outputTypeFactory.create(fieldMetadata, kind, options, {
nullable: fieldMetadata.isNullable,
isArray: fieldMetadata.type === FieldMetadataType.MULTI_SELECT,
});
fields[fieldMetadata.name] = {
@@ -3,10 +3,10 @@ import { Injectable } from '@nestjs/common';
import { GraphQLInputFieldConfigMap, GraphQLInputObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { pascalCase } from 'src/utils/pascal-case';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
import {
InputTypeDefinition,
@@ -44,8 +44,8 @@ export class OrderByTypeDefinitionFactory {
const fields: GraphQLInputFieldConfigMap = {};
for (const fieldMetadata of objectMetadata.fields) {
// Composite field types are generated during extension of object type definition
if (isCompositeFieldMetadataType(fieldMetadata.type)) {
// Relation field types are generated during extension of object type definition
if (isRelationFieldMetadataType(fieldMetadata.type)) {
continue;
}
@@ -3,13 +3,14 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLInputType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import {
TypeMapperService,
TypeOptions,
} from 'src/workspace/workspace-schema-builder/services/type-mapper.service';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { isCompositeFieldMetadataType } from 'src/metadata/field-metadata/utils/is-composite-field-metadata-type.util';
import { InputTypeDefinitionKind } from './input-type-definition.factory';
@@ -27,30 +28,26 @@ export class OrderByTypeFactory {
buildOtions: WorkspaceBuildSchemaOptions,
typeOptions: TypeOptions,
): GraphQLInputType {
const target = isCompositeFieldMetadataType(fieldMetadata.type)
? fieldMetadata.type.toString()
: fieldMetadata.id;
let orderByType = this.typeMapperService.mapToOrderByType(
fieldMetadata.type,
);
orderByType ??= this.typeDefinitionsStorage.getInputTypeByKey(
target,
InputTypeDefinitionKind.OrderBy,
);
if (!orderByType) {
orderByType = this.typeDefinitionsStorage.getInputTypeByKey(
fieldMetadata.type.toString(),
InputTypeDefinitionKind.OrderBy,
);
this.logger.error(`Could not find a GraphQL type for ${target}`, {
fieldMetadata,
buildOtions,
typeOptions,
});
if (!orderByType) {
this.logger.error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
{
fieldMetadata,
buildOtions,
typeOptions,
},
);
throw new Error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
);
}
throw new Error(`Could not find a GraphQL type for ${target}`);
}
return this.typeMapperService.mapToGqlType(orderByType, typeOptions);
@@ -3,13 +3,14 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLOutputType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import {
TypeMapperService,
TypeOptions,
} from 'src/workspace/workspace-schema-builder/services/type-mapper.service';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { isCompositeFieldMetadataType } from 'src/metadata/field-metadata/utils/is-composite-field-metadata-type.util';
import { ObjectTypeDefinitionKind } from './object-type-definition.factory';
@@ -28,6 +29,9 @@ export class OutputTypeFactory {
buildOtions: WorkspaceBuildSchemaOptions,
typeOptions: TypeOptions,
): GraphQLOutputType {
const target = isCompositeFieldMetadataType(fieldMetadata.type)
? fieldMetadata.type.toString()
: fieldMetadata.id;
let gqlType: GraphQLOutputType | undefined =
this.typeMapperService.mapToScalarType(
fieldMetadata.type,
@@ -35,26 +39,18 @@ export class OutputTypeFactory {
buildOtions.numberScalarMode,
);
gqlType ??= this.typeDefinitionsStorage.getObjectTypeByKey(target, kind);
gqlType ??= this.typeDefinitionsStorage.getEnumTypeByKey(target);
if (!gqlType) {
gqlType = this.typeDefinitionsStorage.getObjectTypeByKey(
fieldMetadata.type.toString(),
kind,
);
this.logger.error(`Could not find a GraphQL type for ${target}`, {
fieldMetadata,
buildOtions,
typeOptions,
});
if (!gqlType) {
this.logger.error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
{
fieldMetadata,
buildOtions,
typeOptions,
},
);
throw new Error(
`Could not find a GraphQL type for ${fieldMetadata.type.toString()}`,
);
}
throw new Error(`Could not find a GraphQL type for ${target}`);
}
return this.typeMapperService.mapToGqlType(gqlType, typeOptions);
@@ -4,7 +4,7 @@ import { GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { WorkspaceResolverBuilderQueryMethodNames } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { ObjectTypeName, RootTypeFactory } from './root-type.factory';
@@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLOutputType } from 'graphql';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { RelationMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/relation-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import { RelationMetadataInterface } from 'src/metadata/field-metadata/interfaces/relation-metadata.interface';
import { RelationMetadataType } from 'src/metadata/relation-metadata/relation-metadata.entity';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
@@ -4,7 +4,7 @@ import { GraphQLFieldConfigMap, GraphQLObjectType } from 'graphql';
import { WorkspaceBuildSchemaOptions } from 'src/workspace/workspace-schema-builder/interfaces/workspace-build-schema-optionts.interface';
import { WorkspaceResolverBuilderMethodNames } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { TypeDefinitionsStorage } from 'src/workspace/workspace-schema-builder/storages/type-definitions.storage';
import { getResolverName } from 'src/workspace/utils/get-resolver-name.util';
@@ -1,6 +1,6 @@
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { BigFloatScalarType } from 'src/workspace/workspace-schema-builder/graphql-types/scalars';
export const BigFloatFilterType = new GraphQLInputObjectType({
@@ -13,6 +13,6 @@ export const BigFloatFilterType = new GraphQLInputObjectType({
lt: { type: BigFloatScalarType },
lte: { type: BigFloatScalarType },
neq: { type: BigFloatScalarType },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -5,7 +5,7 @@ import {
GraphQLInt,
} from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const BigIntFilterType = new GraphQLInputObjectType({
name: 'BigIntFilter',
@@ -17,6 +17,6 @@ export const BigIntFilterType = new GraphQLInputObjectType({
lt: { type: GraphQLInt },
lte: { type: GraphQLInt },
neq: { type: GraphQLInt },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,11 +1,11 @@
import { GraphQLBoolean, GraphQLInputObjectType } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const BooleanFilterType = new GraphQLInputObjectType({
name: 'BooleanFilter',
fields: {
eq: { type: GraphQLBoolean },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,6 +1,6 @@
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { DateScalarType } from 'src/workspace/workspace-schema-builder/graphql-types/scalars';
export const DateFilterType = new GraphQLInputObjectType({
@@ -13,6 +13,6 @@ export const DateFilterType = new GraphQLInputObjectType({
lt: { type: DateScalarType },
lte: { type: DateScalarType },
neq: { type: DateScalarType },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,6 +1,6 @@
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { DateTimeScalarType } from 'src/workspace/workspace-schema-builder/graphql-types/scalars';
export const DatetimeFilterType = new GraphQLInputObjectType({
@@ -13,6 +13,6 @@ export const DatetimeFilterType = new GraphQLInputObjectType({
lt: { type: DateTimeScalarType },
lte: { type: DateTimeScalarType },
neq: { type: DateTimeScalarType },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,7 +1,7 @@
import { GraphQLEnumType } from 'graphql';
export const FilterIsNullable = new GraphQLEnumType({
name: 'FilterIsNullable',
export const FilterIs = new GraphQLEnumType({
name: 'FilterIs',
description: 'This enum to filter by nullability',
values: {
NULL: {
@@ -5,7 +5,7 @@ import {
GraphQLNonNull,
} from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const FloatFilterType = new GraphQLInputObjectType({
name: 'FloatFilter',
@@ -17,6 +17,6 @@ export const FloatFilterType = new GraphQLInputObjectType({
lt: { type: GraphQLFloat },
lte: { type: GraphQLFloat },
neq: { type: GraphQLFloat },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -5,7 +5,7 @@ import {
GraphQLInt,
} from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const IntFilterType = new GraphQLInputObjectType({
name: 'IntFilter',
@@ -17,6 +17,6 @@ export const IntFilterType = new GraphQLInputObjectType({
lt: { type: GraphQLInt },
lte: { type: GraphQLInt },
neq: { type: GraphQLInt },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -5,7 +5,7 @@ import {
GraphQLString,
} from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
export const StringFilterType = new GraphQLInputObjectType({
name: 'StringFilter',
@@ -22,6 +22,6 @@ export const StringFilterType = new GraphQLInputObjectType({
ilike: { type: GraphQLString },
regex: { type: GraphQLString },
iregex: { type: GraphQLString },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,6 +1,6 @@
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { TimeScalarType } from 'src/workspace/workspace-schema-builder/graphql-types/scalars';
export const TimeFilterType = new GraphQLInputObjectType({
@@ -13,6 +13,6 @@ export const TimeFilterType = new GraphQLInputObjectType({
lt: { type: TimeScalarType },
lte: { type: TimeScalarType },
neq: { type: TimeScalarType },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,6 +1,6 @@
import { GraphQLInputObjectType, GraphQLList } from 'graphql';
import { FilterIsNullable } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is-nullable.input-type';
import { FilterIs } from 'src/workspace/workspace-schema-builder/graphql-types/input/filter-is.input-type';
import { UUIDScalarType } from 'src/workspace/workspace-schema-builder/graphql-types/scalars';
export const UUIDFilterType = new GraphQLInputObjectType({
@@ -9,6 +9,6 @@ export const UUIDFilterType = new GraphQLInputObjectType({
eq: { type: UUIDScalarType },
in: { type: new GraphQLList(UUIDScalarType) },
neq: { type: UUIDScalarType },
is: { type: FilterIsNullable },
is: { type: FilterIs },
},
});
@@ -1,22 +0,0 @@
import { FieldMetadataTargetColumnMap } from 'src/metadata/field-metadata/interfaces/field-metadata-target-column-map.interface';
import { FieldMetadataDefaultValue } from 'src/metadata/field-metadata/interfaces/field-metadata-default-value.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { RelationMetadataEntity } from 'src/metadata/relation-metadata/relation-metadata.entity';
export interface FieldMetadataInterface<
T extends FieldMetadataType | 'default' = 'default',
> {
id: string;
type: FieldMetadataType;
name: string;
label: string;
targetColumnMap: FieldMetadataTargetColumnMap<T>;
defaultValue?: FieldMetadataDefaultValue<T>;
objectMetadataId: string;
description?: string;
isNullable?: boolean;
fromRelationMetadata?: RelationMetadataEntity;
toRelationMetadata?: RelationMetadataEntity;
isCustom?: boolean;
}
@@ -1,15 +0,0 @@
import { FieldMetadataInterface } from './field-metadata.interface';
import { RelationMetadataInterface } from './relation-metadata.interface';
export interface ObjectMetadataInterface {
id: string;
nameSingular: string;
namePlural: string;
labelSingular: string;
labelPlural: string;
description?: string;
targetTableName: string;
fromRelations: RelationMetadataInterface[];
toRelations: RelationMetadataInterface[];
fields: FieldMetadataInterface[];
}
@@ -1,8 +1,8 @@
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { InputTypeDefinitionKind } from 'src/workspace/workspace-schema-builder/factories/input-type-definition.factory';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { ObjectMetadataInterface } from './object-metadata.interface';
export interface ArgMetadata<T = any> {
kind?: InputTypeDefinitionKind;
type?: FieldMetadataType;
@@ -1,22 +0,0 @@
import { RelationMetadataType } from 'src/metadata/relation-metadata/relation-metadata.entity';
import { ObjectMetadataInterface } from './object-metadata.interface';
import { FieldMetadataInterface } from './field-metadata.interface';
export interface RelationMetadataInterface {
id: string;
relationType: RelationMetadataType;
fromObjectMetadataId: string;
fromObjectMetadata: ObjectMetadataInterface;
toObjectMetadataId: string;
toObjectMetadata: ObjectMetadataInterface;
fromFieldMetadataId: string;
fromFieldMetadata: FieldMetadataInterface;
toFieldMetadataId: string;
toFieldMetadata: FieldMetadataInterface;
}
@@ -1,4 +1,4 @@
import { FieldMetadataInterface } from './field-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
export interface WorkspaceSchemaBuilderContext {
workspaceId: string;
@@ -1,35 +0,0 @@
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
export const currencyObjectDefinition = {
id: FieldMetadataType.CURRENCY.toString(),
nameSingular: 'currency',
namePlural: 'currency',
labelSingular: 'Currency',
labelPlural: 'Currency',
targetTableName: '',
fields: [
{
id: 'amountMicros',
type: FieldMetadataType.NUMERIC,
objectMetadataId: FieldMetadataType.CURRENCY.toString(),
name: 'amountMicros',
label: 'AmountMicros',
targetColumnMap: { value: 'amountMicros' },
isNullable: true,
} satisfies FieldMetadataInterface,
{
id: 'currencyCode',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.CURRENCY.toString(),
name: 'currencyCode',
label: 'Currency Code',
targetColumnMap: { value: 'currencyCode' },
isNullable: true,
} satisfies FieldMetadataInterface,
],
fromRelations: [],
toRelations: [],
} satisfies ObjectMetadataInterface;
@@ -1,35 +0,0 @@
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
export const fullNameObjectDefinition = {
id: FieldMetadataType.FULL_NAME.toString(),
nameSingular: 'fullName',
namePlural: 'fullName',
labelSingular: 'FullName',
labelPlural: 'FullName',
targetTableName: '',
fields: [
{
id: 'firstName',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.FULL_NAME.toString(),
name: 'firstName',
label: 'First Name',
targetColumnMap: { value: 'firstName' },
isNullable: true,
} satisfies FieldMetadataInterface,
{
id: 'lastName',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.FULL_NAME.toString(),
name: 'lastName',
label: 'Last Name',
targetColumnMap: { value: 'lastName' },
isNullable: true,
} satisfies FieldMetadataInterface,
],
fromRelations: [],
toRelations: [],
} satisfies ObjectMetadataInterface;
@@ -1,35 +0,0 @@
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { FieldMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/field-metadata.interface';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
export const linkObjectDefinition = {
id: FieldMetadataType.LINK.toString(),
nameSingular: 'link',
namePlural: 'link',
labelSingular: 'Link',
labelPlural: 'Link',
targetTableName: '',
fields: [
{
id: 'label',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.LINK.toString(),
name: 'label',
label: 'Label',
targetColumnMap: { value: 'label' },
isNullable: true,
} satisfies FieldMetadataInterface,
{
id: 'url',
type: FieldMetadataType.TEXT,
objectMetadataId: FieldMetadataType.LINK.toString(),
name: 'url',
label: 'Url',
targetColumnMap: { value: 'url' },
isNullable: true,
} satisfies FieldMetadataInterface,
],
fromRelations: [],
toRelations: [],
} satisfies ObjectMetadataInterface;
@@ -75,7 +75,7 @@ export class TypeMapperService {
fieldMetadataType: FieldMetadataType,
dateScalarMode: DateScalarMode = 'isoDate',
numberScalarMode: NumberScalarMode = 'float',
): GraphQLInputObjectType | GraphQLScalarType<boolean, boolean> | undefined {
): GraphQLInputObjectType | GraphQLScalarType | undefined {
const dateFilter =
dateScalarMode === 'timestamp' ? DatetimeFilterType : DateFilterType;
const numberScalar =
@@ -84,7 +84,7 @@ export class TypeMapperService {
// LINK and CURRENCY are handled in the factories because they are objects
const typeFilterMapping = new Map<
FieldMetadataType,
GraphQLInputObjectType | GraphQLScalarType<boolean, boolean>
GraphQLInputObjectType | GraphQLScalarType
>([
[FieldMetadataType.UUID, UUIDFilterType],
[FieldMetadataType.TEXT, StringFilterType],
@@ -115,6 +115,9 @@ export class TypeMapperService {
[FieldMetadataType.NUMBER, OrderByDirectionType],
[FieldMetadataType.NUMERIC, OrderByDirectionType],
[FieldMetadataType.PROBABILITY, OrderByDirectionType],
[FieldMetadataType.RATING, OrderByDirectionType],
[FieldMetadataType.SELECT, OrderByDirectionType],
[FieldMetadataType.MULTI_SELECT, OrderByDirectionType],
]);
return typeOrderByMapping.get(fieldMetadataType);
@@ -1,8 +1,13 @@
import { Injectable, Scope } from '@nestjs/common';
import { GraphQLInputObjectType, GraphQLObjectType } from 'graphql';
import {
GraphQLEnumType,
GraphQLInputObjectType,
GraphQLObjectType,
} from 'graphql';
import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity';
import { EnumTypeDefinition } from 'src/workspace/workspace-schema-builder/factories/enum-type-definition.factory';
import {
InputTypeDefinition,
InputTypeDefinitionKind,
@@ -15,6 +20,7 @@ import {
// Must be scoped on REQUEST level
@Injectable({ scope: Scope.REQUEST })
export class TypeDefinitionsStorage {
private readonly enumTypeDefinitions = new Map<string, EnumTypeDefinition>();
private readonly objectTypeDefinitions = new Map<
string,
ObjectTypeDefinition
@@ -24,6 +30,10 @@ export class TypeDefinitionsStorage {
InputTypeDefinition
>();
addEnumTypes(enumDefs: EnumTypeDefinition[]) {
enumDefs.forEach((item) => this.enumTypeDefinitions.set(item.target, item));
}
addObjectTypes(objectDefs: ObjectTypeDefinition[]) {
objectDefs.forEach((item) =>
this.objectTypeDefinitions.set(
@@ -64,6 +74,10 @@ export class TypeDefinitionsStorage {
)?.type;
}
getEnumTypeByKey(target: string): GraphQLEnumType | undefined {
return this.enumTypeDefinitions.get(target)?.type;
}
getAllInputTypeDefinitions(): InputTypeDefinition[] {
return Array.from(this.inputTypeDefinitions.values());
}
@@ -1,8 +1,14 @@
import { Injectable, Logger } from '@nestjs/common';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { FieldMetadataInterface } from 'src/metadata/field-metadata/interfaces/field-metadata.interface';
import { FieldMetadataEntity } from 'src/metadata/field-metadata/field-metadata.entity';
import { customTableDefaultColumns } from 'src/workspace/workspace-migration-runner/utils/custom-table-default-column.util';
import { fullNameObjectDefinition } from 'src/workspace/workspace-schema-builder/object-definitions/full-name.object-definition';
import { fullNameObjectDefinition } from 'src/metadata/field-metadata/composite-types/full-name.composite-type';
import { currencyObjectDefinition } from 'src/metadata/field-metadata/composite-types/currency.composite-type';
import { linkObjectDefinition } from 'src/metadata/field-metadata/composite-types/link.composite-type';
import { EnumTypeDefinitionFactory } from 'src/workspace/workspace-schema-builder/factories/enum-type-definition.factory';
import { TypeDefinitionsStorage } from './storages/type-definitions.storage';
import {
@@ -15,16 +21,12 @@ import {
} from './factories/input-type-definition.factory';
import { getFieldMetadataType } from './utils/get-field-metadata-type.util';
import { WorkspaceBuildSchemaOptions } from './interfaces/workspace-build-schema-optionts.interface';
import { currencyObjectDefinition } from './object-definitions/currency.object-definition';
import { linkObjectDefinition } from './object-definitions/link.object-definition';
import { ObjectMetadataInterface } from './interfaces/object-metadata.interface';
import { FieldMetadataInterface } from './interfaces/field-metadata.interface';
import { FilterTypeDefinitionFactory } from './factories/filter-type-definition.factory';
import { ConnectionTypeDefinitionFactory } from './factories/connection-type-definition.factory';
import { EdgeTypeDefinitionFactory } from './factories/edge-type-definition.factory';
import { OrderByTypeDefinitionFactory } from './factories/order-by-type-definition.factory';
import { ExtendObjectTypeDefinitionFactory } from './factories/extend-object-type-definition.factory';
import { objectContainsCompositeField } from './utils/object-contains-composite-field';
import { objectContainsRelationField } from './utils/object-contains-relation-field';
// Create a default field for each custom table default column
const defaultFields = customTableDefaultColumns.map((column) => {
@@ -42,6 +44,7 @@ export class TypeDefinitionsGenerator {
constructor(
private readonly typeDefinitionsStorage: TypeDefinitionsStorage,
private readonly objectTypeDefinitionFactory: ObjectTypeDefinitionFactory,
private readonly enumTypeDefinitionFactory: EnumTypeDefinitionFactory,
private readonly inputTypeDefinitionFactory: InputTypeDefinitionFactory,
private readonly filterTypeDefintionFactory: FilterTypeDefinitionFactory,
private readonly orderByTypeDefinitionFactory: OrderByTypeDefinitionFactory,
@@ -74,6 +77,7 @@ export class TypeDefinitionsGenerator {
);
// Generate static objects first because they can be used in dynamic objects
this.generateEnumTypeDefs(staticObjectMetadataCollection, options);
this.generateObjectTypeDefs(staticObjectMetadataCollection, options);
this.generateInputTypeDefs(staticObjectMetadataCollection, options);
}
@@ -89,6 +93,7 @@ export class TypeDefinitionsGenerator {
);
// Generate dynamic objects
this.generateEnumTypeDefs(dynamicObjectMetadataCollection, options);
this.generateObjectTypeDefs(dynamicObjectMetadataCollection, options);
this.generatePaginationTypeDefs(dynamicObjectMetadataCollection, options);
this.generateInputTypeDefs(dynamicObjectMetadataCollection, options);
@@ -203,13 +208,26 @@ export class TypeDefinitionsGenerator {
this.typeDefinitionsStorage.addInputTypes(inputTypeDefs);
}
private generateEnumTypeDefs(
objectMetadataCollection: ObjectMetadataInterface[],
options: WorkspaceBuildSchemaOptions,
) {
const enumTypeDefs = objectMetadataCollection
.map((objectMetadata) =>
this.enumTypeDefinitionFactory.create(objectMetadata, options),
)
.flat();
this.typeDefinitionsStorage.addEnumTypes(enumTypeDefs);
}
private generateExtendedObjectTypeDefs(
objectMetadataCollection: ObjectMetadataInterface[],
options: WorkspaceBuildSchemaOptions,
) {
// Generate extended object type defs only for objects that contain composite fields
const objectMetadataCollectionWithCompositeFields =
objectMetadataCollection.filter(objectContainsCompositeField);
objectMetadataCollection.filter(objectContainsRelationField);
const objectTypeDefs = objectMetadataCollectionWithCompositeFields.map(
(objectMetadata) =>
this.extendObjectTypeDefinitionFactory.create(objectMetadata, options),
@@ -1,11 +0,0 @@
import { ObjectMetadataInterface } from 'src/workspace/workspace-schema-builder/interfaces/object-metadata.interface';
import { isCompositeFieldMetadataType } from 'src/workspace/utils/is-composite-field-metadata-type.util';
export const objectContainsCompositeField = (
objectMetadata: ObjectMetadataInterface,
): boolean => {
return objectMetadata.fields.some((field) =>
isCompositeFieldMetadataType(field.type),
);
};
@@ -0,0 +1,11 @@
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { isRelationFieldMetadataType } from 'src/workspace/utils/is-relation-field-metadata-type.util';
export const objectContainsRelationField = (
objectMetadata: ObjectMetadataInterface,
): boolean => {
return objectMetadata.fields.some((field) =>
isRelationFieldMetadataType(field.type),
);
};
@@ -3,13 +3,13 @@ import { Injectable, Logger } from '@nestjs/common';
import { GraphQLSchema } from 'graphql';
import { WorkspaceResolverBuilderMethods } from 'src/workspace/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { ObjectMetadataInterface } from 'src/metadata/field-metadata/interfaces/object-metadata.interface';
import { TypeDefinitionsGenerator } from './type-definitions.generator';
import { WorkspaceBuildSchemaOptions } from './interfaces/workspace-build-schema-optionts.interface';
import { QueryTypeFactory } from './factories/query-type.factory';
import { MutationTypeFactory } from './factories/mutation-type.factory';
import { ObjectMetadataInterface } from './interfaces/object-metadata.interface';
import { OrphanedTypesFactory } from './factories/orphaned-types.factory';
@Injectable()