validation-error.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. 'use strict';
  2. const BaseError = require('./base-error');
  3. /**
  4. * Validation Error. Thrown when the sequelize validation has failed. The error contains an `errors` property,
  5. * which is an array with 1 or more ValidationErrorItems, one for each validation that failed.
  6. *
  7. * @param {string} message Error message
  8. * @param {Array} [errors] Array of ValidationErrorItem objects describing the validation errors
  9. *
  10. * @property errors {ValidationErrorItems[]}
  11. */
  12. class ValidationError extends BaseError {
  13. constructor(message, errors) {
  14. super(message);
  15. this.name = 'SequelizeValidationError';
  16. this.message = 'Validation Error';
  17. /**
  18. *
  19. * @type {ValidationErrorItem[]}
  20. */
  21. this.errors = errors || [];
  22. // Use provided error message if available...
  23. if (message) {
  24. this.message = message;
  25. // ... otherwise create a concatenated message out of existing errors.
  26. } else if (this.errors.length > 0 && this.errors[0].message) {
  27. this.message = this.errors.map(err => `${err.type || err.origin}: ${err.message}`).join(',\n');
  28. }
  29. }
  30. /**
  31. * Gets all validation error items for the path / field specified.
  32. *
  33. * @param {string} path The path to be checked for error items
  34. *
  35. * @returns {Array<ValidationErrorItem>} Validation error items for the specified path
  36. */
  37. get(path) {
  38. return this.errors.reduce((reduced, error) => {
  39. if (error.path === path) {
  40. reduced.push(error);
  41. }
  42. return reduced;
  43. }, []);
  44. }
  45. }
  46. /**
  47. * Validation Error Item
  48. * Instances of this class are included in the `ValidationError.errors` property.
  49. */
  50. class ValidationErrorItem {
  51. /**
  52. * Creates a new ValidationError item. Instances of this class are included in the `ValidationError.errors` property.
  53. *
  54. * @param {string} [message] An error message
  55. * @param {string} [type] The type/origin of the validation error
  56. * @param {string} [path] The field that triggered the validation error
  57. * @param {string} [value] The value that generated the error
  58. * @param {Model} [instance] the DAO instance that caused the validation error
  59. * @param {string} [validatorKey] a validation "key", used for identification
  60. * @param {string} [fnName] property name of the BUILT-IN validator function that caused the validation error (e.g. "in" or "len"), if applicable
  61. * @param {Array} [fnArgs] parameters used with the BUILT-IN validator function, if applicable
  62. */
  63. constructor(message, type, path, value, instance, validatorKey, fnName, fnArgs) {
  64. /**
  65. * An error message
  66. *
  67. * @type {string} message
  68. */
  69. this.message = message || '';
  70. /**
  71. * The type/origin of the validation error
  72. *
  73. * @type {string | null}
  74. */
  75. this.type = null;
  76. /**
  77. * The field that triggered the validation error
  78. *
  79. * @type {string | null}
  80. */
  81. this.path = path || null;
  82. /**
  83. * The value that generated the error
  84. *
  85. * @type {string | null}
  86. */
  87. this.value = value !== undefined ? value : null;
  88. this.origin = null;
  89. /**
  90. * The DAO instance that caused the validation error
  91. *
  92. * @type {Model | null}
  93. */
  94. this.instance = instance || null;
  95. /**
  96. * A validation "key", used for identification
  97. *
  98. * @type {string | null}
  99. */
  100. this.validatorKey = validatorKey || null;
  101. /**
  102. * Property name of the BUILT-IN validator function that caused the validation error (e.g. "in" or "len"), if applicable
  103. *
  104. * @type {string | null}
  105. */
  106. this.validatorName = fnName || null;
  107. /**
  108. * Parameters used with the BUILT-IN validator function, if applicable
  109. *
  110. * @type {Array}
  111. */
  112. this.validatorArgs = fnArgs || [];
  113. if (type) {
  114. if (ValidationErrorItem.Origins[ type ]) {
  115. this.origin = type;
  116. } else {
  117. const lowercaseType = `${type}`.toLowerCase().trim();
  118. const realType = ValidationErrorItem.TypeStringMap[ lowercaseType ];
  119. if (realType && ValidationErrorItem.Origins[ realType ]) {
  120. this.origin = realType;
  121. this.type = type;
  122. }
  123. }
  124. }
  125. // This doesn't need captureStackTrace because it's not a subclass of Error
  126. }
  127. /**
  128. * return a lowercase, trimmed string "key" that identifies the validator.
  129. *
  130. * Note: the string will be empty if the instance has neither a valid `validatorKey` property nor a valid `validatorName` property
  131. *
  132. * @param {boolean} [useTypeAsNS=true] controls whether the returned value is "namespace",
  133. * this parameter is ignored if the validator's `type` is not one of ValidationErrorItem.Origins
  134. * @param {string} [NSSeparator='.'] a separator string for concatenating the namespace, must be not be empty,
  135. * defaults to "." (fullstop). only used and validated if useTypeAsNS is TRUE.
  136. * @throws {Error} thrown if NSSeparator is found to be invalid.
  137. * @returns {string}
  138. *
  139. * @private
  140. */
  141. getValidatorKey(useTypeAsNS, NSSeparator) {
  142. const useTANS = useTypeAsNS === undefined || !!useTypeAsNS;
  143. const NSSep = NSSeparator === undefined ? '.' : NSSeparator;
  144. const type = this.origin;
  145. const key = this.validatorKey || this.validatorName;
  146. const useNS = useTANS && type && ValidationErrorItem.Origins[ type ];
  147. if (useNS && (typeof NSSep !== 'string' || !NSSep.length)) {
  148. throw new Error('Invalid namespace separator given, must be a non-empty string');
  149. }
  150. if (!(typeof key === 'string' && key.length)) {
  151. return '';
  152. }
  153. return (useNS ? [type, key].join(NSSep) : key).toLowerCase().trim();
  154. }
  155. }
  156. /**
  157. * An enum that defines valid ValidationErrorItem `origin` values
  158. *
  159. * @type {object}
  160. * @property CORE {string} specifies errors that originate from the sequelize "core"
  161. * @property DB {string} specifies validation errors that originate from the storage engine
  162. * @property FUNCTION {string} specifies validation errors that originate from validator functions (both built-in and custom) defined for a given attribute
  163. */
  164. ValidationErrorItem.Origins = {
  165. CORE: 'CORE',
  166. DB: 'DB',
  167. FUNCTION: 'FUNCTION'
  168. };
  169. /**
  170. * An object that is used internally by the `ValidationErrorItem` class
  171. * that maps current `type` strings (as given to ValidationErrorItem.constructor()) to
  172. * our new `origin` values.
  173. *
  174. * @type {object}
  175. */
  176. ValidationErrorItem.TypeStringMap = {
  177. 'notnull violation': 'CORE',
  178. 'string violation': 'CORE',
  179. 'unique violation': 'DB',
  180. 'validation error': 'FUNCTION'
  181. };
  182. module.exports = ValidationError;
  183. module.exports.ValidationErrorItem = ValidationErrorItem;