UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

147 lines (144 loc) 8.97 kB
'use strict'; var tslib_es6 = require('../../external/tslib/tslib.es6.js'); var operatorRegistry_constant = require('../../constant/filter/operator-registry.constant.js'); var operand_enum = require('../../enum/filter/operand.enum.js'); require('../../enum/filter/operation.enum.js'); require('../../enum/filter/order-direction.enum.js'); var classValidator = require('class-validator'); // eslint-disable-next-line @elsikora/typescript/naming-convention exports.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)) { const operatorField = `${baseName}[${operatorSuffix}]`; const operatorValue = indexableObject[operatorField]; const operator = operatorValue; const operatorConfig = operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.OPERATORS[operator]; if (!operatorConfig) { return `Invalid operator "${operator}" for group "${baseName}"`; } if (operatorConfig.operand === operand_enum.EFilterOperand.NONE) { const valueCount = valueSuffixes.filter((suffix) => groupSuffixes.has(suffix)).length; if (valueCount > 0) { return `group "${baseName}" with ${operator} operation should not have any values`; } continue; } if (groupSuffixes.size === 1) { return `group "${baseName}" with operator suffix must have at least one value with suffix [${[...valueSuffixes].join(", ")}]`; } 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.operand === operand_enum.EFilterOperand.PAIR || operatorConfig.operand === operand_enum.EFilterOperand.VALUES) && !isArray) { return `group "${baseName}" with ${operator} operation requires an array value`; } if (operatorConfig.operand === operand_enum.EFilterOperand.VALUE && isArray) { return `group "${baseName}" with ${operator} operation requires a single value, not an array`; } if (isArray) { if (operatorConfig.operand === operand_enum.EFilterOperand.PAIR && value.length !== operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.PAIR_OPERAND_COUNT) { return `group "${baseName}" with ${operator} operation requires exactly ${String(operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.PAIR_OPERAND_COUNT)} values`; } if (operatorConfig.operand === operand_enum.EFilterOperand.VALUES && value.length < operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.VALUES_MINIMUM_OPERAND_COUNT) { return `group "${baseName}" with ${operator} operation requires at least ${String(operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.VALUES_MINIMUM_OPERAND_COUNT)} value`; } } } } 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(String.raw `^(.+?)\[(${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 = operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.OPERATORS[operator]; if (!operatorConfig) return false; if (operatorConfig.operand === operand_enum.EFilterOperand.NONE) { 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.operand === operand_enum.EFilterOperand.PAIR || operatorConfig.operand === operand_enum.EFilterOperand.VALUES) && !isArray) return false; if (operatorConfig.operand === operand_enum.EFilterOperand.VALUE && isArray) return false; if (isArray) { if (operatorConfig.operand === operand_enum.EFilterOperand.PAIR && value.length !== operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.PAIR_OPERAND_COUNT) return false; if (operatorConfig.operand === operand_enum.EFilterOperand.VALUES && value.length < operatorRegistry_constant.FILTER_OPERATOR_REGISTRY_CONSTANT.VALUES_MINIMUM_OPERAND_COUNT) return false; } } } return true; } }; exports.HasPairedCustomSuffixesFieldsValidator = tslib_es6.__decorate([ classValidator.ValidatorConstraint({ async: false, name: "has-paired-custom-suffixes-fields" }) ], exports.HasPairedCustomSuffixesFieldsValidator); //# sourceMappingURL=paired-custom-suffixes-fields.validator.js.map