required-property-validator.js 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import {DataType} from './data-type.js';
  2. import {Service} from '@e22m4u/js-service';
  3. import {BlankValuesService} from '@e22m4u/js-empty-values';
  4. import {InvalidArgumentError} from '../../../errors/index.js';
  5. import {ModelDefinitionUtils} from '../model-definition-utils.js';
  6. /**
  7. * Required property validator.
  8. */
  9. export class RequiredPropertyValidator extends Service {
  10. /**
  11. * Validate.
  12. *
  13. * @param {string} modelName
  14. * @param {object} modelData
  15. * @param {boolean} [isPartial]
  16. */
  17. validate(modelName, modelData, isPartial = false) {
  18. if (!modelName || typeof modelName !== 'string') {
  19. throw new InvalidArgumentError(
  20. 'Parameter "modelName" must be a non-empty String, but %v was given.',
  21. modelName,
  22. );
  23. }
  24. if (
  25. !modelData ||
  26. typeof modelData !== 'object' ||
  27. Array.isArray(modelData)
  28. ) {
  29. throw new InvalidArgumentError(
  30. 'Data of the model %v should be an Object, but %v was given.',
  31. modelName,
  32. modelData,
  33. );
  34. }
  35. if (typeof isPartial !== 'boolean') {
  36. throw new InvalidArgumentError(
  37. 'Parameter "isPartial" must be a Boolean, but %v was given.',
  38. isPartial,
  39. );
  40. }
  41. const propDefs =
  42. this.getService(
  43. ModelDefinitionUtils,
  44. ).getPropertiesDefinitionInBaseModelHierarchy(modelName);
  45. const propNames = Object.keys(isPartial ? modelData : propDefs);
  46. const blankValuesService = this.getService(BlankValuesService);
  47. for (const propName of propNames) {
  48. const propDef = propDefs[propName];
  49. if (!propDef || typeof propDef !== 'object') {
  50. continue;
  51. }
  52. // проверка основного значения
  53. const propValue = modelData[propName];
  54. if (propDef.required) {
  55. const propType = propDef.type || DataType.ANY;
  56. if (blankValuesService.isBlankOf(propType, propValue)) {
  57. throw new InvalidArgumentError(
  58. 'Property %v of the model %v is required, but %v was given.',
  59. propName,
  60. modelName,
  61. propValue,
  62. );
  63. }
  64. }
  65. // проверка вложенного объекта
  66. if (
  67. propDef.type === DataType.OBJECT &&
  68. propDef.model &&
  69. propValue !== null &&
  70. typeof propValue === 'object' &&
  71. !Array.isArray(propValue)
  72. ) {
  73. this.validate(propDef.model, propValue);
  74. }
  75. // проверка массива объектов
  76. else if (
  77. propDef.type === DataType.ARRAY &&
  78. propDef.itemType === DataType.OBJECT &&
  79. propDef.itemModel &&
  80. Array.isArray(propValue)
  81. ) {
  82. propValue.forEach(itemData => {
  83. if (
  84. itemData !== null &&
  85. typeof itemData === 'object' &&
  86. !Array.isArray(itemData)
  87. ) {
  88. this.validate(propDef.itemModel, itemData);
  89. }
  90. });
  91. }
  92. }
  93. }
  94. }