Skip to content

Commit

Permalink
Merge branch 'Diluka-intersection-type-helper'
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Apr 17, 2020
2 parents 05e1651 + 7393bbf commit 35a8cf6
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 300 deletions.
2 changes: 1 addition & 1 deletion lib/services/model-properties-accessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class ModelPropertiesAccessor {
}
const metadata = prototype.constructor[METADATA_FACTORY_NAME]();
const properties = Object.keys(metadata);
properties.forEach(key => {
properties.forEach((key) => {
createApiPropertyDecorator(metadata[key], false)(classPrototype, key);
});
} while (
Expand Down
1 change: 1 addition & 0 deletions lib/type-helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './intersection-type.helper';
export * from './omit-type.helper';
export * from './partial-type.helper';
export * from './pick-type.helper';
63 changes: 63 additions & 0 deletions lib/type-helpers/intersection-type.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Type } from '@nestjs/common';
import {
inheritTransformationMetadata,
inheritValidationMetadata
} from '@nestjs/mapped-types';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import { clonePluginMetadataFactory } from './mapped-types.utils';

const modelPropertiesAccessor = new ModelPropertiesAccessor();

export function IntersectionType<A, B>(
classARef: Type<A>,
classBRef: Type<B>
): Type<A & B> {
const fieldsOfA = modelPropertiesAccessor.getModelProperties(
classARef.prototype
);
const fieldsOfB = modelPropertiesAccessor.getModelProperties(
classBRef.prototype
);

abstract class IntersectionTypeClass {}
inheritValidationMetadata(classARef, IntersectionTypeClass);
inheritTransformationMetadata(classARef, IntersectionTypeClass);
inheritValidationMetadata(classBRef, IntersectionTypeClass);
inheritTransformationMetadata(classBRef, IntersectionTypeClass);

clonePluginMetadataFactory(
IntersectionTypeClass as Type<unknown>,
classARef.prototype
);
clonePluginMetadataFactory(
IntersectionTypeClass as Type<unknown>,
classBRef.prototype
);

fieldsOfA.forEach((propertyKey) => {
const metadata = Reflect.getMetadata(
DECORATORS.API_MODEL_PROPERTIES,
classARef.prototype,
propertyKey
);
const decoratorFactory = ApiProperty(metadata);
decoratorFactory(IntersectionTypeClass.prototype, propertyKey);
});

fieldsOfB.forEach((propertyKey) => {
const metadata = Reflect.getMetadata(
DECORATORS.API_MODEL_PROPERTIES,
classBRef.prototype,
propertyKey
);
const decoratorFactory = ApiProperty(metadata);
decoratorFactory(IntersectionTypeClass.prototype, propertyKey);
});

Object.defineProperty(IntersectionTypeClass, 'name', {
value: `Intersection${classARef.name}${classBRef.name}`
});
return IntersectionTypeClass as Type<A & B>;
}
43 changes: 43 additions & 0 deletions lib/type-helpers/mapped-types.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Type } from '@nestjs/common';
import { identity } from 'lodash';
import { METADATA_FACTORY_NAME } from '../plugin/plugin-constants';

export function clonePluginMetadataFactory(
target: Type<unknown>,
parent: Type<unknown>,
transformFn: (metadata: Record<string, any>) => Record<string, any> = identity
) {
let targetMetadata = {};

do {
if (!parent.constructor) {
return;
}
if (!parent.constructor[METADATA_FACTORY_NAME]) {
continue;
}
const parentMetadata = parent.constructor[METADATA_FACTORY_NAME]();
targetMetadata = {
...parentMetadata,
...targetMetadata
};
} while (
(parent = Reflect.getPrototypeOf(parent) as Type<any>) &&
parent !== Object.prototype &&
parent
);
targetMetadata = transformFn(targetMetadata);

if (target[METADATA_FACTORY_NAME]) {
const originalFactory = target[METADATA_FACTORY_NAME];
target[METADATA_FACTORY_NAME] = () => {
const originalMetadata = originalFactory();
return {
...originalMetadata,
...targetMetadata
};
};
} else {
target[METADATA_FACTORY_NAME] = () => targetMetadata;
}
}
16 changes: 12 additions & 4 deletions lib/type-helpers/omit-type.helper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Type } from '@nestjs/common';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import {
inheritTransformationMetadata,
inheritValidationMetadata
} from './type-helpers.utils';
} from '@nestjs/mapped-types';
import { omit } from 'lodash';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import { clonePluginMetadataFactory } from './mapped-types.utils';

const modelPropertiesAccessor = new ModelPropertiesAccessor();

Expand All @@ -24,6 +26,12 @@ export function OmitType<T, K extends keyof T>(
inheritValidationMetadata(classRef, OmitTypeClass, isInheritedPredicate);
inheritTransformationMetadata(classRef, OmitTypeClass, isInheritedPredicate);

clonePluginMetadataFactory(
OmitTypeClass as Type<unknown>,
classRef.prototype,
(metadata: Record<string, any>) => omit(metadata, keys)
);

fields.forEach((propertyKey) => {
const metadata = Reflect.getMetadata(
DECORATORS.API_MODEL_PROPERTIES,
Expand Down
17 changes: 13 additions & 4 deletions lib/type-helpers/partial-type.helper.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Type } from '@nestjs/common';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import {
applyIsOptionalDecorator,
inheritTransformationMetadata,
inheritValidationMetadata
} from './type-helpers.utils';
} from '@nestjs/mapped-types';
import { mapValues } from 'lodash';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import { clonePluginMetadataFactory } from './mapped-types.utils';

const modelPropertiesAccessor = new ModelPropertiesAccessor();

Expand All @@ -17,6 +19,13 @@ export function PartialType<T>(classRef: Type<T>): Type<Partial<T>> {
inheritValidationMetadata(classRef, PartialTypeClass);
inheritTransformationMetadata(classRef, PartialTypeClass);

clonePluginMetadataFactory(
PartialTypeClass as Type<unknown>,
classRef.prototype,
(metadata: Record<string, any>) =>
mapValues(metadata, (item) => ({ ...item, required: false }))
);

fields.forEach((key) => {
const metadata =
Reflect.getMetadata(
Expand Down
16 changes: 12 additions & 4 deletions lib/type-helpers/pick-type.helper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Type } from '@nestjs/common';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import {
inheritTransformationMetadata,
inheritValidationMetadata
} from './type-helpers.utils';
} from '@nestjs/mapped-types';
import { pick } from 'lodash';
import { DECORATORS } from '../constants';
import { ApiProperty } from '../decorators';
import { ModelPropertiesAccessor } from '../services/model-properties-accessor';
import { clonePluginMetadataFactory } from './mapped-types.utils';

const modelPropertiesAccessor = new ModelPropertiesAccessor();

Expand All @@ -24,6 +26,12 @@ export function PickType<T, K extends keyof T>(
inheritValidationMetadata(classRef, PickTypeClass, isInheritedPredicate);
inheritTransformationMetadata(classRef, PickTypeClass, isInheritedPredicate);

clonePluginMetadataFactory(
PickTypeClass as Type<unknown>,
classRef.prototype,
(metadata: Record<string, any>) => pick(metadata, keys)
);

fields.forEach((propertyKey) => {
const metadata = Reflect.getMetadata(
DECORATORS.API_MODEL_PROPERTIES,
Expand Down
140 changes: 0 additions & 140 deletions lib/type-helpers/type-helpers.utils.ts

This file was deleted.

5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"release": "release-it"
},
"dependencies": {
"@nestjs/mapped-types": "0.0.1",
"lodash": "4.17.15",
"path-to-regexp": "3.2.0"
},
Expand Down
Loading

0 comments on commit 35a8cf6

Please sign in to comment.