Reference · Database

db.error_kind

signature
db.error_kind(any) -> str | null

What it does

What kind of failure a database's error value is, in one word that is the same for SQLite, PostgreSQL and MySQL, whose own messages differ: "unique" (a key or unique column has the value already), "foreign_key", "not_null", "check", or "conflict" (another transaction: the database busy, a deadlock, a serialization failure), or "connection" (the server ended the connection, or it could not be made) (since 0.7). Any other failure, and anything that is not a database error, is null. It needs no effect, so it can be called from any function.

A PostgreSQL error's message ends in its SQLSTATE, in brackets: db: duplicate key value violates unique constraint "seats_pkey" (Key (k)=(1) already exists.) [23505]. The code is read first, so the kind is found whatever language the server writes its messages in: 23505 is unique, 23503 foreign_key, 23502 not_null, 23514 check, and 40001, 40P01 and 55P03 conflict, and 57P01 to 57P03 and class 08 connection. MySQL's messages carry their code too ((1062)), and SQLite's words are always English.

Examples

db.open("app.db")db.exec("create table seats (show text, seat text, unique (show, seat))")db.exec("insert into seats values ('tonight', 'A1')")let r = db.exec("insert into seats values (?, ?)", "tonight", "A1")print(db.error_kind(r))if db.error_kind(r) == "unique" { print("Someone has just taken that seat") }
output
uniqueSomeone has just taken that seat

Edge cases

db.open("app.db")db.exec("create table teams (id integer primary key)")db.exec("create table users (id integer primary key, email text unique not null, age integer check (age >= 0), team integer references teams(id))")print(db.error_kind(db.exec("insert into users (email) values ('a@x.io')")))print(db.error_kind(db.exec("insert into users (email) values ('a@x.io')")))print(db.error_kind(db.exec("insert into users (email) values (null)")))print(db.error_kind(db.exec("insert into users (email, age) values ('b@x.io', -1)")))print(db.error_kind(db.exec("insert into users (email, team) values ('c@x.io', 9)")))let other = db.exec("insert into nope values (1)")print(db.error_kind(other), is_err(other))print(db.error_kind(err("unique")), db.error_kind("unique"), db.error_kind(null), db.error_kind(read_file("nope")))
output
nulluniquenot_nullcheckforeign_keynull truenull null null null

Errors

db.error_kind never fails: whatever it is given, the answer is a word or null. The usual shape is to name the failures the user can mend and pass the rest on with ?:

db.open("app.db")db.exec("create table users (email text unique)")db.exec("insert into users values ('a@x.io')")fn signup(email: str) {    let r = db.exec("insert into users values (?)", email)    if db.error_kind(r) == "unique" { return err("that email is taken") }    r?    "welcome"}print(signup("b@x.io"), signup("a@x.io"))
output
welcome err("that email is taken")

Chaining

db.open("app.db")db.exec("create table t (n integer unique)")print([1, 1, 2] | map((n) => db.exec("insert into t values (?)", n)) | map(db.error_kind))print(db.exec("insert into t values (2)") | db.error_kind)
output
[null, "unique", null]unique

See also

db.exec, db.transaction, is_err, err

Thread
7Useful? Like it, or add to its thread below.

Thread 0 posts

On db.error_kind(): questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.

    Edit this page on GitHub · every example's output was made by running it (tools/refcheck.mjs) · questions on Discord or r/quillo