From 4f10ad2eac088e2d4fb3b700b3674f20001c4fed Mon Sep 17 00:00:00 2001 From: Claudio Romano Date: Sat, 2 Nov 2024 14:44:49 +0100 Subject: [PATCH] feat: breaking change on CrudField relations --- .changeset/clever-flies-hope.md | 5 ++ .changeset/mighty-apricots-deny.md | 5 ++ .gitlab-ci.yml | 13 ++-- libs/crud/src/crud.module.ts | 14 +++-- libs/crud/src/graphql/crud-field.decorator.ts | 8 +-- libs/crud/src/graphql/upsert-input.ts | 60 +++++++++++-------- .../service/crud-entity-service.factory.ts | 13 +++- libs/crud/src/service/crud.service.ts | 3 + libs/crud/test/e2e/test-setup.ts | 6 +- libs/crud/test/fixtures/company.entity.ts | 4 +- libs/crud/test/fixtures/group.entity.ts | 8 +-- .../unit/fixtures/all-types-shema.fixtures.ts | 2 +- 12 files changed, 91 insertions(+), 50 deletions(-) create mode 100644 .changeset/clever-flies-hope.md create mode 100644 .changeset/mighty-apricots-deny.md diff --git a/.changeset/clever-flies-hope.md b/.changeset/clever-flies-hope.md new file mode 100644 index 0000000..eb7582a --- /dev/null +++ b/.changeset/clever-flies-hope.md @@ -0,0 +1,5 @@ +--- +"@panter/crud": patch +--- + +Feat: freaking change in CrudFiel, all relation show\* properties are default to false diff --git a/.changeset/mighty-apricots-deny.md b/.changeset/mighty-apricots-deny.md new file mode 100644 index 0000000..c84c728 --- /dev/null +++ b/.changeset/mighty-apricots-deny.md @@ -0,0 +1,5 @@ +--- +"@panter/nestjs-utils": patch +--- + +Fix ModuleLogger typings diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index da8bdc0..0a36354 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,10 +11,13 @@ variables: DOCKER_TLS_CERTDIR: '' DOCKER_DRIVER: overlay2 DOCKER_BUILDKIT: '1' + DOCKER_MEMORY: '4g' + DOCKER_CPUS: '2' + TESTCONTAINERS_HOST_OVERRIDE: 'host.docker.internal' + KUBERNETES_MEMORY_REQUEST: 3Gi + KUBERNETES_MEMORY_LIMIT: 6Gi KUBERNETES_CPU_REQUEST: '0.5' KUBERNETES_CPU_LIMIT: '1' - KUBERNETES_MEMORY_REQUEST: 2Gi - KUBERNETES_MEMORY_LIMIT: 4Gi cache: - key: yarn-workspace @@ -59,7 +62,8 @@ build-samples: # - yarn changesets-gitlab comment test-lib: - stage: test + stage: build + needs: ['build-lib'] only: ['merge_requests', 'main'] script: - yarn --immutable @@ -73,7 +77,8 @@ test-lib: - .yarn test-samples: - stage: test + stage: build + needs: ['build-samples'] only: ['merge_requests', 'main'] allow_failure: true script: diff --git a/libs/crud/src/crud.module.ts b/libs/crud/src/crud.module.ts index b4e94e6..061e4cb 100644 --- a/libs/crud/src/crud.module.ts +++ b/libs/crud/src/crud.module.ts @@ -15,21 +15,25 @@ export interface CrudModuleOptions { export type CrudModuleAsyncOptions = ModuleAsyncOptions< CrudModuleOptions -> & { defaultRelationModifier?: boolean }; +>; -let relationModifier: boolean | undefined = true; +const relationModifier: boolean | undefined = true; +const connectRelationModifier: boolean | undefined = true; -export const defaultRelationModifier = () => relationModifier; +export const defaultRelationModifier = () => { + return relationModifier; +}; +export const defaultConnectRelationModifier = () => { + return connectRelationModifier; +}; @Module({}) export class CrudModule implements OnModuleInit { static async forRootAsync({ - defaultRelationModifier, inject, imports, useFactory, }: CrudModuleAsyncOptions): Promise { - relationModifier = defaultRelationModifier; return { module: CrudModule, imports: [...(imports || []), ConfigModule, DiscoveryModule], diff --git a/libs/crud/src/graphql/crud-field.decorator.ts b/libs/crud/src/graphql/crud-field.decorator.ts index f2fec69..93d6e6a 100644 --- a/libs/crud/src/graphql/crud-field.decorator.ts +++ b/libs/crud/src/graphql/crud-field.decorator.ts @@ -53,9 +53,9 @@ export type InputFieldResolver = ( export type CrudRelationFieldOptions = { /** - * If set to `true`, the relation cannot be connected by primary key + * If set to `true`, the relation can be disconnected with all it's fields. */ - hideConnect?: boolean; + showConnect?: boolean; /** * If set to `true`, the relation can be created with all it's fields. */ @@ -65,9 +65,9 @@ export type CrudRelationFieldOptions = { */ showUpdate?: boolean; /** - * If set to `true`, the relation cannot be disconnected by primary key. + * If set to `true`, the relation can be disconnected with all it's fields. */ - hideDisconnect?: boolean; + showDisconnect?: boolean; }; export type CrudFieldProps = { diff --git a/libs/crud/src/graphql/upsert-input.ts b/libs/crud/src/graphql/upsert-input.ts index 1a9eb89..9e1cb84 100644 --- a/libs/crud/src/graphql/upsert-input.ts +++ b/libs/crud/src/graphql/upsert-input.ts @@ -2,7 +2,11 @@ import { Field, Float, InputType, TypeMetadataStorage } from '@nestjs/graphql'; import { GraphQLJSON } from 'graphql-scalars'; import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'; import { isArray, uniqBy } from 'lodash'; -import { CrudGqlType, defaultRelationModifier } from '../'; // CrudGqlType needs to be imported from root index.ts +import { + CrudGqlType, + defaultConnectRelationModifier, + defaultRelationModifier, +} from '../'; // CrudGqlType needs to be imported from root index.ts import { CrudEntityType } from './crud-types'; import { manyRelationInput } from './many-relation-input'; import { typesCache } from './types-cache'; @@ -98,9 +102,9 @@ const getCreateDesignType = (p: CrudInfo, parentRef: CrudEntityType) => { ? !p.crudOptions?.relation?.showCreate : defaultRelationModifier(), hideConnect: - p.crudOptions?.relation?.hideConnect !== undefined - ? p.crudOptions?.relation?.hideConnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showConnect !== undefined + ? !p.crudOptions?.relation?.showConnect + : defaultConnectRelationModifier(), parentProperty: p.name, }, ); @@ -136,9 +140,9 @@ const getCreateDesignType = (p: CrudInfo, parentRef: CrudEntityType) => { ? !p.crudOptions?.relation?.showCreate : defaultRelationModifier(), hideConnect: - p.crudOptions?.relation?.hideConnect !== undefined - ? p.crudOptions?.relation?.hideConnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showConnect !== undefined + ? !p.crudOptions?.relation?.showConnect + : defaultConnectRelationModifier(), parentProperty: p.name, }); } @@ -169,13 +173,15 @@ const getUpdateDesignType = (p: CrudInfo, parentRef: CrudEntityType) => { ? !p.crudOptions?.relation?.showUpdate : defaultRelationModifier(), hideDisconnect: - p.crudOptions?.relation?.hideDisconnect !== undefined - ? p.crudOptions?.relation?.hideDisconnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showDisconnect !== undefined + ? !p.crudOptions?.relation?.showDisconnect + : !p.crudOptions?.fieldOptions?.nullable + ? true + : defaultConnectRelationModifier(), hideConnect: - p.crudOptions?.relation?.hideConnect !== undefined - ? p.crudOptions?.relation?.hideConnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showConnect !== undefined + ? !p.crudOptions?.relation?.showConnect + : defaultConnectRelationModifier(), parentProperty: p.name, }, ); @@ -216,13 +222,15 @@ const getUpdateDesignType = (p: CrudInfo, parentRef: CrudEntityType) => { ? !p.crudOptions?.relation?.showUpdate : defaultRelationModifier(), hideConnect: - p.crudOptions?.relation?.hideConnect !== undefined - ? p.crudOptions?.relation?.hideConnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showConnect !== undefined + ? !p.crudOptions?.relation?.showConnect + : defaultConnectRelationModifier(), hideDisconnect: - p.crudOptions?.relation?.hideDisconnect !== undefined - ? p.crudOptions?.relation?.hideDisconnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showDisconnect !== undefined + ? !p.crudOptions?.relation?.showDisconnect + : !p.crudOptions?.fieldOptions?.nullable + ? true + : defaultConnectRelationModifier(), parentProperty: p.name, }, ); @@ -241,13 +249,15 @@ const getUpdateDesignType = (p: CrudInfo, parentRef: CrudEntityType) => { ? !p.crudOptions?.relation?.showUpdate : defaultRelationModifier(), hideConnect: - p.crudOptions?.relation?.hideConnect !== undefined - ? p.crudOptions?.relation?.hideConnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showConnect !== undefined + ? !p.crudOptions?.relation?.showConnect + : defaultConnectRelationModifier(), hideDisconnect: - p.crudOptions?.relation?.hideDisconnect !== undefined - ? p.crudOptions?.relation?.hideDisconnect - : defaultRelationModifier(), + p.crudOptions?.relation?.showDisconnect !== undefined + ? !p.crudOptions?.relation?.showDisconnect + : !p.crudOptions?.fieldOptions?.nullable + ? true + : defaultConnectRelationModifier(), parentProperty: p.name, }, ); diff --git a/libs/crud/src/service/crud-entity-service.factory.ts b/libs/crud/src/service/crud-entity-service.factory.ts index 724ad9e..f8a58dd 100644 --- a/libs/crud/src/service/crud-entity-service.factory.ts +++ b/libs/crud/src/service/crud-entity-service.factory.ts @@ -8,17 +8,26 @@ import { CRUD_SERVICE } from './crud-service.decorator'; * Factory to get the correct CRUD service for a given entity. * * To provide a default CRUD service, the factory will return the provided CRUD service if no specific service is found. + * + * @example + * @CrudServiceResource({ entity: PersonEntity }) + * @Injectable() + * export class PersonEntityService implements ICrudEntityService {} + * */ @Injectable() export class CrudEntityServiceFactory { constructor( private readonly discovery: DiscoveryService, private readonly reflector: Reflector, - private readonly crudEntityService: CrudEntityService, + private readonly defaultCrudEntityService: CrudEntityService, ) {} /** * Get the CRUD service for the given entity. + * If no service is found, the default service will be returned. + * The decorator CrudServiceResource will be used to find the service a entity. + * */ getCrudService( entity: CrudEntityType, @@ -34,7 +43,7 @@ export class CrudEntityServiceFactory { if (!provider || !provider.instance) { // TODO: make sure i can reuse the instance if this is on how to solve it - return this.crudEntityService; + return this.defaultCrudEntityService; } return provider.instance; diff --git a/libs/crud/src/service/crud.service.ts b/libs/crud/src/service/crud.service.ts index 68dcb89..36ec96d 100644 --- a/libs/crud/src/service/crud.service.ts +++ b/libs/crud/src/service/crud.service.ts @@ -4,6 +4,9 @@ import { DiscoveryService } from '@nestjs/core'; import { CrudAuditCallback, CrudAuthorizeCallback } from '../'; import { CrudModuleOptions } from '../crud.module'; +/** + * This service is used to register CRUD resources and to provide default authorization and audit callbacks. + */ @Injectable() export class CrudService { private logger = new Logger(CrudService.name); diff --git a/libs/crud/test/e2e/test-setup.ts b/libs/crud/test/e2e/test-setup.ts index dd2dfaa..4fc5c3a 100644 --- a/libs/crud/test/e2e/test-setup.ts +++ b/libs/crud/test/e2e/test-setup.ts @@ -9,13 +9,13 @@ export default async () => { console.log('Starting PostgreSQL (pgContainer) container'); console.time('pgContainer'); if (!global.pgContainer) { - console.log('Creating new PostgreSQL (pgContainer) container'); - global.pgContainer = await new PostgreSqlContainer('postgres:13.3-alpine') + console.log('Creating new PostgreSQL (pgContainer) testcontainer'); + global.pgContainer = await new PostgreSqlContainer() .withExposedPorts(5432) .withStartupTimeout(60000) .start(); } else { - console.log('Reusing existing PostgreSQL (pgContainer) container'); + console.log('Reusing existing PostgreSQL (pgContainer) testcontainer'); } console.timeEnd('pgContainer'); }; diff --git a/libs/crud/test/fixtures/company.entity.ts b/libs/crud/test/fixtures/company.entity.ts index b21c497..3f0a16f 100644 --- a/libs/crud/test/fixtures/company.entity.ts +++ b/libs/crud/test/fixtures/company.entity.ts @@ -24,12 +24,12 @@ export class Company { @Property({ nullable: true }) description?: string; - @CrudField({ hideUpdate: true, relation: { hideConnect: false } }) + @CrudField({ hideUpdate: true, relation: { showConnect: true } }) @Field() @ManyToOne(() => User) founder!: User; - @CrudField({ hideCreate: true, relation: { hideConnect: false } }) + @CrudField({ hideCreate: true, relation: { showConnect: true } }) @Field({ nullable: true }) @ManyToOne(() => User, { nullable: true }) ceo?: User; diff --git a/libs/crud/test/fixtures/group.entity.ts b/libs/crud/test/fixtures/group.entity.ts index 71efe72..c1cd50b 100644 --- a/libs/crud/test/fixtures/group.entity.ts +++ b/libs/crud/test/fixtures/group.entity.ts @@ -32,7 +32,7 @@ export class Group { @CrudField({ hideCreate: false, hideUpdate: true, - relation: { hideConnect: false }, + relation: { showConnect: true }, }) @Field(() => [User]) @ManyToMany({ entity: () => User }) @@ -40,7 +40,7 @@ export class Group { @CrudField({ hideCreate: true, - relation: { hideConnect: false, hideDisconnect: false }, + relation: { showConnect: true, showDisconnect: true }, }) @Field(() => [User], { nullable: true }) @ManyToMany({ entity: () => User, nullable: true }) @@ -52,8 +52,8 @@ export class Group { relation: { showCreate: true, showUpdate: true, - hideConnect: false, - hideDisconnect: false, + showConnect: true, + showDisconnect: true, }, }) @Field(() => [User], { nullable: true }) diff --git a/libs/crud/test/unit/fixtures/all-types-shema.fixtures.ts b/libs/crud/test/unit/fixtures/all-types-shema.fixtures.ts index 20cd1d1..6ff35e1 100644 --- a/libs/crud/test/unit/fixtures/all-types-shema.fixtures.ts +++ b/libs/crud/test/unit/fixtures/all-types-shema.fixtures.ts @@ -73,7 +73,7 @@ export class Dummy { @CrudField({ typeFn: () => Dummy2, - relation: { showCreate: true, showUpdate: true, hideConnect: false }, + relation: { showCreate: true, showUpdate: true, showConnect: true }, }) @Field(() => [Dummy2]) @ManyToMany(() => Dummy2, (dummy2) => dummy2.dummyProp)