-
-
Notifications
You must be signed in to change notification settings - Fork 523
Description
What is the problem this feature would solve?
There are various reasons why a sql query may fail: ConnectTimeout, LockWaitTimeout, Deadlock, DuplicateEntry, SyntaxError, etc. Some errors are retriable (e.g. LockWaitTimeout), some are retriable with some modifications to the "query values" (e.g. DuplicateEntry), others aren't retriable at all.
Currently, the only way to distinguish the various types of errors is by doing something like this:
import type { QueryError } from "mysql2";
Effect.catchTag("SqlError", (error) => {
if (error.cause instanceof Error) {
const originalError = error.cause as QueryError;
switch (originalError.code) {
"ER_DUP_ENTRY": // ...
"ER_LOCK_WAIT_TIMEOUT": // ...
// etc.
default: // ...
}
}
})What is the feature you are proposing to solve the problem?
Extend the SqlError type with a code field, so that the block becomes a bit simpler:
Effect.catchTag("SqlError", (error) => {
switch (error.code) {
"ER_DUP_ENTRY": // ...
"ER_LOCK_WAIT_TIMEOUT": // ...
// etc.
default: // ...
}
})The challenge is to pick the right type for code. It cannot simply be an enumeration such as:
type Code = "ER_DUP_ENTRY" | "ER_LOCK_WAIT_TIMEOUT" | ...;These codes are not database-agnostic. For example, the duplicate entry key constraint violation error is called:
Typing it as string is more robust but lacks a good DX.
Another way to go would be to use the greatest common divisor approach, standardize some error codes within Effect SQL and perform some mapping within the sql-xyz libraries themselves.
Another option would be to ditch the codes but use SQLSTATE, a standardized five-character alphanumeric code used in database systems to identify the outcome of a SQL statement.
What alternatives have you considered?
I have considered two alternative solutions:
- Replacing
SqlErrorwith a union of its specific errors:DuplicateEntrySqlError|LockWaitTimeoutSqlError| ... |OtherSqlError. The problem with this approach would be too many error tags every time an Effect has to interact with the DB. Also, all these errors would appear on all queries regardless of their nature. For example, it is impossible to get aDuplicateEntrySqlErrorfor a read-only query. - Extending the
SqlErrortype with aisRetriableboolean. The problem is that errors such asDuplicateEntryare not retriable without the right modifications to the query (maybe one of the ids has to be incremented, or so). In such case would it be a retriable or a non-retriable error? Maybe aretryStrategy: "without_modification" | "with_modification" | "never"might work better (I can't think of a better wording at the moment).