data-transfer-object
Version:
Data Transfer Object class built on `class-validator`.
116 lines (115 loc) • 4.8 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataTransferObject = void 0;
const class_validator_1 = require("class-validator");
const validation_exception_1 = require("./validation-exception");
const validation_error_handler_1 = require("./validation-error-handler");
// Strict options by default
const defaultOpts = {
whitelist: true,
forbidNonWhitelisted: true,
forbidUnknownValues: true,
};
// Must use symbols for private properties so that they are not included in validation
/** Cached validation errors from previous validation. */
const validationErrors = Symbol.for('validationErrors');
/** Whether this object has already been validated. */
const validated = Symbol.for('validated');
/** Pending validation promise, if any. */
const ongoingValidation = Symbol.for('ongoingValidation');
/**
* Checks the input error list, and if non-empty, throws an error.
* @param errors The error list to check against.
*/
function assertEmptyErrorList(errors) {
if (errors.length) {
if (!validation_error_handler_1.onValidationError)
throw new validation_exception_1.ValidationException(errors);
validation_error_handler_1.onValidationError(errors);
throw new validation_exception_1.ValidationException(errors);
}
}
/**
* Creates a new data transfer object which will validate and reshape its input
* data based on the validators of its own properties. Must be extended, should
* not be instantiated on its own.
*/
class DataTransferObject {
/**
* Constructs a new instance of a data transfer object with the given input.
* @param data The input data to assign to this data transfer object.
*/
constructor(data) {
/** Cached validation errors from previous validation. */
this[_a] = [];
/** Whether this object has already been validated. */
this[_b] = false;
Object.assign(this, data);
}
/**
* Runs all synchronous validators on this object.
* To run asynchronous validators as well, use `.getValidationErrorsAsync()`.
* @param opts Options to pass to the validator system.
*/
getValidationErrors(opts) {
if (this[validated])
return this[validationErrors];
this[validationErrors] = class_validator_1.validateSync(this, { ...defaultOpts, ...opts });
this[validated] = true;
return this[validationErrors];
}
/**
* Runs all synchronous and asynchronous validators on this object.
* Always returns a promise. To validate synchronously, use `.getValidationErrors()`.
* @param opts Options to pass to the validator system.
*/
async getValidationErrorsAsync(opts) {
if (this[validated])
return this[validationErrors];
const ongoing = this[ongoingValidation];
if (ongoing)
return ongoing;
const newPromise = class_validator_1.validate(this, { ...defaultOpts, ...opts }).then(errs => {
this[validationErrors] = errs;
this[validated] = true;
this[ongoingValidation] = undefined;
return errs;
});
this[ongoingValidation] = newPromise;
return newPromise;
}
/**
* Validates this object (sync validators only), and returns its plain data if validations pass.
* Otherwise, throws an error or runs the appropriate handler set with `setValidationErrorHandler()`.
*
* To run both sync and async validators, use `.validateAsync()`.
* @param opts Options to pass to the validator system.
*/
validate(opts) {
const errors = this.getValidationErrors(opts);
assertEmptyErrorList(errors);
return this.toJSON();
}
/**
* Validates this object asynchronously, and resolves to its plain data if validations pass.
* Otherwise, rejects with an error or runs the appropriate handler set with `setValidationErrorHandler()`.
*
* To validate synchronously, use `.validate()`.
* @param opts Options to pass to the validator system.
*/
async validateAsync(opts) {
const errors = await this.getValidationErrorsAsync(opts);
assertEmptyErrorList(errors);
return this.toJSON();
}
/**
* Returns a JSON friendly object containing only data properties of this object (ie, no validation functions).
* Automatically used by `JSON.stringify()`.
*/
toJSON() {
return Object.fromEntries(Object.entries(this).filter(([_key, val]) => typeof val !== 'function'));
}
}
exports.DataTransferObject = DataTransferObject;
_a = validationErrors, _b = validated;