@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
151 lines (148 loc) • 9.05 kB
JavaScript
import { __decorate } from '../external/tslib/tslib.es6.js';
import { VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT } from '../constant/validator/has-paired-custom-suffixes-fields.constant.js';
import { EHasPairedCustomSuffixesFieldsArgumentType } from '../enum/validator/has-paired-custom-suffixes-fields-argument-type.enum.js';
import '../enum/validator/must-match-one-of-schemas-error-type.enum.js';
import { ValidatorConstraint } from 'class-validator';
// eslint-disable-next-line @elsikora/typescript/naming-convention
let HasPairedCustomSuffixesFieldsValidator = class HasPairedCustomSuffixesFieldsValidator {
/**
* Provides a custom error message describing the validation failure
* @param {ValidationArguments} properties - Validation arguments containing the object being validated
* @returns {string} A descriptive error message explaining why validation failed
*/
defaultMessage(properties) {
const object = properties.object;
const fieldGroups = object.__fieldGroups;
const operatorSuffix = object.__operatorSuffix;
const valueSuffixes = object.__valueSuffixes;
const indexableObject = properties.object;
for (const [baseName, groupSuffixes] of fieldGroups) {
const hasValueSuffix = valueSuffixes.some((suffix) => groupSuffixes.has(suffix));
if (hasValueSuffix && !groupSuffixes.has(operatorSuffix)) {
return `group "${baseName}" with value suffix must have an operator suffix [${operatorSuffix}]`;
}
if (groupSuffixes.has(operatorSuffix)) {
if (groupSuffixes.size === 1) {
return `group "${baseName}" with operator suffix must have at least one value with suffix [${[...valueSuffixes].join(", ")}]`;
}
const operatorField = `${baseName}[${operatorSuffix}]`;
const operatorValue = indexableObject[operatorField];
const operator = operatorValue;
const operatorConfig = VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT.DEFAULT_OPERATION_CONFIGS[operator];
if (!operatorConfig) {
return `Invalid operator "${operator}" for group "${baseName}"`;
}
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.NULL) {
const valueCount = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).length;
if (valueCount > 0) {
return `group "${baseName}" with ${operator} operation should not have any values`;
}
continue;
}
const valueFields = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).map((suffix) => `${baseName}[${suffix}]`);
if (valueFields.length === 0) {
return `group "${baseName}" requires a value for ${operator} operation`;
}
if (valueFields.length > 1) {
return `group "${baseName}" can only have one value with suffix [${[...valueSuffixes].join(", ")}] when operator is present`;
}
// @ts-ignore
// eslint-disable-next-line @elsikora/typescript/no-unsafe-assignment
const value = indexableObject[valueFields[0]];
const isArray = Array.isArray(value);
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.ARRAY && !isArray) {
return `group "${baseName}" with ${operator} operation requires an array value`;
}
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.SINGLE && isArray) {
return `group "${baseName}" with ${operator} operation requires a single value, not an array`;
}
if (isArray) {
if (operatorConfig.exactLength !== undefined && value.length !== operatorConfig.exactLength) {
return `group "${baseName}" with ${operator} operation requires exactly ${String(operatorConfig.exactLength)} values`;
}
if (operatorConfig.minLength !== undefined && value.length < operatorConfig.minLength) {
return `group "${baseName}" with ${operator} operation requires at least ${String(operatorConfig.minLength)} values`;
}
if (operatorConfig.maxLength !== undefined && value.length > operatorConfig.maxLength) {
return `group "${baseName}" with ${operator} operation requires at most ${String(operatorConfig.maxLength)} values`;
}
}
}
}
return `fields must have valid operator-value suffix pairs`;
}
/**
* Validates that fields with suffixes follow the proper operator-value pairing pattern
* @param {unknown} _value - The value being validated (unused)
* @param {{ constraints: [string, Array<string>] } & ValidationArguments} properties - Validation arguments and constraints
* @returns {boolean} True if the object has properly paired suffixes, false otherwise
*/
validate(_value, properties) {
const [operatorSuffix, valueSuffixes] = properties.constraints;
const indexableObject = properties.object;
const fields = Object.keys(indexableObject);
const fieldGroups = new Map();
const suffixPattern = [operatorSuffix, ...valueSuffixes].map((suffix) => suffix.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw `\$&`)).join("|");
const regex = new RegExp(`^(.+?)\\[(${suffixPattern})\\]$`);
for (const field of fields) {
const match = regex.exec(field);
if (match) {
const [, baseName, suffix] = match;
if (!fieldGroups.has(baseName)) {
fieldGroups.set(baseName, new Set());
}
if (indexableObject[field] !== undefined) {
fieldGroups.get(baseName)?.add(suffix);
}
}
}
properties.object.__fieldGroups = fieldGroups;
properties.object.__operatorSuffix = operatorSuffix;
properties.object.__valueSuffixes = valueSuffixes;
for (const [baseName, groupSuffixes] of fieldGroups) {
const hasValueSuffix = valueSuffixes.some((suffix) => groupSuffixes.has(suffix));
if (hasValueSuffix && !groupSuffixes.has(operatorSuffix)) {
return false;
}
if (groupSuffixes.has(operatorSuffix)) {
const operatorField = `${baseName}[${operatorSuffix}]`;
const operatorValue = indexableObject[operatorField];
const operator = operatorValue;
const operatorConfig = VALIDATOR_HAS_PAIRED_CUSTOM_SUFFIXES_FIELDS_CONSTANT.DEFAULT_OPERATION_CONFIGS[operator];
if (!operatorConfig)
return false;
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.NULL) {
const valueCount = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).length;
if (valueCount > 0)
return false;
continue;
}
const valueFields = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).map((suffix) => `${baseName}[${suffix}]`);
if (valueFields.length !== 1)
return false;
// @ts-ignore
// eslint-disable-next-line @elsikora/typescript/no-unsafe-assignment
const value = indexableObject[valueFields[0]];
const isArray = Array.isArray(value);
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.ARRAY && !isArray)
return false;
if (operatorConfig.argumentType === EHasPairedCustomSuffixesFieldsArgumentType.SINGLE && isArray)
return false;
if (isArray) {
if (operatorConfig.exactLength !== undefined && value.length !== operatorConfig.exactLength)
return false;
if (operatorConfig.minLength !== undefined && value.length < operatorConfig.minLength)
return false;
if (operatorConfig.maxLength !== undefined && value.length > operatorConfig.maxLength)
return false;
}
}
}
return true;
}
};
HasPairedCustomSuffixesFieldsValidator = __decorate([
ValidatorConstraint({ async: false, name: "has-paired-custom-suffixes-fields" })
], HasPairedCustomSuffixesFieldsValidator);
export { HasPairedCustomSuffixesFieldsValidator };
//# sourceMappingURL=has-paired-custom-suffixes-fields.validator.js.map