Repository: nestjs/swagger
Pull request #458 (2019-12-27 12:44:46)

fix(): override base class metadata with the metadata from the sub class
The schema from the the base class is not being correctly updated when a
sub class overrides a property

The existing schema and the new schema is not being merged properly (missing spread operator) and the merge order is reversed, the existing schema should be merged first in order to keep the updates from the new schema


The error below is the error thrown by the test I've implemented without any further code modification
```
Error: A circular dependency has been detected (property key: "name"). Please, make sure that each side of a bidirectional relationships are using lazy resolvers ("type: () => ClassType").

    at SchemaObjectFactory.createNotBuiltInTypeReference (/home/user/workspace/github/swagger/lib/services/schema-object-factory.ts:189:13)
    at SchemaObjectFactory.mergePropertyWithMetadata (/home/user/workspace/github/swagger/lib/services/schema-object-factory.ts:156:19)
    at /home/user/workspace/github/swagger/lib/services/schema-object-factory.ts:101:29
    at Array.map (<anonymous>)
    at SchemaObjectFactory.exploreModelSchema (/home/user/workspace/github/swagger/lib/services/schema-object-factory.ts:100:48)
    at Object.<anonymous> (/home/user/workspace/github/swagger/test/services/schema-object-factory.spec.ts:138:27)
    at Object.asyncJestTest (/home/user/workspace/github/swagger/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:102:37)
    at /home/user/workspace/github/swagger/node_modules/jest-jasmine2/build/queueRunner.js:43:12
    at new Promise (<anonymous>)
    at mapper (/home/user/workspace/github/swagger/node_modules/jest-jasmine2/build/queueRunner.js:26:19)
```

## PR Checklist
Please check if your PR fulfills the following requirements:

- [x] The commit message follows our guidelines: https://github.com/nestjs/nest/blob/master/CONTRIBUTING.md
- [x] Tests for the changes have been added (for bug fixes / features)
- [x] Docs have been added / updated (for bug fixes / features)


## PR Type
What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->
```
[x] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Other... Please describe:
```

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->

Issue Number: N/A


## What is the new behavior?

The schema is updated as expected


## Does this PR introduce a breaking change?
```
[ ] Yes
[x] No
```

<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->


## Other information


Patch:
diff --git a/lib/decorators/helpers.ts b/lib/decorators/helpers.ts
index 284fb218..a7842777 100644
--- a/lib/decorators/helpers.ts
+++ b/lib/decorators/helpers.ts
@@ -47,8 +47,8 @@ export function createPropertyDecorator<T extends Record<string, any> = any>(
       Reflect.defineMetadata(
         metakey,
         {
-          ...pickBy(metadata, negate(isUndefined)),
-          existingMetadata
+          ...existingMetadata,
+          ...pickBy(metadata, negate(isUndefined))
         },
         target,
         propertyKey


Test patch:
diff --git a/test/services/schema-object-factory.spec.ts b/test/services/schema-object-factory.spec.ts
index e7b7cec1..e79b97a6 100644
--- a/test/services/schema-object-factory.spec.ts
+++ b/test/services/schema-object-factory.spec.ts
@@ -1,3 +1,4 @@
+import { ApiProperty } from '../../lib/decorators';
 import { ModelPropertiesAccessor } from '../../lib/services/model-properties-accessor';
 import { SchemaObjectFactory } from '../../lib/services/schema-object-factory';
 import { SwaggerTypesMapper } from '../../lib/services/swagger-types-mapper';
@@ -119,5 +120,33 @@ describe('SchemaObjectFactory', () => {
         required: ['firstname', 'lastname', 'parent']
       });
     });
+
+    it('should override base class metadata', () => {
+      class CreatUserDto {
+        @ApiProperty({ minLength: 0, required: true })
+        name: string;
+      }
+
+      class UpdateUserDto extends CreatUserDto {
+        @ApiProperty({ minLength: 1, required: false })
+        name: string;
+      }
+
+      const schemas = [];
+
+      schemaObjectFactory.exploreModelSchema(CreatUserDto, schemas);
+      schemaObjectFactory.exploreModelSchema(UpdateUserDto, schemas);
+
+      expect(schemas[0][CreatUserDto.name]).toEqual({
+        type: 'object',
+        properties: { name: { type: 'string', minLength: 0 } },
+        required: ['name']
+      });
+
+      expect(schemas[1][UpdateUserDto.name]).toEqual({
+        type: 'object',
+        properties: { name: { type: 'string', minLength: 1 } }
+      });
+    });
   });
 });