Compare commits

...

10 Commits

@ -0,0 +1,3 @@
{
"extends": "@joepie91/eslint-config"
}

@ -1,3 +1,9 @@
## 2.0.2 (November 25, 2020)
- __Patch:__ Now works on newer Node.js versions, by replacing the internal `create-error` usage with `error-chain`.
- __Patch:__ Various error parsing robustness improvements.
- __Patch:__ Gulp and Babel were removed, as pretty much everything supports ES2015 by now.
## 2.0.1 (July 25, 2017) ## 2.0.1 (July 25, 2017)
* __Patch:__ Made the error message for composite UNIQUE constraint violations slightly more readable, by wrapping multiple columns and values in a set of brackets. * __Patch:__ Made the error message for composite UNIQUE constraint violations slightly more readable, by wrapping multiple columns and values in a set of brackets.

@ -1,18 +0,0 @@
var gulp = require("gulp");
var presetES2015 = require("@joepie91/gulp-preset-es2015");
var source = ["src/**/*.js"]
gulp.task('babel', function() {
return gulp.src(source)
.pipe(presetES2015({
basePath: __dirname
}))
.pipe(gulp.dest("lib/"));
});
gulp.task("watch", function () {
gulp.watch(source, ["babel"]);
});
gulp.task("default", ["babel", "watch"]);

@ -1,3 +1,3 @@
'use strict'; 'use strict';
module.exports = require("./lib"); module.exports = require("./src");

@ -0,0 +1,2 @@
error: invalid input syntax for type timestamp with time zone: "{}"
insert into "transaction_events" ("field", "operator_id", "origin", "transaction_id", "type", "value") values ($1, DEFAULT, $2, $3, $4, $5), ($6, DEFAULT, $7, $8, $9, $10), ($11, DEFAULT, $12, $13, $14, $15), ($16, DEFAULT, $17, $18, $19, $20), ($21, DEFAULT, $22, $23, $24, $25), ($26, DEFAULT, $27, $28, $29, $30), ($31, DEFAULT, $32, $33, $34, $35), ($36, DEFAULT, $37, $38, $39, $40), ($41, DEFAULT, $42, $43, $44, $45), ($46, DEFAULT, $47, $48, $49, $50), ($51, DEFAULT, $52, $53, $54, $55), ($56, DEFAULT, $57, $58, $59, $60), ($61, DEFAULT, $62, $63, $64, $65), ($66, DEFAULT, $67, $68, $69, $70), ($71, DEFAULT, $72, $73, $74, DEFAULT) returning * - invalid input syntax for type json

@ -1,6 +1,6 @@
{ {
"name": "database-error", "name": "database-error",
"version": "2.0.1", "version": "2.0.2",
"description": "Turns errors from database libraries into more useful error objects", "description": "Turns errors from database libraries into more useful error objects",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
@ -22,15 +22,15 @@
"author": "Sven Slootweg", "author": "Sven Slootweg",
"license": "WTFPL", "license": "WTFPL",
"dependencies": { "dependencies": {
"create-error": "^0.3.1", "debug": "^4.1.1",
"error-chain": "^0.1.2",
"pg-error-codes": "^1.0.0" "pg-error-codes": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
"@joepie91/gulp-preset-es2015": "^1.0.1", "@joepie91/eslint-config": "^1.1.0",
"babel-preset-es2015": "^6.6.0", "bluebird": "^3.5.1",
"bluebird": "^3.4.6", "eslint": "^7.14.0",
"gulp": "^3.9.1", "knex": "^0.12.9",
"knex": "^0.12.6", "pg": "^6.4.2"
"pg": "^6.1.0"
} }
} }

@ -1,5 +1,5 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
module.exports = createError("DatabaseError"); module.exports = create("DatabaseError");

@ -1,59 +1,59 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const getColumns = require("../get-columns"); const getColumns = require("../get-columns");
const getValues = require("../get-values"); const getValues = require("../get-values");
let CheckConstraintViolationError = createError(DatabaseError, "CheckConstraintViolationError"); let CheckConstraintViolationError = create("CheckConstraintViolationError", { inheritsFrom: DatabaseError });
let messageRegex = /^(.+) - new row for relation "([^"]+)" violates check constraint "([^"]+)"$/; let messageRegex = /^(.+) - new row for relation "([^"]+)" violates check constraint "([^"]+)"$/;
module.exports = { module.exports = {
error: CheckConstraintViolationError, error: CheckConstraintViolationError,
errorName: "CheckConstraintViolationError", errorName: "CheckConstraintViolationError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23514") (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23514")
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let messageMatch = messageRegex.exec(error.message); let messageMatch = messageRegex.exec(error.message);
if (messageMatch == null) { if (messageMatch == null) {
throw new Error("Encountered unknown error format"); throw new Error("Encountered unknown error format");
} }
let [_, query, table, constraint] = messageMatch; let [_, query, _table, _constraint] = messageMatch;
let columns = getColumns(query); let columns = getColumns(query);
let offendingColumn, message; let offendingColumn, message;
if (columns != null) { if (columns != null) {
/* This is the naming convention that Knex uses for .enum() in PostgreSQL */ /* This is the naming convention that Knex uses for .enum() in PostgreSQL */
offendingColumn = columns.find(column => { offendingColumn = columns.find(column => {
return error.constraint === `${error.table}_${column}_check` return error.constraint === `${error.table}_${column}_check`;
}); });
message = `Value violates the '${error.constraint}' constraint for the '${offendingColumn}' column in the '${error.table}' table`; message = `Value violates the '${error.constraint}' constraint for the '${offendingColumn}' column in the '${error.table}' table`;
} else { } else {
message = `Value violates the '${error.constraint}' constraint for the '${error.table}' table`; message = `Value violates the '${error.constraint}' constraint for the '${error.table}' table`;
} }
return new CheckConstraintViolationError(message, { return new CheckConstraintViolationError(message, {
originalError: error, originalError: error,
pgCode: error.code, pgCode: error.code,
code: pgErrorCodes[error.code], code: pgErrorCodes[error.code],
query: query, query: query,
schema: error.schema, schema: error.schema,
table: error.table, table: error.table,
column: offendingColumn, column: offendingColumn,
constraint: error.constraint, constraint: error.constraint,
values: getValues(error.detail) values: getValues(error.detail)
}); });
} }
}; };

@ -1,50 +1,50 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const getTable = require("../get-table"); const getTable = require("../get-table");
let EnumError = createError(DatabaseError, "EnumError"); let EnumError = create("EnumError", { inheritsFrom: DatabaseError });
let messageRegex = /^(.+) - invalid input value for enum ([^:]+): "([^"]+)"$/; let messageRegex = /^(.+) - invalid input value for enum ([^:]+): "([^"]+)"$/;
module.exports = { module.exports = {
error: EnumError, error: EnumError,
errorName: "EnumError", errorName: "EnumError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "22P02" && error.message.includes("invalid input value for enum")) (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "22P02" && error.message.includes("invalid input value for enum"))
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let messageMatch = messageRegex.exec(error.message); let messageMatch = messageRegex.exec(error.message);
if (messageMatch == null) { if (messageMatch == null) {
throw new Error("Encountered unknown error format"); throw new Error("Encountered unknown error format");
} }
let [_, query, enumType, value] = messageMatch; let [_, query, enumType, value] = messageMatch;
let table = getTable(query); let table = getTable(query);
let message; let message;
if (table != null) { if (table != null) {
message = `Value '${value}' is not an allowed value for the ENUM type '${enumType}' (in table '${table}')`; message = `Value '${value}' is not an allowed value for the ENUM type '${enumType}' (in table '${table}')`;
} else { } else {
message = `Value '${value}' is not an allowed value for the ENUM type '${enumType}'`; message = `Value '${value}' is not an allowed value for the ENUM type '${enumType}'`;
} }
return new EnumError(message, { return new EnumError(message, {
originalError: error, originalError: error,
pgCode: error.code, pgCode: error.code,
code: pgErrorCodes[error.code], code: pgErrorCodes[error.code],
query: query, query: query,
table: table, table: table,
enumType: enumType, enumType: enumType,
value: value value: value
}); });
} }
}; };

@ -1,35 +1,35 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
let ForeignKeyConstraintViolationError = createError(DatabaseError, "ForeignKeyConstraintViolationError"); let ForeignKeyConstraintViolationError = create("ForeignKeyConstraintViolationError", { inheritsFrom: DatabaseError });
let detailsRegex = /^Key \(([^\)]+)\)=\(([^\)]+)\) is not present in table "([^"]+)"\.$/; let detailsRegex = /^Key \(([^\)]+)\)=\(([^\)]+)\) is not present in table "([^"]+)"\.$/;
module.exports = { module.exports = {
error: ForeignKeyConstraintViolationError, error: ForeignKeyConstraintViolationError,
errorName: "ForeignKeyConstraintViolationError", errorName: "ForeignKeyConstraintViolationError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23503") (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23503")
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let [_, column, value, foreignTable] = detailsRegex.exec(error.detail); let [_, column, value, foreignTable] = detailsRegex.exec(error.detail);
return new ForeignKeyConstraintViolationError(`Value for column '${column}' in table '${error.table}' refers to a non-existent key '${value}' in table '${foreignTable}'`, { return new ForeignKeyConstraintViolationError(`Value for column '${column}' in table '${error.table}' refers to a non-existent key '${value}' in table '${foreignTable}'`, {
originalError: error, originalError: error,
pgCode: error.code, pgCode: error.code,
code: pgErrorCodes[error.code], code: pgErrorCodes[error.code],
schema: error.schema, schema: error.schema,
table: error.table, table: error.table,
foreignTable: foreignTable, foreignTable: foreignTable,
column: column, column: column,
value: value, value: value,
constraint: error.constraint constraint: error.constraint
}); });
} }
}; };

@ -1,51 +1,53 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const getTable = require("../get-table"); const getTable = require("../get-table");
let InvalidTypeError = createError(DatabaseError, "InvalidTypeError"); let InvalidTypeError = create("InvalidTypeError", { inheritsFrom: DatabaseError });
/* NOTE: error messages vary. Eg. for boolean-type columns, it states "for type boolean", but for integer-type columns, it starts "for integer". */ /* NOTE: error messages vary. Eg. for boolean-type columns, it states "for type boolean", but for integer-type columns, it starts "for integer". */
let messageRegex = /^(.+) - invalid input syntax for(?: type)? ([^:]+): "([^"]+)"$/; let messageRegex = /^(?:(.+) - )?invalid input syntax for(?: type)? ([^:]+)(?:: "(.+)")?$/;
module.exports = { module.exports = {
error: InvalidTypeError, error: InvalidTypeError,
errorName: "InvalidTypeError", errorName: "InvalidTypeError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "22P02" && error.message.includes("invalid input syntax for")) (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "22P02" && error.message.includes("invalid input syntax for"))
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let messageMatch = messageRegex.exec(error.message); let messageMatch = messageRegex.exec(error.message);
if (messageMatch == null) { if (messageMatch == null) {
throw new Error("Encountered unknown error format"); /* TODO: Update other error parsing modules to display the original error message here as well. */
} throw new Error(`Encountered unknown error format for error message: ${error.message}`);
}
let [_, query, expectedType, value] = messageMatch;
let table = getTable(query); let [_, query, expectedType, value] = messageMatch;
let table = getTable(query);
let message;
let message;
if (table != null) {
message = `Value '${value}' is of the wrong type for a '${expectedType}'-type column (in table '${table}')`; /* TODO: `value` can be undefined! */
} else { if (table != null) {
message = `Value '${value}' is of the wrong type for a '${expectedType}'-type column '${enumType}'`; message = `Value <${value}> is of the wrong type for a '${expectedType}'-type column (in table '${table}')`;
} } else {
message = `Value <${value}> is of the wrong type for a '${expectedType}'-type column`;
return new InvalidTypeError(message, { }
originalError: error,
pgCode: error.code, return new InvalidTypeError(message, {
code: pgErrorCodes[error.code], originalError: error,
query: query, pgCode: error.code,
table: table, code: pgErrorCodes[error.code],
expectedType: expectedType, query: query,
value: value, table: table,
}); expectedType: expectedType,
} value: value,
});
}
}; };

@ -1,36 +1,36 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const getValues = require("../get-values"); const getValues = require("../get-values");
let NotNullConstraintViolationError = createError(DatabaseError, "NotNullConstraintViolationError"); let NotNullConstraintViolationError = create("NotNullConstraintViolationError", { inheritsFrom: DatabaseError });
let messageRegex = /^(.+) - null value in column "([^"]+)" violates not-null constraint$/; let messageRegex = /^(.+) - null value in column "([^"]+)" violates not-null constraint$/;
module.exports = { module.exports = {
error: NotNullConstraintViolationError, error: NotNullConstraintViolationError,
errorName: "NotNullConstraintViolationError", errorName: "NotNullConstraintViolationError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23502") (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23502")
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let [_, query, column] = messageRegex.exec(error.message); let [_, query, _column] = messageRegex.exec(error.message);
return new NotNullConstraintViolationError(`Missing required value for column '${error.column}' in table '${error.table}'`, { return new NotNullConstraintViolationError(`Missing required value for column '${error.column}' in table '${error.table}'`, {
originalError: error, originalError: error,
pgCode: error.code, pgCode: error.code,
code: pgErrorCodes[error.code], code: pgErrorCodes[error.code],
schema: error.schema, schema: error.schema,
table: error.table, table: error.table,
column: error.column, column: error.column,
values: getValues(error.detail), values: getValues(error.detail),
query: query query: query
}); });
} }
}; };

@ -1,40 +1,48 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const getTable = require("../get-table");
let UndefinedColumnError = createError(DatabaseError, "UndefinedColumnError"); let UndefinedColumnError = create("UndefinedColumnError", { inheritsFrom: DatabaseError });
let messageRegex = /^(.+) - column "([^"]+)" of relation "([^"]+)" does not exist$/; let messageRegex = /^(.+) - column "([^"]+)" (?:of relation "([^"]+)" )?does not exist$/;
module.exports = { module.exports = {
error: UndefinedColumnError, error: UndefinedColumnError,
errorName: "UndefinedColumnError", errorName: "UndefinedColumnError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "42703") (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "42703")
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let messageMatch = messageRegex.exec(error.message); let messageMatch = messageRegex.exec(error.message);
if (messageMatch == null) { if (messageMatch == null) {
throw new Error("Encountered unknown error format"); throw new Error("Encountered unknown error format");
} }
let [_, query, column, table] = messageMatch; let [_, query, column, table] = messageMatch;
return new UndefinedColumnError(`The '${column}' column does not exist in the '${table}' table`, { let errorMessage;
originalError: error,
pgCode: error.code, if (table != null) {
code: pgErrorCodes[error.code], errorMessage = `The '${column}' column does not exist in the '${table}' table`;
query: query, } else {
table: table, /* TODO: Maybe try to extract this from the query... somehow? */
column: column, errorMessage = `The '${column}' column does not exist in (unknown table)`;
}); }
}
return new UndefinedColumnError(errorMessage, {
originalError: error,
pgCode: error.code,
code: pgErrorCodes[error.code],
query: query,
table: table,
column: column,
});
}
}; };

@ -1,58 +1,58 @@
'use strict'; 'use strict';
const createError = require("create-error"); const { create } = require("error-chain");
const pgErrorCodes = require("pg-error-codes"); const pgErrorCodes = require("pg-error-codes");
const DatabaseError = require("../database-error.js"); const DatabaseError = require("../database-error.js");
const splitValues = require("../split-values"); const splitValues = require("../split-values");
let UniqueConstraintViolationError = createError(DatabaseError, "UniqueConstraintViolationError"); let UniqueConstraintViolationError = create("UniqueConstraintViolationError", { inheritsFrom: DatabaseError });
let detailsRegex = /Key \(([^\)]+)\)=\(([^\)]+)\) already exists\./; let detailsRegex = /Key \(([^\)]+)\)=\(([^\)]+)\) already exists\./;
module.exports = { module.exports = {
error: UniqueConstraintViolationError, error: UniqueConstraintViolationError,
errorName: "UniqueConstraintViolationError", errorName: "UniqueConstraintViolationError",
check: function checkType(error) { check: function checkType(error) {
return ( return (
// PostgreSQL (via `pg`): // PostgreSQL (via `pg`):
(error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23505") (error.length != null && error.file != null && error.line != null && error.routine != null && error.code === "23505")
) );
}, },
convert: function convertError(error) { convert: function convertError(error) {
let [_, columnValue, valueValue] = detailsRegex.exec(error.detail); let [_, columnValue, valueValue] = detailsRegex.exec(error.detail);
let column, columns, value, values, messageColumn, messageValue, isComposite; let column, columns, value, values, messageColumn, messageValue, isComposite;
if (columnValue.includes(",")) { if (columnValue.includes(",")) {
columns = splitValues(columnValue); columns = splitValues(columnValue);
messageColumn = `columns [${columns.map(column => `'${column}'`).join(", ")}]`; messageColumn = `columns [${columns.map(column => `'${column}'`).join(", ")}]`;
isComposite = true; isComposite = true;
} else { } else {
column = columnValue; column = columnValue;
messageColumn = `column '${column}'`; messageColumn = `column '${column}'`;
isComposite = false; isComposite = false;
} }
if (valueValue.includes(",")) { if (valueValue.includes(",")) {
values = splitValues(valueValue); values = splitValues(valueValue);
messageValue = `Values [${values.map(value => `'${value}'`).join(", ")}] already exist`; messageValue = `Values [${values.map(value => `'${value}'`).join(", ")}] already exist`;
} else { } else {
value = valueValue; value = valueValue;
messageValue = `Value '${value}' already exists`; messageValue = `Value '${value}' already exists`;
} }
return new UniqueConstraintViolationError(`${messageValue} for ${messageColumn} in table '${error.table}'`, { return new UniqueConstraintViolationError(`${messageValue} for ${messageColumn} in table '${error.table}'`, {
originalError: error, originalError: error,
pgCode: error.code, pgCode: error.code,
code: pgErrorCodes[error.code], code: pgErrorCodes[error.code],
schema: error.schema, schema: error.schema,
table: error.table, table: error.table,
column: column, column: column,
columns: columns, columns: columns,
value: value, value: value,
values: values, values: values,
isComposite: isComposite, isComposite: isComposite,
constraint: error.constraint constraint: error.constraint
}); });
} }
}; };

@ -5,15 +5,15 @@ let updateRegex = /^update "[^"]+" set (.+) where/;
let updateColumnRegex = /^"([^"]+)"/; let updateColumnRegex = /^"([^"]+)"/;
module.exports = function getColumns(query) { module.exports = function getColumns(query) {
let match, columns; let match;
if (match = insertRegex.exec(query)) { if (match = insertRegex.exec(query)) {
return match[1].split(",").map((columnName) => { return match[1].split(",").map((columnName) => {
return columnName.trim().slice(1, -1) return columnName.trim().slice(1, -1);
}); });
} else if (match = updateRegex.exec(query)) { } else if (match = updateRegex.exec(query)) {
return match[1].split(",").map((statement) => { return match[1].split(",").map((statement) => {
return updateColumnRegex.exec(statement.trim())[1]; return updateColumnRegex.exec(statement.trim())[1];
}); });
} }
}; };

@ -4,11 +4,11 @@ let insertRegex = /^insert into "([^"]+)"/;
let updateRegex = /^update "([^"]+)"/; let updateRegex = /^update "([^"]+)"/;
module.exports = function getTable(query) { module.exports = function getTable(query) {
let match; let match;
if (match = insertRegex.exec(query)) { if (match = insertRegex.exec(query)) {
return match[1]; return match[1];
} else if (match = updateRegex.exec(query)) { } else if (match = updateRegex.exec(query)) {
return match[1]; return match[1];
} }
}; };

@ -1,15 +1,15 @@
'use strict'; 'use strict';
let detailsRegex = /^Failing row contains \(([^\)]+)\).$/; let detailsRegex = /^Failing row contains \((.+)\).$/;
module.exports = function getValues(detail) { module.exports = function getValues(detail) {
let detailsMatch = detailsRegex.exec(detail); let detailsMatch = detailsRegex.exec(detail);
if (detailsMatch == null) { if (detailsMatch == null) {
throw new Error("Could not determine values for query"); throw new Error("Could not determine values for query");
} }
let [_, valueList] = detailsMatch; let [_, valueList] = detailsMatch;
return valueList.split(", "); return valueList.split(", ");
}; };

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const createError = require("create-error"); const createError = require("create-error");
const debug = require("debug")("database-error");
const DatabaseError = require("./database-error"); const DatabaseError = require("./database-error");
@ -14,12 +15,13 @@ let handlers = [
require("./errors/invalid-type"), require("./errors/invalid-type"),
require("./errors/undefined-column"), require("./errors/undefined-column"),
require("./errors/not-null-constraint-violation"), require("./errors/not-null-constraint-violation"),
] ];
function convertError(error) { function convertError(error) {
let handler = handlers.find(handler => handler.check(error)); let handler = handlers.find(handler => handler.check(error));
if (handler != null) { if (handler != null) {
debug(`Converting error with message: ${error.message}`);
return handler.convert(error); return handler.convert(error);
} else { } else {
throw new UnknownError("The specified error is not of a recognized type"); throw new UnknownError("The specified error is not of a recognized type");
@ -49,4 +51,4 @@ module.exports = Object.assign({
rethrow: rethrowBetterError, rethrow: rethrowBetterError,
UnknownError: UnknownError, UnknownError: UnknownError,
DatabaseError: DatabaseError DatabaseError: DatabaseError
}, errorTypes) }, errorTypes);

@ -1,16 +1,14 @@
'use strict'; 'use strict';
const Promise = require("bluebird");
module.exports = { module.exports = {
up: function createCheckConstraintViolationTable(knex, errorHandler) { up: function createCheckConstraintViolationTable(knex, errorHandler) {
return knex.schema.createTable("check_constraint_violation", (table) => { return knex.schema.createTable("check_constraint_violation", (table) => {
table.increments("id"); table.increments("id");
table.enum("number_value", ["one", "two", "three"]); table.enum("number_value", ["one", "two", "three"]);
table.text("name"); table.text("name");
}).catch(errorHandler); }).catch(errorHandler);
}, },
down: function dropCheckConstraintViolationTable(knex, errorHandler) { down: function dropCheckConstraintViolationTable(knex, errorHandler) {
return knex.schema.dropTable("check_constraint_violation").catch(errorHandler); return knex.schema.dropTable("check_constraint_violation").catch(errorHandler);
} }
}; };

@ -1,16 +1,16 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
up: function createUniqueConstraintViolationTable(knex, errorHandler) { up: function createUniqueConstraintViolationTable(knex, errorHandler) {
return knex.schema.createTable("composite_unique_constraint_violation", (table) => { return knex.schema.createTable("composite_unique_constraint_violation", (table) => {
table.increments("id"); table.increments("id");
table.text("email"); table.text("email");
table.text("username"); table.text("username");
table.text("name"); table.text("name");
table.unique(["email", "username"]); table.unique(["email", "username"]);
}).catch(errorHandler); }).catch(errorHandler);
}, },
down: function dropUniqueConstraintViolationTable(knex, errorHandler) { down: function dropUniqueConstraintViolationTable(knex, errorHandler) {
return knex.schema.dropTable("composite_unique_constraint_violation").catch(errorHandler); return knex.schema.dropTable("composite_unique_constraint_violation").catch(errorHandler);
} }
}; };

@ -3,22 +3,22 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
module.exports = { module.exports = {
up: function createEnumViolationTable(knex, errorHandler) { up: function createEnumViolationTable(knex, errorHandler) {
return Promise.try(() => { return Promise.try(() => {
return knex.raw("CREATE TYPE number AS ENUM ('one', 'two', 'three')").catch(errorHandler); return knex.raw("CREATE TYPE number AS ENUM ('one', 'two', 'three')").catch(errorHandler);
}).then(() => { }).then(() => {
return knex.schema.createTable("enum_violation", (table) => { return knex.schema.createTable("enum_violation", (table) => {
table.increments("id"); table.increments("id");
table.specificType("number_value", "number"); table.specificType("number_value", "number");
table.text("name"); table.text("name");
}).catch(errorHandler); }).catch(errorHandler);
}); });
}, },
down: function dropEnumViolationTable(knex, errorHandler) { down: function dropEnumViolationTable(knex, errorHandler) {
return Promise.try(() => { return Promise.try(() => {
return knex.schema.dropTable("enum_violation").catch(errorHandler); return knex.schema.dropTable("enum_violation").catch(errorHandler);
}).then(() => { }).then(() => {
return knex.raw("DROP TYPE number").catch(errorHandler); return knex.raw("DROP TYPE number").catch(errorHandler);
}); });
} }
}; };

@ -3,26 +3,26 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
module.exports = { module.exports = {
up: function createForeignKeyConstraintViolationTable(knex, errorHandler) { up: function createForeignKeyConstraintViolationTable(knex, errorHandler) {
return Promise.try(() => { return Promise.try(() => {
return knex.schema.createTable("foreign_key_constraint_users", (table) => { return knex.schema.createTable("foreign_key_constraint_users", (table) => {
table.increments("id"); table.increments("id");
table.text("username"); table.text("username");
table.text("name"); table.text("name");
}).catch(errorHandler); }).catch(errorHandler);
}).then(() => { }).then(() => {
return knex.schema.createTable("foreign_key_constraint_posts", (table) => { return knex.schema.createTable("foreign_key_constraint_posts", (table) => {
table.increments("id"); table.increments("id");
table.integer("user_id").references("id").inTable("foreign_key_constraint_users"); table.integer("user_id").references("id").inTable("foreign_key_constraint_users");
table.text("body"); table.text("body");
}).catch(errorHandler); }).catch(errorHandler);
}); });
}, },
down: function dropForeignKeyConstraintViolationTable(knex, errorHandler) { down: function dropForeignKeyConstraintViolationTable(knex, errorHandler) {
return Promise.try(() => { return Promise.try(() => {
return knex.schema.dropTable("foreign_key_constraint_posts").catch(errorHandler); return knex.schema.dropTable("foreign_key_constraint_posts").catch(errorHandler);
}).then(() => { }).then(() => {
return knex.schema.dropTable("foreign_key_constraint_users").catch(errorHandler); return knex.schema.dropTable("foreign_key_constraint_users").catch(errorHandler);
}); });
} }
}; };

@ -3,40 +3,40 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
let tables = [ let tables = [
require("./unique-constraint-violation"), require("./unique-constraint-violation"),
require("./composite-unique-constraint-violation"), require("./composite-unique-constraint-violation"),
require("./check-constraint-violation"), require("./check-constraint-violation"),
require("./foreign-key-constraint-violation"), require("./foreign-key-constraint-violation"),
require("./enum"), require("./enum"),
require("./invalid-type"), require("./invalid-type"),
require("./not-null-constraint-violation") require("./not-null-constraint-violation")
]; ];
let noop = function noop(err) { let noop = function noop(_err) {
// Do nothing. // Do nothing.
} };
let rethrow = function rethrowError(err) { let rethrow = function rethrowError(err) {
throw err; throw err;
} };
module.exports = { module.exports = {
up: function createTables(knex) { up: function createTables(knex) {
return Promise.map(tables, (table) => { return Promise.map(tables, (table) => {
return table.up(knex, rethrow); return table.up(knex, rethrow);
}); });
}, },
down: function dropTables(knex, ignoreErrors) { down: function dropTables(knex, ignoreErrors) {
let errorHandler; let errorHandler;
if (ignoreErrors) { if (ignoreErrors) {
errorHandler = noop; errorHandler = noop;
} else { } else {
errorHandler = rethrow; errorHandler = rethrow;
} }
return Promise.map(tables, (table) => { return Promise.map(tables, (table) => {
return table.down(knex, errorHandler); return table.down(knex, errorHandler);
}); });
} }
} };

@ -1,15 +1,15 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
up: function createInvalidTypeTable(knex, errorHandler) { up: function createInvalidTypeTable(knex, errorHandler) {
return knex.schema.createTable("invalid_type", (table) => { return knex.schema.createTable("invalid_type", (table) => {
table.increments("id"); table.increments("id");
table.integer("age"); table.integer("age");
table.text("name"); table.text("name");
table.boolean("active"); table.boolean("active");
}).catch(errorHandler); }).catch(errorHandler);
}, },
down: function dropInvalidTypeTable(knex, errorHandler) { down: function dropInvalidTypeTable(knex, errorHandler) {
return knex.schema.dropTable("invalid_type").catch(errorHandler); return knex.schema.dropTable("invalid_type").catch(errorHandler);
} }
}; };

@ -1,14 +1,14 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
up: function createNotNullConstraintViolationTable(knex, errorHandler) { up: function createNotNullConstraintViolationTable(knex, errorHandler) {
return knex.schema.createTable("not_null_violation", (table) => { return knex.schema.createTable("not_null_violation", (table) => {
table.increments("id"); table.increments("id");
table.text("email").notNull(); table.text("email").notNull();
table.text("name"); table.text("name");
}).catch(errorHandler); }).catch(errorHandler);
}, },
down: function dropNotNullConstraintViolationTable(knex, errorHandler) { down: function dropNotNullConstraintViolationTable(knex, errorHandler) {
return knex.schema.dropTable("not_null_violation").catch(errorHandler); return knex.schema.dropTable("not_null_violation").catch(errorHandler);
} }
}; };

@ -1,14 +1,14 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
up: function createUniqueConstraintViolationTable(knex, errorHandler) { up: function createUniqueConstraintViolationTable(knex, errorHandler) {
return knex.schema.createTable("unique_constraint_violation", (table) => { return knex.schema.createTable("unique_constraint_violation", (table) => {
table.increments("id"); table.increments("id");
table.text("email").unique(); table.text("email").unique();
table.text("name"); table.text("name");
}).catch(errorHandler); }).catch(errorHandler);
}, },
down: function dropUniqueConstraintViolationTable(knex, errorHandler) { down: function dropUniqueConstraintViolationTable(knex, errorHandler) {
return knex.schema.dropTable("unique_constraint_violation").catch(errorHandler); return knex.schema.dropTable("unique_constraint_violation").catch(errorHandler);
} }
}; };

@ -10,29 +10,29 @@ const path = require("path");
const createTables = require("./create-tables"); const createTables = require("./create-tables");
let db = knex({ let db = knex({
client: "pg", client: "pg",
connection: { connection: {
host: "localhost", host: "localhost",
user: "sven", user: "sven",
password: "password", password: "password",
database: "database_error" database: "database_error"
}, },
debug: true debug: true
}); });
return Promise.try(() => { return Promise.try(() => {
return createTables.down(db, true); return createTables.down(db, true);
}).then(() => { }).then(() => {
return createTables.up(db); return createTables.up(db);
}).then(() => { }).then(() => {
let testcase = require(path.join(process.cwd(), process.argv[2])); let testcase = require(path.join(process.cwd(), process.argv[2]));
return testcase(db); return testcase(db);
}).catch(databaseError.rethrow).catch((err) => { }).catch(databaseError.rethrow).catch((err) => {
console.log("__________________\n"); console.log("__________________\n");
console.error(util.inspect(err, {colors: true, depth: 1})); console.error(util.inspect(err, {colors: true, depth: 1}));
console.log("__________________\n"); console.log("__________________\n");
}).finally(() => { }).finally(() => {
return createTables.down(db); return createTables.down(db);
}).finally(() => { }).finally(() => {
return db.destroy(); return db.destroy();
}); });

@ -1,11 +1,11 @@
'use strict'; 'use strict';
module.exports = function attemptCheckConstraintViolation(knex) { module.exports = function attemptCheckConstraintViolation(knex) {
return knex("check_constraint_violation").insert([{ return knex("check_constraint_violation").insert([{
number_value: "one", number_value: "one",
name: "Joe" name: "Joe"
}, { }, {
number_value: "four", number_value: "four",
name: "Jane" name: "Jane"
}]).returning("*"); }]).returning("*");
}; };

@ -3,16 +3,16 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
module.exports = function attemptCheckConstraintViolation(knex) { module.exports = function attemptCheckConstraintViolation(knex) {
return Promise.try(() => { return Promise.try(() => {
return knex("check_constraint_violation").insert({ return knex("check_constraint_violation").insert({
number_value: "one", number_value: "one",
name: "Joe" name: "Joe"
}).returning("id"); }).returning("id");
}).then((id) => { }).then((id) => {
return knex("check_constraint_violation").update({ return knex("check_constraint_violation").update({
number_value: "four" number_value: "four"
}).where({ }).where({
id: id[0] id: id[0]
}); });
}); });
}; };

@ -1,21 +1,21 @@
'use strict'; 'use strict';
module.exports = function attemptCompositeUniqueConstraintViolation(knex) { module.exports = function attemptCompositeUniqueConstraintViolation(knex) {
return knex("composite_unique_constraint_violation").insert([{ return knex("composite_unique_constraint_violation").insert([{
email: "foo@bar.com", email: "foo@bar.com",
username: "foo", username: "foo",
name: "Joe" name: "Joe"
}, { }, {
email: "baz@qux.com", email: "baz@qux.com",
username: "bar", username: "bar",
name: "Jane" name: "Jane"
}, { }, {
email: "foo@bar.com", email: "foo@bar.com",
username: "baz", username: "baz",
name: "Pete" name: "Pete"
}, { }, {
email: "foo@bar.com", email: "foo@bar.com",
username: "foo", username: "foo",
name: "Jill" name: "Jill"
}]).returning("*"); }]).returning("*");
}; };

@ -1,11 +1,11 @@
'use strict'; 'use strict';
module.exports = function attemptEnumViolation(knex) { module.exports = function attemptEnumViolation(knex) {
return knex("enum_violation").insert([{ return knex("enum_violation").insert([{
number_value: "one", number_value: "one",
name: "Joe" name: "Joe"
}, { }, {
number_value: "four", number_value: "four",
name: "Jane" name: "Jane"
}]).returning("*"); }]).returning("*");
}; };

@ -3,16 +3,16 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
module.exports = function attemptEnumViolation(knex) { module.exports = function attemptEnumViolation(knex) {
return Promise.try(() => { return Promise.try(() => {
return knex("enum_violation").insert({ return knex("enum_violation").insert({
number_value: "one", number_value: "one",
name: "Joe" name: "Joe"
}).returning("id"); }).returning("id");
}).then((id) => { }).then((id) => {
return knex("enum_violation").update({ return knex("enum_violation").update({
number_value: "four" number_value: "four"
}).where({ }).where({
id: id[0] id: id[0]
}); });
}); });
}; };

@ -3,24 +3,24 @@
const Promise = require("bluebird"); const Promise = require("bluebird");
module.exports = function attemptForeignKeyConstraintViolation(knex) { module.exports = function attemptForeignKeyConstraintViolation(knex) {
return Promise.try(() => { return Promise.try(() => {
return knex("foreign_key_constraint_users").insert([{ return knex("foreign_key_constraint_users").insert([{
name: "Joe", name: "Joe",
username: "joe" username: "joe"
}, { }, {
name: "Jane", name: "Jane",
username: "jane" username: "jane"
}]).returning("id"); }]).returning("id");
}).then((ids) => { }).then((ids) => {
return knex("foreign_key_constraint_posts").insert([{ return knex("foreign_key_constraint_posts").insert([{
user_id: ids[0], user_id: ids[0],
body: "Foo" body: "Foo"
}, { }, {
user_id: ids[1], user_id: ids[1],
body: "Bar" body: "Bar"
}, { }, {
user_id: 567213, user_id: 567213,
body: "Baz" body: "Baz"
}]) }]);
}); });
}; };

@ -1,17 +1,17 @@
'use strict'; 'use strict';
module.exports = function attemptInvalidTypeBooleanInverse(knex) { module.exports = function attemptInvalidTypeBooleanInverse(knex) {
return knex("invalid_type").insert([{ return knex("invalid_type").insert([{
name: "Joe", name: "Joe",
age: 29, age: 29,
active: true active: true
}, { }, {
name: "Jane", name: "Jane",
age: 42, age: 42,
active: true active: true
}, { }, {
name: true, name: true,
age: 24, age: 24,
active: false active: false
}]).returning("*"); }]).returning("*");
}; };

@ -1,17 +1,17 @@
'use strict'; 'use strict';
module.exports = function attemptInvalidTypeBoolean(knex) { module.exports = function attemptInvalidTypeBoolean(knex) {
return knex("invalid_type").insert([{ return knex("invalid_type").insert([{
name: "Joe", name: "Joe",
age: 29, age: 29,
active: true active: true
}, { }, {
name: "Jane", name: "Jane",
age: 42, age: 42,
active: true active: true
}, { }, {
name: "Pete", name: "Pete",
age: 24, age: 24,
active: "foo bar" active: "foo bar"
}]).returning("*"); }]).returning("*");
}; };

@ -1,17 +1,17 @@
'use strict'; 'use strict';
module.exports = function attemptInvalidTypeInteger(knex) { module.exports = function attemptInvalidTypeInteger(knex) {
return knex("invalid_type").insert([{ return knex("invalid_type").insert([{
name: "Joe", name: "Joe",
age: 29, age: 29,
active: true active: true
}, { }, {
name: "Jane", name: "Jane",
age: 42, age: 42,
active: true active: true
}, { }, {
name: "Pete", name: "Pete",
age: "twenty-four", age: "twenty-four",
active: false active: false
}]).returning("*"); }]).returning("*");
}; };

@ -1,12 +1,12 @@
'use strict'; 'use strict';
module.exports = function attemptNotNullConstraintViolation(knex) { module.exports = function attemptNotNullConstraintViolation(knex) {
return knex("not_null_violation").insert([{ return knex("not_null_violation").insert([{
email: "foo@bar.com", email: "foo@bar.com",
name: "Joe" name: "Joe"
}, { }, {
email: "baz@qux.com" email: "baz@qux.com"
}, { }, {
name: "Pete" name: "Pete"
}]).returning("*"); }]).returning("*");
}; };

@ -1,10 +1,10 @@
'use strict'; 'use strict';
module.exports = function attemptUndefinedColumn(knex) { module.exports = function attemptUndefinedColumn(knex) {
return knex("invalid_type").insert([{ return knex("invalid_type").insert([{
name: "Joe", name: "Joe",
age: 29, age: 29,
active: true, active: true,
nonexistentColumn: "Hello!" nonexistentColumn: "Hello!"
}]).returning("*"); }]).returning("*");
}; };

@ -1,14 +1,14 @@
'use strict'; 'use strict';
module.exports = function attemptUniqueConstraintViolation(knex) { module.exports = function attemptUniqueConstraintViolation(knex) {
return knex("unique_constraint_violation").insert([{ return knex("unique_constraint_violation").insert([{
email: "foo@bar.com", email: "foo@bar.com",
name: "Joe" name: "Joe"
}, { }, {
email: "baz@qux.com", email: "baz@qux.com",
name: "Jane" name: "Jane"
}, { }, {
email: "foo@bar.com", email: "foo@bar.com",
name: "Pete" name: "Pete"
}]).returning("*"); }]).returning("*");
}; };

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save