@nestjs/graphql
Version:
Nest - modern, fast, powerful node.js web framework (@graphql)
77 lines (76 loc) • 3.4 kB
JavaScript
import { isFunction } from '@nestjs/common/utils/shared.utils.js';
import { applyIsOptionalDecorator, applyValidateIfDefinedDecorator, inheritPropertyInitializers, inheritTransformationMetadata, inheritValidationMetadata, } from '@nestjs/mapped-types';
import { Field } from '../decorators/index.js';
import { MetadataLoader } from '../plugin/metadata-loader.js';
import { METADATA_FACTORY_NAME } from '../plugin/plugin-constants.js';
import { getFieldsAndDecoratorForType } from '../schema-builder/utils/get-fields-and-decorator.util.js';
import { applyFieldDecorators } from './type-helpers.utils.js';
function isPartialTypeOptions(optionsOrDecorator) {
return (optionsOrDecorator &&
('decorator' in optionsOrDecorator ||
'omitDefaultValues' in optionsOrDecorator ||
'skipNullProperties' in optionsOrDecorator));
}
export function PartialType(classRef, optionsOrDecorator) {
const { fields, decoratorFactory } = getFieldsAndDecoratorForType(classRef);
class PartialObjectType {
constructor() {
inheritPropertyInitializers(this, classRef);
}
}
let decorator;
let omitDefaultValues = false;
let skipNullProperties = true;
if (isPartialTypeOptions(optionsOrDecorator)) {
decorator = optionsOrDecorator.decorator;
omitDefaultValues = optionsOrDecorator.omitDefaultValues;
skipNullProperties = optionsOrDecorator.skipNullProperties ?? true;
}
else {
decorator = optionsOrDecorator;
}
const applyPartialDecoratorFn = skipNullProperties === false
? applyValidateIfDefinedDecorator
: applyIsOptionalDecorator;
if (decorator) {
decorator({ isAbstract: true })(PartialObjectType);
}
else {
decoratorFactory({ isAbstract: true })(PartialObjectType);
}
inheritValidationMetadata(classRef, PartialObjectType);
inheritTransformationMetadata(classRef, PartialObjectType);
function applyFields(fields) {
fields.forEach((item) => {
if (isFunction(item.typeFn)) {
// Execute type function eagerly to update the type options object (before "clone" operation)
// when the passed function (e.g., @Field(() => Type)) lazily returns an array.
item.typeFn();
}
Field(item.typeFn, {
...item.options,
nullable: true,
defaultValue: omitDefaultValues ? undefined : item.options.defaultValue,
})(PartialObjectType.prototype, item.name);
applyPartialDecoratorFn(PartialObjectType, item.name);
applyFieldDecorators(PartialObjectType, item);
});
}
applyFields(fields);
// Register a refresh hook to update the fields when the serialized metadata
// is loaded from file.
MetadataLoader.addRefreshHook(() => {
const { fields } = getFieldsAndDecoratorForType(classRef, {
overrideFields: true,
});
applyFields(fields);
});
if (PartialObjectType[METADATA_FACTORY_NAME]) {
const pluginFields = Object.keys(PartialObjectType[METADATA_FACTORY_NAME]());
pluginFields.forEach((key) => applyPartialDecoratorFn(PartialObjectType, key));
}
Object.defineProperty(PartialObjectType, 'name', {
value: `Partial${classRef.name}`,
});
return PartialObjectType;
}