diff --git a/packages/hydra-cli/src/generate/ModelRenderer.ts b/packages/hydra-cli/src/generate/ModelRenderer.ts index 338a33edd..04753c518 100644 --- a/packages/hydra-cli/src/generate/ModelRenderer.ts +++ b/packages/hydra-cli/src/generate/ModelRenderer.ts @@ -1,4 +1,3 @@ -import * as path from 'path' import { ObjectType, WarthogModel, FieldResolver } from '../model' import Debug from 'debug' import { GeneratorContext } from './SourcesGenerator' @@ -108,22 +107,15 @@ export class ModelRenderer extends AbstractRenderer { withImportProps(): GeneratorContext { const relatedEntityImports: Set = new Set() - this.objType.fields .filter((f) => f.relation) .forEach((f) => { - const columnType = f.relation?.columnType - if (!columnType) { - // should never happen - throw new Error(`Relation column type for ${f.name} is undefined`) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { columnType } = f.relation! + // Check if it is not a self reference so we don't add the object to import list + if (columnType !== this.objType.name) { + relatedEntityImports.add(utils.generateEntityImport(columnType)) } - relatedEntityImports.add( - path.join( - `import { ${columnType} } from '..`, - utils.kebabCase(columnType), - `${utils.kebabCase(columnType)}.model'` - ) - ) }) return { relatedEntityImports: Array.from(relatedEntityImports.values()), @@ -145,7 +137,9 @@ export class ModelRenderer extends AbstractRenderer { rootArgName: 'r', // disable utils.camelCase(entityName) could be a reverved ts/js keyword ie `class` returnType: utils.generateResolverReturnType(returnTypeFunc, f.isList), }) - fieldResolverImports.add(utils.generateEntityImport(returnTypeFunc)) + if (f.type !== this.objType.name) { + fieldResolverImports.add(utils.generateEntityImport(returnTypeFunc)) + } } const imports = Array.from(fieldResolverImports.values()) // If there is at least one field resolver then add typeorm to imports diff --git a/packages/hydra-cli/src/model/relations.ts b/packages/hydra-cli/src/model/relations.ts index bbeeb397b..3c108ea9a 100644 --- a/packages/hydra-cli/src/model/relations.ts +++ b/packages/hydra-cli/src/model/relations.ts @@ -41,6 +41,11 @@ function addOne2Many(rel: EntityRelationship): void { field.name, relatedField.nullable ) + // Re-organize relation types if it is a self reference + if (field.type === relatedField.type && rel.field.isList) { + rel.field.relation.type = 'otm' + rel.relatedField.relation.type = 'mto' + } } function addOne2One(rel: EntityRelationship): void { diff --git a/packages/hydra-cli/test/helpers/Relationships.test.ts b/packages/hydra-cli/test/helpers/Relationships.test.ts new file mode 100644 index 000000000..f3ca90843 --- /dev/null +++ b/packages/hydra-cli/test/helpers/Relationships.test.ts @@ -0,0 +1,35 @@ +import { expect } from 'chai' +import * as fs from 'fs-extra' +import { EnumContextProvider } from '../../src/generate/EnumContextProvider' +import { ModelRenderer } from '../../src/generate/ModelRenderer' +import { fromStringSchema } from './model' + +describe('Entity Relationships', () => { + let generator: ModelRenderer + let modelTemplate: string + let enumCtxProvider: EnumContextProvider + + before(() => { + modelTemplate = fs.readFileSync( + './src/templates/entities/model.ts.mst', + 'utf-8' + ) + }) + + it('should not create import statement for self referenced entities', () => { + const model = fromStringSchema(` + type Member @entity { + invitor: Member + invitees: [Member!] @derivedFrom(field: "invitor") + }`) + generator = new ModelRenderer( + model, + model.lookupEntity('Member'), + enumCtxProvider + ) + const rendered = generator.render(modelTemplate) + expect(rendered).to.not.include( + `import { Member } from '../member/member.model.ts'` + ) + }) +})