blob: 12a27cfffb6cbf61556eca8eba6fb5cf95c05a47 [file] [log] [blame]
"use strict";
var inherits = require('inherits');
inherits(PouchError, Error);
function PouchError(opts) {
Error.call(opts.reason);
this.status = opts.status;
this.name = opts.error;
this.message = opts.reason;
this.error = true;
}
PouchError.prototype.toString = function () {
return JSON.stringify({
status: this.status,
name: this.name,
message: this.message
});
};
exports.UNAUTHORIZED = new PouchError({
status: 401,
error: 'unauthorized',
reason: "Name or password is incorrect."
});
exports.MISSING_BULK_DOCS = new PouchError({
status: 400,
error: 'bad_request',
reason: "Missing JSON list of 'docs'"
});
exports.MISSING_DOC = new PouchError({
status: 404,
error: 'not_found',
reason: 'missing'
});
exports.REV_CONFLICT = new PouchError({
status: 409,
error: 'conflict',
reason: 'Document update conflict'
});
exports.INVALID_ID = new PouchError({
status: 400,
error: 'invalid_id',
reason: '_id field must contain a string'
});
exports.MISSING_ID = new PouchError({
status: 412,
error: 'missing_id',
reason: '_id is required for puts'
});
exports.RESERVED_ID = new PouchError({
status: 400,
error: 'bad_request',
reason: 'Only reserved document ids may start with underscore.'
});
exports.NOT_OPEN = new PouchError({
status: 412,
error: 'precondition_failed',
reason: 'Database not open'
});
exports.UNKNOWN_ERROR = new PouchError({
status: 500,
error: 'unknown_error',
reason: 'Database encountered an unknown error'
});
exports.BAD_ARG = new PouchError({
status: 500,
error: 'badarg',
reason: 'Some query argument is invalid'
});
exports.INVALID_REQUEST = new PouchError({
status: 400,
error: 'invalid_request',
reason: 'Request was invalid'
});
exports.QUERY_PARSE_ERROR = new PouchError({
status: 400,
error: 'query_parse_error',
reason: 'Some query parameter is invalid'
});
exports.DOC_VALIDATION = new PouchError({
status: 500,
error: 'doc_validation',
reason: 'Bad special document member'
});
exports.BAD_REQUEST = new PouchError({
status: 400,
error: 'bad_request',
reason: 'Something wrong with the request'
});
exports.NOT_AN_OBJECT = new PouchError({
status: 400,
error: 'bad_request',
reason: 'Document must be a JSON object'
});
exports.DB_MISSING = new PouchError({
status: 404,
error: 'not_found',
reason: 'Database not found'
});
exports.IDB_ERROR = new PouchError({
status: 500,
error: 'indexed_db_went_bad',
reason: 'unknown'
});
exports.WSQ_ERROR = new PouchError({
status: 500,
error: 'web_sql_went_bad',
reason: 'unknown'
});
exports.LDB_ERROR = new PouchError({
status: 500,
error: 'levelDB_went_went_bad',
reason: 'unknown'
});
exports.FORBIDDEN = new PouchError({
status: 403,
error: 'forbidden',
reason: 'Forbidden by design doc validate_doc_update function'
});
exports.INVALID_REV = new PouchError({
status: 400,
error: 'bad_request',
reason: 'Invalid rev format'
});
exports.FILE_EXISTS = new PouchError({
status: 412,
error: 'file_exists',
reason: 'The database could not be created, the file already exists.'
});
exports.MISSING_STUB = new PouchError({
status: 412,
error: 'missing_stub'
});
exports.error = function (error, reason, name) {
function CustomPouchError(reason) {
// inherit error properties from our parent error manually
// so as to allow proper JSON parsing.
/* jshint ignore:start */
for (var p in error) {
if (typeof error[p] !== 'function') {
this[p] = error[p];
}
}
/* jshint ignore:end */
if (name !== undefined) {
this.name = name;
}
if (reason !== undefined) {
this.reason = reason;
}
}
CustomPouchError.prototype = PouchError.prototype;
return new CustomPouchError(reason);
};
// Find one of the errors defined above based on the value
// of the specified property.
// If reason is provided prefer the error matching that reason.
// This is for differentiating between errors with the same name and status,
// eg, bad_request.
exports.getErrorTypeByProp = function (prop, value, reason) {
var errors = exports;
var keys = Object.keys(errors).filter(function (key) {
var error = errors[key];
return typeof error !== 'function' && error[prop] === value;
});
var key = reason && keys.filter(function (key) {
var error = errors[key];
return error.message === reason;
})[0] || keys[0];
return (key) ? errors[key] : null;
};
exports.generateErrorFromResponse = function (res) {
var error, errName, errType, errMsg, errReason;
var errors = exports;
errName = (res.error === true && typeof res.name === 'string') ?
res.name :
res.error;
errReason = res.reason;
errType = errors.getErrorTypeByProp('name', errName, errReason);
if (res.missing ||
errReason === 'missing' ||
errReason === 'deleted' ||
errName === 'not_found') {
errType = errors.MISSING_DOC;
} else if (errName === 'doc_validation') {
// doc validation needs special treatment since
// res.reason depends on the validation error.
// see utils.js
errType = errors.DOC_VALIDATION;
errMsg = errReason;
} else if (errName === 'bad_request' && errType.message !== errReason) {
// if bad_request error already found based on reason don't override.
// attachment errors.
if (errReason.indexOf('unknown stub attachment') === 0) {
errType = errors.MISSING_STUB;
errMsg = errReason;
} else {
errType = errors.BAD_REQUEST;
}
}
// fallback to error by statys or unknown error.
if (!errType) {
errType = errors.getErrorTypeByProp('status', res.status, errReason) ||
errors.UNKNOWN_ERROR;
}
error = errors.error(errType, errReason, errName);
// Keep custom message.
if (errMsg) {
error.message = errMsg;
}
// Keep helpful response data in our error messages.
if (res.id) {
error.id = res.id;
}
if (res.status) {
error.status = res.status;
}
if (res.statusText) {
error.name = res.statusText;
}
if (res.missing) {
error.missing = res.missing;
}
return error;
};