|
1 month ago | |
---|---|---|
src | 1 month ago | |
test | 1 month ago | |
.eslintrc | 1 month ago | |
.gitignore | 4 years ago | |
.npmignore | 4 years ago | |
CHANGELOG.md | 1 month ago | |
README.md | 3 years ago | |
index.js | 1 month ago | |
notes.txt | 1 month ago | |
package.json | 1 month ago | |
yarn.lock | 1 month ago |
A small library to make error objects from databases more programmatically useful. Currently supports:
pg
(not pg.native
!).Database libraries tend to throw rather hard-to-process errors - often, they will contain a mishmash of information in a single error message string, with no clear way to filter or handle them programmatically. This library solves that by parsing the errors for you, and turning them into more consistent, useful, identifiable, and structured error objects.
Note that while Knex is supported (since it uses pg
internally, for talking to PostgreSQL), it is not required - this library should work fine with any other pg
-based implementation as well. Support for other (relational) database libraries is planned in the future, with the intention to provide a standardized format for useful database errors.
WTFPL or CC0, whichever you prefer. A donation and/or attribution are appreciated, but not required.
Maintaining open-source projects takes a lot of time, and the more donations I receive, the more time I can dedicate to open-source. If this module is useful to you, consider making a donation!
You can donate using Bitcoin, PayPal, Flattr, cash-in-mail, SEPA transfers, and pretty much anything else. Thank you!
Pull requests welcome. Please make sure your modifications are in line with the overall code style, and ensure that you’re editing the files in src/
, not those in lib/
.
Build tool of choice is gulp
; simply run gulp
while developing, and it will watch for changes.
Be aware that by making a pull request, you agree to release your modifications under the licenses stated above.
A simple example, detecting a duplicate entry in the database:
const Promise = require("bluebird");
const databaseError = require("database-error");
/* The below objects are used as 'object predicates' in Bluebird's .catch, to filter out the specific kind of database errors we're interested in. Errors are matched by the properties of the predicate object(s). */
let duplicateEmailAddress = {
name: "UniqueConstraintViolationError",
table: "users",
column: "email"
}
let duplicateUsername = {
name: "UniqueConstraintViolationError",
table: "users",
column: "username"
}
// ... assuming we have a Knex instance, and an Express application with an `express-promise-router` ...
router.post("/register", (req, res) => {
Promise.try(() => {
return knex("users").insert({
username: req.body.username,
email: req.body.emailAddress
}).returning("id");
}).then((id) => {
res.send(`Hello, user ${id[0]}!`);
}).catch(databaseError.rethrow).catch(duplicateEmailAddress, (err) => {
res.status(422).send("That e-mail address already exists! Please pick a different one.");
}).catch(duplicateUsername, (err) => {
res.status(422).send("That username already exists! Please pick a different one.");
})
});
This assumes the following:
users
table exists, with an id
, username
and email
column.email
and username
columns both have a UNIQUE constraint set on them, disallowing duplicates.When a user attempts to register a new account, and either their provided username or e-mail address already exist in the database the following happens:
pg
).databaseError.rethrow
in the first .catch
statement, and turned into a more useful error (with the clearly distinguishable UniqueConstraintViolationError
name, and structured table
/column
properties).databaseError.rethrow
..catch
statement each receive the new error, check whether it has the properties they’re looking for, and if so, trigger the corresponding error handler.A brief listing of the currently defined error types, for easier searching:
The full documentation for each type is below.
Rethrows a more useful error, where possible.
Throws:
database-error
error object. This will be one of the types specified below.In practice, this means that unrecognized errors are “passed through”, while recognized errors are converted into more useful errors.
You would not normally use this method directly, and you should probably use databaseError.rethrow
instead.
Converts the specified error
into a more useful Error object.
Returns/throws:
database-error
error object. This will be one of the types specified below.databaseError.UnknownError
.Special error type that’s thrown for databaseError.convert
when an unrecognized error is provided. You will never encounter this error when using databaseError.rethrow
, and it does not include any further information.
“Base type” that all other error types (except for UnknownError
) are inheriting from. This can be useful for logging all recognized database errors.
However, note that you will never encounter a DatabaseError
directly - it purely functions as a base type, meaning that you need to use instanceof
to recognize an error as a DatabaseError
, and matching by name is not sufficient.
Every error inheriting from DatabaseError
will always contain the following properties:
In addition, different errors include different other properties. These are listed for each error type below.
This error is thrown when a query violates a UNIQUE
constraint. In practice, this means that there’s an attempt to insert a duplicate entry into your database (see also the Usage section above).
A UniqueConstraintViolationError
will contain the following additional properties:
UNIQUE
constraints:
UNIQUE
constraints:
UNIQUE
constraint involves multiple columns. Boolean.UNIQUE
constraint that is being violated.Note that the keys for composite UNIQUE
constraints are plural, not singular. This is intentional, to provide a more predictable API.
This error is thrown when a query violates a foreign key constraint. In practice, this means that there’s an attempt to point a foreign key at a non-existent entry (usually in another table).
A ForeignKeyConstraintViolationError
will contain the following additional properties:
This error is thrown when a query violates a NOT NULL
constraint. In practice, this usually means that a required value is missing.
A NotNullConstraintViolationError
will contain the following additional properties:
This error is thrown when a query violates a CHECK
constraint. This can mean a lot of things (as CHECK
constraints can be fairly arbitrary), but one of the most common cases is probably an invalid value for a Knex-defined “enum”, since Knex uses CHECK
constraints rather than native ENUMs.
An CheckConstraintViolationError
will contain the following additional properties:
<table>_<column>_check
format (like is the case for Knex-defined “enum” columns).CHECK
constraint that is being violated.This error is thrown when a query attempts to store a value of the wrong type in a column. Note that it does not always occur when storing a value of the wrong type, as some databases and libraries attempt to cast values automatically, and will only throw this error when they are unable to do so.
Unfortunately, when using PostgreSQL, InvalidTypeError
errors include very little information to pinpoint the problem, and there is no way for this library to obtain more information. You should make sure to validate value types carefully before attempting to insert them into the database, to prevent this type of error from occurring.
An InvalidTypeError
will contain the following additional properties:
This error is thrown when a query attempts to store a value in an ENUM-type column, and that value isn’t one of the allowed values.
Unfortunately, when using PostgreSQL, EnumError
errors include very little information to pinpoint the problem, and there is no way for this library to obtain more information. You should make sure to validate ENUM values in your application carefully before attempting to insert them into the database, to prevent this type of error from occurring.
An EnumError
will contain the following additional properties:
This error is thrown when a query attempts to store a value into a column that doesn’t exist. A typical cause of this is forgetting to update the database schema after updating an application.
An UndefinedColumnError
will contain the following additional properties: