You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
544 lines
16 KiB
544 lines
16 KiB
'use strict';
|
|
|
|
const _ = require('lodash');
|
|
|
|
/**
|
|
* Sequelize provides a host of custom error classes, to allow you to do easier debugging. All of these errors are exposed on the sequelize object and the sequelize constructor.
|
|
* All sequelize errors inherit from the base JS error object.
|
|
*
|
|
* This means that errors can be accessed using `Sequelize.ValidationError` or `sequelize.ValidationError`
|
|
* The Base Error all Sequelize Errors inherit from.
|
|
*/
|
|
class BaseError extends Error {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeBaseError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.BaseError = BaseError;
|
|
|
|
/**
|
|
* Scope Error. Thrown when the sequelize cannot query the specified scope.
|
|
*/
|
|
class SequelizeScopeError extends BaseError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeScopeError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.SequelizeScopeError = SequelizeScopeError;
|
|
|
|
/**
|
|
* Validation Error. Thrown when the sequelize validation has failed. The error contains an `errors` property,
|
|
* which is an array with 1 or more ValidationErrorItems, one for each validation that failed.
|
|
*
|
|
* @param {string} message Error message
|
|
* @param {Array} [errors] Array of ValidationErrorItem objects describing the validation errors
|
|
*
|
|
* @property errors {ValidationErrorItems[]}
|
|
*/
|
|
class ValidationError extends BaseError {
|
|
constructor(message, errors) {
|
|
super(message);
|
|
this.name = 'SequelizeValidationError';
|
|
this.message = 'Validation Error';
|
|
/**
|
|
*
|
|
* @type {ValidationErrorItem[]}
|
|
*/
|
|
this.errors = errors || [];
|
|
|
|
// Use provided error message if available...
|
|
if (message) {
|
|
this.message = message;
|
|
|
|
// ... otherwise create a concatenated message out of existing errors.
|
|
} else if (this.errors.length > 0 && this.errors[0].message) {
|
|
this.message = this.errors.map(err => (err.type || err.origin) + ': ' + err.message).join(',\n');
|
|
}
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
|
|
/**
|
|
* Gets all validation error items for the path / field specified.
|
|
*
|
|
* @param {string} path The path to be checked for error items
|
|
* @returns {ValidationErrorItem[]} Validation error items for the specified path
|
|
*/
|
|
get(path) {
|
|
return this.errors.reduce((reduced, error) => {
|
|
if (error.path === path) {
|
|
reduced.push(error);
|
|
}
|
|
return reduced;
|
|
}, []);
|
|
}
|
|
}
|
|
exports.ValidationError = ValidationError;
|
|
|
|
/**
|
|
* Thrown when attempting to update a stale model instance
|
|
*/
|
|
class OptimisticLockError extends BaseError {
|
|
constructor(options) {
|
|
options = options || {};
|
|
options.message = options.message || 'Attempting to update a stale model instance: ' + options.modelName;
|
|
super(options);
|
|
this.name = 'SequelizeOptimisticLockError';
|
|
/**
|
|
* The name of the model on which the update was attempted
|
|
* @type {string}
|
|
*/
|
|
this.modelName = options.modelName;
|
|
/**
|
|
* The values of the attempted update
|
|
* @type {object}
|
|
*/
|
|
this.values = options.values;
|
|
/**
|
|
*
|
|
* @type {object}
|
|
*/
|
|
this.where = options.where;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.OptimisticLockError = OptimisticLockError;
|
|
|
|
/**
|
|
* A base class for all database related errors.
|
|
*/
|
|
class DatabaseError extends BaseError {
|
|
constructor(parent) {
|
|
super(parent.message);
|
|
this.name = 'SequelizeDatabaseError';
|
|
/**
|
|
* @type {Error}
|
|
*/
|
|
this.parent = parent;
|
|
/**
|
|
* @type {Error}
|
|
*/
|
|
this.original = parent;
|
|
/**
|
|
* The SQL that triggered the error
|
|
* @type {string}
|
|
*/
|
|
this.sql = parent.sql;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.DatabaseError = DatabaseError;
|
|
|
|
/**
|
|
* Thrown when a database query times out because of a deadlock
|
|
*/
|
|
class TimeoutError extends DatabaseError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeTimeoutError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.TimeoutError = TimeoutError;
|
|
|
|
/**
|
|
* Thrown when a unique constraint is violated in the database
|
|
*/
|
|
class UniqueConstraintError extends ValidationError {
|
|
constructor(options) {
|
|
options = options || {};
|
|
options.parent = options.parent || { sql: '' };
|
|
options.message = options.message || options.parent.message || 'Validation Error';
|
|
options.errors = options.errors || {};
|
|
super(options.message, options.errors);
|
|
|
|
this.name = 'SequelizeUniqueConstraintError';
|
|
this.errors = options.errors;
|
|
this.fields = options.fields;
|
|
this.parent = options.parent;
|
|
this.original = options.parent;
|
|
this.sql = options.parent.sql;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.UniqueConstraintError = UniqueConstraintError;
|
|
|
|
/**
|
|
* Thrown when a foreign key constraint is violated in the database
|
|
*/
|
|
class ForeignKeyConstraintError extends DatabaseError {
|
|
constructor(options) {
|
|
options = options || {};
|
|
options.parent = options.parent || { sql: '' };
|
|
|
|
super(options.parent);
|
|
this.name = 'SequelizeForeignKeyConstraintError';
|
|
|
|
this.message = options.message || options.parent.message || 'Database Error';
|
|
this.fields = options.fields;
|
|
this.table = options.table;
|
|
this.value = options.value;
|
|
this.index = options.index;
|
|
this.reltype = options.reltype;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.ForeignKeyConstraintError = ForeignKeyConstraintError;
|
|
|
|
/**
|
|
* Thrown when an exclusion constraint is violated in the database
|
|
*/
|
|
class ExclusionConstraintError extends DatabaseError {
|
|
constructor(options) {
|
|
options = options || {};
|
|
options.parent = options.parent || { sql: '' };
|
|
|
|
super(options.parent);
|
|
this.name = 'SequelizeExclusionConstraintError';
|
|
|
|
this.message = options.message || options.parent.message || '';
|
|
this.constraint = options.constraint;
|
|
this.fields = options.fields;
|
|
this.table = options.table;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.ExclusionConstraintError = ExclusionConstraintError;
|
|
|
|
/**
|
|
* Thrown when constraint name is not found in the database
|
|
*/
|
|
class UnknownConstraintError extends DatabaseError {
|
|
constructor(message) {
|
|
const parent = { message };
|
|
super(parent);
|
|
this.name = 'SequelizeUnknownConstraintError';
|
|
this.message = message || 'The specified constraint does not exist';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.UnknownConstraintError = UnknownConstraintError;
|
|
|
|
/**
|
|
* Validation Error Item
|
|
* Instances of this class are included in the `ValidationError.errors` property.
|
|
*
|
|
* @param {String} message An error message
|
|
* @param {String} type The type/origin of the validation error
|
|
* @param {String} path The field that triggered the validation error
|
|
* @param {String} value The value that generated the error
|
|
* @param {Object} [inst] the DAO instance that caused the validation error
|
|
* @param {Object} [validatorKey] a validation "key", used for identification
|
|
* @param {String} [fnName] property name of the BUILT-IN validator function that caused the validation error (e.g. "in" or "len"), if applicable
|
|
* @param {String} [fnArgs] parameters used with the BUILT-IN validator function, if applicable
|
|
*/
|
|
class ValidationErrorItem {
|
|
constructor(message, type, path, value, inst, validatorKey, fnName, fnArgs) {
|
|
/**
|
|
* An error message
|
|
*
|
|
* @type {String} message
|
|
*/
|
|
this.message = message || '';
|
|
|
|
/**
|
|
* The type/origin of the validation error
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.type = null;
|
|
|
|
/**
|
|
* The field that triggered the validation error
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.path = path || null;
|
|
|
|
/**
|
|
* The value that generated the error
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.value = value !== undefined ? value : null;
|
|
|
|
this.origin = null;
|
|
|
|
/**
|
|
* The DAO instance that caused the validation error
|
|
*
|
|
* @type {Model}
|
|
*/
|
|
this.instance = inst || null;
|
|
|
|
/**
|
|
* A validation "key", used for identification
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.validatorKey = validatorKey || null;
|
|
|
|
/**
|
|
* Property name of the BUILT-IN validator function that caused the validation error (e.g. "in" or "len"), if applicable
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.validatorName = fnName || null;
|
|
|
|
/**
|
|
* Parameters used with the BUILT-IN validator function, if applicable
|
|
*
|
|
* @type {String}
|
|
*/
|
|
this.validatorArgs = fnArgs || [];
|
|
|
|
if (type) {
|
|
if (ValidationErrorItem.Origins[ type ]) {
|
|
this.origin = type;
|
|
} else {
|
|
const lowercaseType = _.toLower(type + '').trim();
|
|
const realType = ValidationErrorItem.TypeStringMap[ lowercaseType ];
|
|
|
|
if (realType && ValidationErrorItem.Origins[ realType ]) {
|
|
this.origin = realType;
|
|
this.type = type;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This doesn't need captureStackTrace because it's not a subclass of Error
|
|
}
|
|
|
|
/**
|
|
* return a lowercase, trimmed string "key" that identifies the validator.
|
|
*
|
|
* Note: the string will be empty if the instance has neither a valid `validatorKey` property nor a valid `validatorName` property
|
|
*
|
|
* @param {Boolean} [useTypeAsNS=true] controls whether the returned value is "namespace",
|
|
* this parameter is ignored if the validator's `type` is not one of ValidationErrorItem.Origins
|
|
* @param {String} [NSSeparator='.'] a separator string for concatenating the namespace, must be not be empty,
|
|
* defaults to "." (fullstop). only used and validated if useTypeAsNS is TRUE.
|
|
* @throws {Error} thrown if NSSeparator is found to be invalid.
|
|
* @return {String}
|
|
*
|
|
* @private
|
|
*/
|
|
getValidatorKey(useTypeAsNS, NSSeparator) {
|
|
const useTANS = typeof useTypeAsNS === 'undefined' ? true : !!useTypeAsNS;
|
|
const NSSep = typeof NSSeparator === 'undefined' ? '.' : NSSeparator;
|
|
|
|
const type = this.origin;
|
|
const key = this.validatorKey || this.validatorName;
|
|
const useNS = useTANS && type && ValidationErrorItem.Origins[ type ];
|
|
|
|
if (useNS && (typeof NSSep !== 'string' || !NSSep.length)) {
|
|
throw new Error('Invalid namespace separator given, must be a non-empty string');
|
|
}
|
|
|
|
if (!(typeof key === 'string' && key.length)) {
|
|
return '';
|
|
}
|
|
|
|
return _.toLower(useNS ? [type, key].join(NSSep) : key).trim();
|
|
}
|
|
}
|
|
|
|
exports.ValidationErrorItem = ValidationErrorItem;
|
|
|
|
/**
|
|
* An enum that defines valid ValidationErrorItem `origin` values
|
|
*
|
|
* @type {Object}
|
|
* @property CORE {String} specifies errors that originate from the sequelize "core"
|
|
* @property DB {String} specifies validation errors that originate from the storage engine
|
|
* @property FUNCTION {String} specifies validation errors that originate from validator functions (both built-in and custom) defined for a given attribute
|
|
*/
|
|
ValidationErrorItem.Origins = {
|
|
CORE: 'CORE',
|
|
DB: 'DB',
|
|
FUNCTION: 'FUNCTION'
|
|
};
|
|
|
|
/**
|
|
* An object that is used internally by the `ValidationErrorItem` class
|
|
* that maps current `type` strings (as given to ValidationErrorItem.constructor()) to
|
|
* our new `origin` values.
|
|
*
|
|
* @type {Object}
|
|
*/
|
|
ValidationErrorItem.TypeStringMap = {
|
|
'notnull violation': 'CORE',
|
|
'string violation': 'CORE',
|
|
'unique violation': 'DB',
|
|
'validation error': 'FUNCTION'
|
|
};
|
|
|
|
/**
|
|
* A base class for all connection related errors.
|
|
*/
|
|
class ConnectionError extends BaseError {
|
|
constructor(parent) {
|
|
super(parent ? parent.message : '');
|
|
this.name = 'SequelizeConnectionError';
|
|
/**
|
|
* The connection specific error which triggered this one
|
|
* @type {Error}
|
|
*/
|
|
this.parent = parent;
|
|
this.original = parent;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.ConnectionError = ConnectionError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database is refused
|
|
*/
|
|
class ConnectionRefusedError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeConnectionRefusedError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.ConnectionRefusedError = ConnectionRefusedError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database is refused due to insufficient privileges
|
|
*/
|
|
class AccessDeniedError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeAccessDeniedError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.AccessDeniedError = AccessDeniedError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database has a hostname that was not found
|
|
*/
|
|
class HostNotFoundError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeHostNotFoundError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.HostNotFoundError = HostNotFoundError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database has a hostname that was not reachable
|
|
*/
|
|
class HostNotReachableError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeHostNotReachableError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.HostNotReachableError = HostNotReachableError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database has invalid values for any of the connection parameters
|
|
*/
|
|
class InvalidConnectionError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeInvalidConnectionError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.InvalidConnectionError = InvalidConnectionError;
|
|
|
|
/**
|
|
* Thrown when a connection to a database times out
|
|
*/
|
|
class ConnectionTimedOutError extends ConnectionError {
|
|
constructor(parent) {
|
|
super(parent);
|
|
this.name = 'SequelizeConnectionTimedOutError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.ConnectionTimedOutError = ConnectionTimedOutError;
|
|
|
|
/**
|
|
* Thrown when a some problem occurred with Instance methods (see message for details)
|
|
*/
|
|
class InstanceError extends BaseError {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeInstanceError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.InstanceError = InstanceError;
|
|
|
|
/**
|
|
* Thrown when a record was not found, Usually used with rejectOnEmpty mode (see message for details)
|
|
*/
|
|
class EmptyResultError extends BaseError {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeEmptyResultError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.EmptyResultError = EmptyResultError;
|
|
|
|
/**
|
|
* Thrown when an include statement is improperly constructed (see message for details)
|
|
*/
|
|
class EagerLoadingError extends BaseError {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeEagerLoadingError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.EagerLoadingError = EagerLoadingError;
|
|
|
|
/**
|
|
* Thrown when an association is improperly constructed (see message for details)
|
|
*/
|
|
class AssociationError extends BaseError {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeAssociationError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.AssociationError = AssociationError;
|
|
/**
|
|
* Thrown when a query is passed invalid options (see message for details)
|
|
*/
|
|
class QueryError extends BaseError {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = 'SequelizeQueryError';
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.QueryError = QueryError;
|
|
|
|
/**
|
|
* Thrown when bulk operation fails, it represent per record level error.
|
|
* Used with Promise.AggregateError
|
|
*
|
|
* @param {Error} error Error for a given record/instance
|
|
* @param {Object} record DAO instance that error belongs to
|
|
*/
|
|
class BulkRecordError extends BaseError {
|
|
constructor(error, record) {
|
|
super(error.message);
|
|
this.name = 'SequelizeBulkRecordError';
|
|
this.errors = error;
|
|
this.record = record;
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
exports.BulkRecordError = BulkRecordError;
|
|
|