Packages

A compile-time safe database library for Gleam - Ecto-inspired schemas, composable queries, and adapter-based persistence

Current section

Files

Jump to
cquill src cquill@error.erl
Raw

src/cquill@error.erl

-module(cquill@error).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/cquill/error.gleam").
-export([is_not_found/1, is_constraint_violation/1, is_unique_violation/1, is_foreign_key_violation/1, is_connection_error/1, is_recoverable/1, is_query_error/1, format_error/1, format_error_compact/1, format_transaction_error/1, format_transaction_error_compact/1, format_savepoint_error/1, format_savepoint_error_compact/1, from_postgres_error/3, from_mysql_error/2, from_sqlite_error/2, not_found/0, query_failed/1, query_failed_with_code/2, connection_failed/1, timeout/0, unique_violation/2, not_supported/1, adapter_specific/2]).
-export_type([adapter_error/0, transaction_error/1, savepoint_error/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type adapter_error() :: not_found |
{too_many_rows, integer(), integer()} |
{connection_failed, binary()} |
connection_timeout |
pool_exhausted |
{connection_lost, binary()} |
{query_failed, binary(), gleam@option:option(binary())} |
{decode_failed, integer(), binary(), binary(), binary()} |
timeout |
{unique_violation, binary(), binary()} |
{foreign_key_violation, binary(), binary()} |
{check_violation, binary(), binary()} |
{not_null_violation, binary()} |
{constraint_violation, binary(), binary()} |
{stale_data, binary(), binary()} |
{data_integrity_error, binary()} |
{not_supported, binary()} |
{adapter_specific, binary(), binary()}.
-type transaction_error(LAT) :: {user_error, LAT} |
{adapter_transaction_error, adapter_error()} |
{begin_failed, binary()} |
{commit_failed, binary()} |
rolled_back |
{transaction_rollback, binary()} |
transaction_connection_lost |
nested_transaction_error |
transaction_timeout |
serialization_failure.
-type savepoint_error(LAU) :: {savepoint_not_found, binary()} |
{savepoint_adapter_error, adapter_error()} |
{savepoint_user_error, LAU} |
{savepoint_creation_failed, binary()} |
{savepoint_release_failed, binary()} |
savepoint_no_transaction.
-file("src/cquill/error.gleam", 169).
?DOC(" Check if an error indicates the record was not found\n").
-spec is_not_found(adapter_error()) -> boolean().
is_not_found(Error) ->
case Error of
not_found ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 177).
?DOC(" Check if an error is any kind of constraint violation\n").
-spec is_constraint_violation(adapter_error()) -> boolean().
is_constraint_violation(Error) ->
case Error of
{unique_violation, _, _} ->
true;
{foreign_key_violation, _, _} ->
true;
{check_violation, _, _} ->
true;
{not_null_violation, _} ->
true;
{constraint_violation, _, _} ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 189).
?DOC(" Check if an error is a unique constraint violation\n").
-spec is_unique_violation(adapter_error()) -> boolean().
is_unique_violation(Error) ->
case Error of
{unique_violation, _, _} ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 197).
?DOC(" Check if an error is a foreign key violation\n").
-spec is_foreign_key_violation(adapter_error()) -> boolean().
is_foreign_key_violation(Error) ->
case Error of
{foreign_key_violation, _, _} ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 205).
?DOC(" Check if an error is a connection-related error\n").
-spec is_connection_error(adapter_error()) -> boolean().
is_connection_error(Error) ->
case Error of
{connection_failed, _} ->
true;
connection_timeout ->
true;
pool_exhausted ->
true;
{connection_lost, _} ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 216).
?DOC(" Check if an error is recoverable (can retry)\n").
-spec is_recoverable(adapter_error()) -> boolean().
is_recoverable(Error) ->
case Error of
{connection_failed, _} ->
true;
connection_timeout ->
true;
pool_exhausted ->
true;
{connection_lost, _} ->
true;
timeout ->
true;
{stale_data, _, _} ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 233).
?DOC(" Check if an error is a query/execution error\n").
-spec is_query_error(adapter_error()) -> boolean().
is_query_error(Error) ->
case Error of
{query_failed, _, _} ->
true;
{decode_failed, _, _, _, _} ->
true;
timeout ->
true;
_ ->
false
end.
-file("src/cquill/error.gleam", 409).
?DOC(
" Sanitize connection messages to prevent leaking sensitive information.\n"
"\n"
" Removes potential passwords, connection strings, and other secrets.\n"
).
-spec sanitize_connection_message(binary()) -> binary().
sanitize_connection_message(Message) ->
Lower = string:lowercase(Message),
case ((((gleam_stdlib:contains_string(Lower, <<"password"/utf8>>) orelse gleam_stdlib:contains_string(
Lower,
<<"pwd="/utf8>>
))
orelse gleam_stdlib:contains_string(Lower, <<"postgres://"/utf8>>))
orelse gleam_stdlib:contains_string(Lower, <<"mysql://"/utf8>>))
orelse gleam_stdlib:contains_string(Lower, <<"secret"/utf8>>))
orelse gleam_stdlib:contains_string(Lower, <<"api_key"/utf8>>) of
true ->
<<"[connection details redacted]"/utf8>>;
false ->
Message
end.
-file("src/cquill/error.gleam", 255).
?DOC(
" Format an error for display with clear, actionable messages.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" let error = UniqueViolation(\"users_email_key\", \"Key (email)=(test@example.com) already exists\")\n"
" format_error(error)\n"
" // -> \"Unique constraint violation on users_email_key\\n Key (email)=(test@example.com) already exists\\n\\nHint: Check if a record with this value exists before inserting,\\n or use an upsert operation for insert-or-update semantics.\"\n"
" ```\n"
).
-spec format_error(adapter_error()) -> binary().
format_error(Error) ->
case Error of
not_found ->
<<"Record not found\n\nHint: Verify the record exists before querying, or use get_by which returns Option."/utf8>>;
{too_many_rows, Expected, Got} ->
<<<<<<<<"Too many rows returned: expected "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(Got))/binary>>/binary,
"\n\nHint: Add more specific conditions to your query, or use get_all instead of get_one."/utf8>>;
{connection_failed, Reason} ->
<<<<"Connection failed: "/utf8,
(sanitize_connection_message(Reason))/binary>>/binary,
"\n\nHint: Check that the database server is running and accessible."/utf8>>;
connection_timeout ->
<<"Connection timed out\n\nHint: The database server may be overloaded or unreachable. Check network connectivity and server status."/utf8>>;
pool_exhausted ->
<<"Connection pool exhausted: all connections are in use\n\nHint: Increase the pool size, reduce long-running queries, or check for connection leaks."/utf8>>;
{connection_lost, Reason@1} ->
<<<<"Connection lost: "/utf8,
(sanitize_connection_message(Reason@1))/binary>>/binary,
"\n\nHint: The database connection was interrupted. This operation can be retried."/utf8>>;
{query_failed, Message, none} ->
<<"Query failed: "/utf8, Message/binary>>;
{query_failed, Message@1, {some, Code}} ->
<<<<<<"Query failed ["/utf8, Code/binary>>/binary, "]: "/utf8>>/binary,
Message@1/binary>>;
{decode_failed, Row, Column, Expected@1, Got@1} ->
<<<<<<<<<<<<<<<<"Decode failed at row "/utf8,
(erlang:integer_to_binary(Row))/binary>>/binary,
", column '"/utf8>>/binary,
Column/binary>>/binary,
"': expected type "/utf8>>/binary,
Expected@1/binary>>/binary,
", got "/utf8>>/binary,
Got@1/binary>>/binary,
"\n\nHint: Check that the column type in your schema matches the database column type."/utf8>>;
timeout ->
<<"Operation timed out\n\nHint: Consider adding an index, optimizing the query, or increasing the timeout limit."/utf8>>;
{unique_violation, Constraint, Detail} ->
<<<<<<<<"Unique constraint violation on "/utf8, Constraint/binary>>/binary,
"\n "/utf8>>/binary,
Detail/binary>>/binary,
"\n\nHint: Check if a record with this value exists before inserting,\n or use an upsert operation for insert-or-update semantics."/utf8>>;
{foreign_key_violation, Constraint@1, Detail@1} ->
<<<<<<<<"Foreign key violation on "/utf8, Constraint@1/binary>>/binary,
"\n "/utf8>>/binary,
Detail@1/binary>>/binary,
"\n\nHint: Ensure the referenced record exists before creating this record,\n or check that you're not deleting a record that others depend on."/utf8>>;
{check_violation, Constraint@2, Detail@2} ->
<<<<<<<<"Check constraint violation on "/utf8, Constraint@2/binary>>/binary,
"\n "/utf8>>/binary,
Detail@2/binary>>/binary,
"\n\nHint: Verify that the value meets the constraint requirements defined in the database."/utf8>>;
{not_null_violation, Column@1} ->
<<<<"NOT NULL violation on column '"/utf8, Column@1/binary>>/binary,
"'\n\nHint: Provide a value for this required field, or update the schema to allow NULL."/utf8>>;
{constraint_violation, Constraint@3, Detail@3} ->
<<<<<<"Constraint violation on "/utf8, Constraint@3/binary>>/binary,
"\n "/utf8>>/binary,
Detail@3/binary>>;
{stale_data, Expected@2, Actual} ->
<<<<<<<<"Stale data detected: expected version "/utf8,
Expected@2/binary>>/binary,
", found version "/utf8>>/binary,
Actual/binary>>/binary,
"\n\nHint: The record was modified by another process. Reload the data and retry your operation."/utf8>>;
{data_integrity_error, Message@2} ->
<<<<"Data integrity error: "/utf8, Message@2/binary>>/binary,
"\n\nHint: Check that your data meets all schema requirements and constraints."/utf8>>;
{not_supported, Operation} ->
<<<<"Operation not supported: "/utf8, Operation/binary>>/binary,
"\n\nHint: This operation is not available with the current adapter."/utf8>>;
{adapter_specific, Code@1, Message@3} ->
<<<<<<"Adapter error ["/utf8, Code@1/binary>>/binary, "]: "/utf8>>/binary,
Message@3/binary>>
end.
-file("src/cquill/error.gleam", 355).
?DOC(
" Format an error for display without hints (compact format).\n"
"\n"
" Use this for logging or when hints are not needed.\n"
).
-spec format_error_compact(adapter_error()) -> binary().
format_error_compact(Error) ->
case Error of
not_found ->
<<"Record not found"/utf8>>;
{too_many_rows, Expected, Got} ->
<<<<<<"Too many rows: expected "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
", got "/utf8>>/binary,
(erlang:integer_to_binary(Got))/binary>>;
{connection_failed, Reason} ->
<<"Connection failed: "/utf8,
(sanitize_connection_message(Reason))/binary>>;
connection_timeout ->
<<"Connection timed out"/utf8>>;
pool_exhausted ->
<<"Connection pool exhausted"/utf8>>;
{connection_lost, Reason@1} ->
<<"Connection lost: "/utf8,
(sanitize_connection_message(Reason@1))/binary>>;
{query_failed, Message, none} ->
<<"Query failed: "/utf8, Message/binary>>;
{query_failed, Message@1, {some, Code}} ->
<<<<<<"Query failed ["/utf8, Code/binary>>/binary, "]: "/utf8>>/binary,
Message@1/binary>>;
{decode_failed, Row, Column, Expected@1, Got@1} ->
<<<<<<<<<<<<<<"Decode failed at row "/utf8,
(erlang:integer_to_binary(Row))/binary>>/binary,
", column '"/utf8>>/binary,
Column/binary>>/binary,
"': expected "/utf8>>/binary,
Expected@1/binary>>/binary,
", got "/utf8>>/binary,
Got@1/binary>>;
timeout ->
<<"Operation timed out"/utf8>>;
{unique_violation, Constraint, Detail} ->
<<<<<<"Unique constraint violation: "/utf8, Constraint/binary>>/binary,
" - "/utf8>>/binary,
Detail/binary>>;
{foreign_key_violation, Constraint@1, Detail@1} ->
<<<<<<"Foreign key violation: "/utf8, Constraint@1/binary>>/binary,
" - "/utf8>>/binary,
Detail@1/binary>>;
{check_violation, Constraint@2, Detail@2} ->
<<<<<<"Check constraint violation: "/utf8, Constraint@2/binary>>/binary,
" - "/utf8>>/binary,
Detail@2/binary>>;
{not_null_violation, Column@1} ->
<<"NOT NULL violation on column: "/utf8, Column@1/binary>>;
{constraint_violation, Constraint@3, Detail@3} ->
<<<<<<"Constraint violation: "/utf8, Constraint@3/binary>>/binary,
" - "/utf8>>/binary,
Detail@3/binary>>;
{stale_data, Expected@2, Actual} ->
<<<<<<"Stale data: expected version "/utf8, Expected@2/binary>>/binary,
", found "/utf8>>/binary,
Actual/binary>>;
{data_integrity_error, Message@2} ->
<<"Data integrity error: "/utf8, Message@2/binary>>;
{not_supported, Operation} ->
<<"Operation not supported: "/utf8, Operation/binary>>;
{adapter_specific, Code@1, Message@3} ->
<<<<<<"Adapter error ["/utf8, Code@1/binary>>/binary, "]: "/utf8>>/binary,
Message@3/binary>>
end.
-file("src/cquill/error.gleam", 426).
?DOC(" Format a transaction error for display with actionable hints.\n").
-spec format_transaction_error(transaction_error(any())) -> binary().
format_transaction_error(Error) ->
case Error of
{user_error, _} ->
<<"Transaction aborted: user error\n\nHint: Your transaction callback returned an error. The transaction has been rolled back."/utf8>>;
{adapter_transaction_error, Adapter_err} ->
<<"Transaction aborted: "/utf8,
(format_error_compact(Adapter_err))/binary>>;
{begin_failed, Reason} ->
<<<<"Failed to begin transaction: "/utf8, Reason/binary>>/binary,
"\n\nHint: Check database connection and permissions."/utf8>>;
{commit_failed, Reason@1} ->
<<<<"Failed to commit transaction: "/utf8, Reason@1/binary>>/binary,
"\n\nHint: The transaction may have been rolled back. Check for constraint violations or connection issues."/utf8>>;
rolled_back ->
<<"Transaction was rolled back\n\nHint: An explicit rollback was requested during the transaction."/utf8>>;
{transaction_rollback, Reason@2} ->
<<<<"Transaction rolled back: "/utf8, Reason@2/binary>>/binary,
"\n\nHint: The transaction was explicitly rolled back with the reason above."/utf8>>;
transaction_connection_lost ->
<<"Connection lost during transaction\n\nHint: The database connection was interrupted. The transaction state is unknown - verify data integrity."/utf8>>;
nested_transaction_error ->
<<"Nested transactions are not supported\n\nHint: Use savepoints for partial rollback within a transaction instead."/utf8>>;
transaction_timeout ->
<<"Transaction timed out\n\nHint: Consider breaking up long transactions or increasing the timeout limit."/utf8>>;
serialization_failure ->
<<"Serialization failure: concurrent transaction conflict\n\nHint: This operation can be safely retried. Another transaction modified the same data."/utf8>>
end.
-file("src/cquill/error.gleam", 467).
?DOC(" Format a transaction error without hints (compact format).\n").
-spec format_transaction_error_compact(transaction_error(any())) -> binary().
format_transaction_error_compact(Error) ->
case Error of
{user_error, _} ->
<<"Transaction aborted: user error"/utf8>>;
{adapter_transaction_error, Adapter_err} ->
<<"Transaction aborted: "/utf8,
(format_error_compact(Adapter_err))/binary>>;
{begin_failed, Reason} ->
<<"Failed to begin transaction: "/utf8, Reason/binary>>;
{commit_failed, Reason@1} ->
<<"Failed to commit transaction: "/utf8, Reason@1/binary>>;
rolled_back ->
<<"Transaction was rolled back"/utf8>>;
{transaction_rollback, Reason@2} ->
<<"Transaction rolled back: "/utf8, Reason@2/binary>>;
transaction_connection_lost ->
<<"Connection lost during transaction"/utf8>>;
nested_transaction_error ->
<<"Nested transactions are not supported"/utf8>>;
transaction_timeout ->
<<"Transaction timed out"/utf8>>;
serialization_failure ->
<<"Serialization failure: concurrent transaction conflict"/utf8>>
end.
-file("src/cquill/error.gleam", 485).
?DOC(" Format a savepoint error for display with actionable hints.\n").
-spec format_savepoint_error(savepoint_error(any())) -> binary().
format_savepoint_error(Error) ->
case Error of
{savepoint_not_found, Name} ->
<<<<"Savepoint not found: '"/utf8, Name/binary>>/binary,
"'\n\nHint: Verify the savepoint name and that it was created in the current transaction."/utf8>>;
{savepoint_adapter_error, Adapter_err} ->
<<"Savepoint operation failed: "/utf8,
(format_error_compact(Adapter_err))/binary>>;
{savepoint_user_error, _} ->
<<"Savepoint aborted: user error\n\nHint: The savepoint callback returned an error. The savepoint has been rolled back."/utf8>>;
{savepoint_creation_failed, Reason} ->
<<<<"Failed to create savepoint: "/utf8, Reason/binary>>/binary,
"\n\nHint: Check that you are within an active transaction."/utf8>>;
{savepoint_release_failed, Reason@1} ->
<<<<"Failed to release savepoint: "/utf8, Reason@1/binary>>/binary,
"\n\nHint: The savepoint may have already been released or rolled back."/utf8>>;
savepoint_no_transaction ->
<<"Cannot use savepoint outside of a transaction\n\nHint: Savepoints must be created within an active transaction. Use repo.transaction first."/utf8>>
end.
-file("src/cquill/error.gleam", 514).
?DOC(" Format a savepoint error without hints (compact format).\n").
-spec format_savepoint_error_compact(savepoint_error(any())) -> binary().
format_savepoint_error_compact(Error) ->
case Error of
{savepoint_not_found, Name} ->
<<"Savepoint not found: "/utf8, Name/binary>>;
{savepoint_adapter_error, Adapter_err} ->
<<"Savepoint operation failed: "/utf8,
(format_error_compact(Adapter_err))/binary>>;
{savepoint_user_error, _} ->
<<"Savepoint aborted: user error"/utf8>>;
{savepoint_creation_failed, Reason} ->
<<"Failed to create savepoint: "/utf8, Reason/binary>>;
{savepoint_release_failed, Reason@1} ->
<<"Failed to release savepoint: "/utf8, Reason@1/binary>>;
savepoint_no_transaction ->
<<"Cannot use savepoint outside of a transaction"/utf8>>
end.
-file("src/cquill/error.gleam", 694).
?DOC(" Extract constraint name from error detail/message\n").
-spec extract_constraint_name(binary()) -> binary().
extract_constraint_name(Text) ->
case gleam@string:split(Text, <<"constraint \""/utf8>>) of
[_, Rest] ->
case gleam@string:split(Rest, <<"\""/utf8>>) of
[Name | _] ->
Name;
_ ->
<<"unknown"/utf8>>
end;
_ ->
case gleam@string:split(Text, <<"for key '"/utf8>>) of
[_, Rest@1] ->
case gleam@string:split(Rest@1, <<"'"/utf8>>) of
[Name@1 | _] ->
Name@1;
_ ->
<<"unknown"/utf8>>
end;
_ ->
<<"unknown"/utf8>>
end
end.
-file("src/cquill/error.gleam", 718).
?DOC(" Extract column name from error message\n").
-spec extract_column_name(binary()) -> binary().
extract_column_name(Text) ->
case gleam@string:split(Text, <<"column \""/utf8>>) of
[_, Rest] ->
case gleam@string:split(Rest, <<"\""/utf8>>) of
[Name | _] ->
Name;
_ ->
<<"unknown"/utf8>>
end;
_ ->
case gleam@string:split(Text, <<"Field '"/utf8>>) of
[_, Rest@1] ->
case gleam@string:split(Rest@1, <<"'"/utf8>>) of
[Name@1 | _] ->
Name@1;
_ ->
<<"unknown"/utf8>>
end;
_ ->
<<"unknown"/utf8>>
end
end.
-file("src/cquill/error.gleam", 548).
?DOC(
" Map a PostgreSQL error code to an AdapterError.\n"
"\n"
" PostgreSQL error codes are 5-character strings where the first two\n"
" characters indicate the error class. See:\n"
" https://www.postgresql.org/docs/current/errcodes-appendix.html\n"
"\n"
" Common codes:\n"
" - 23505: unique_violation\n"
" - 23503: foreign_key_violation\n"
" - 23514: check_violation\n"
" - 23502: not_null_violation\n"
" - 23000: integrity_constraint_violation\n"
" - 08000: connection_exception\n"
" - 08003: connection_does_not_exist\n"
" - 08006: connection_failure\n"
" - 57P01: admin_shutdown\n"
" - 42P01: undefined_table\n"
" - 42703: undefined_column\n"
).
-spec from_postgres_error(binary(), binary(), binary()) -> adapter_error().
from_postgres_error(Code, Message, Detail) ->
case Code of
<<"23505"/utf8>> ->
{unique_violation, extract_constraint_name(Detail), Detail};
<<"23503"/utf8>> ->
{foreign_key_violation, extract_constraint_name(Detail), Detail};
<<"23514"/utf8>> ->
{check_violation, extract_constraint_name(Detail), Detail};
<<"23502"/utf8>> ->
{not_null_violation, extract_column_name(Message)};
<<"23000"/utf8>> ->
{constraint_violation, extract_constraint_name(Detail), Detail};
<<"08000"/utf8>> ->
{connection_failed, Message};
<<"08003"/utf8>> ->
{connection_lost, <<"Connection does not exist"/utf8>>};
<<"08006"/utf8>> ->
{connection_failed, <<"Connection failure: "/utf8, Message/binary>>};
<<"57P01"/utf8>> ->
{connection_lost, <<"Server shutdown"/utf8>>};
<<"57P02"/utf8>> ->
{connection_lost, <<"Crash shutdown"/utf8>>};
<<"57P03"/utf8>> ->
{connection_failed, <<"Cannot connect now"/utf8>>};
<<"3D000"/utf8>> ->
{query_failed, Message, {some, Code}};
<<"3F000"/utf8>> ->
{query_failed, Message, {some, Code}};
<<"42P01"/utf8>> ->
{query_failed,
<<"Undefined table: "/utf8, Message/binary>>,
{some, Code}};
<<"42703"/utf8>> ->
{query_failed,
<<"Undefined column: "/utf8, Message/binary>>,
{some, Code}};
<<"42601"/utf8>> ->
{query_failed,
<<"Syntax error: "/utf8, Message/binary>>,
{some, Code}};
<<"42501"/utf8>> ->
{query_failed,
<<"Insufficient privilege: "/utf8, Message/binary>>,
{some, Code}};
<<"57014"/utf8>> ->
timeout;
<<"53300"/utf8>> ->
pool_exhausted;
<<"53400"/utf8>> ->
{query_failed,
<<"Configuration limit exceeded: "/utf8, Message/binary>>,
{some, Code}};
_ ->
{adapter_specific, Code, Message}
end.
-file("src/cquill/error.gleam", 607).
?DOC(
" Map a MySQL error code to an AdapterError.\n"
"\n"
" Common MySQL error codes:\n"
" - 1062: Duplicate entry (unique violation)\n"
" - 1452: Foreign key constraint fails\n"
" - 1364: No default value (not null violation)\n"
" - 1048: Column cannot be null\n"
" - 2002: Connection refused\n"
" - 2003: Can't connect to server\n"
" - 2006: Server has gone away\n"
" - 2013: Lost connection during query\n"
).
-spec from_mysql_error(integer(), binary()) -> adapter_error().
from_mysql_error(Code, Message) ->
case Code of
1062 ->
{unique_violation, extract_constraint_name(Message), Message};
1452 ->
{foreign_key_violation, extract_constraint_name(Message), Message};
1364 ->
{not_null_violation, extract_column_name(Message)};
1048 ->
{not_null_violation, extract_column_name(Message)};
3819 ->
{check_violation, extract_constraint_name(Message), Message};
2002 ->
{connection_failed, <<"Connection refused"/utf8>>};
2003 ->
{connection_failed, <<"Can't connect to server"/utf8>>};
2006 ->
{connection_lost, <<"Server has gone away"/utf8>>};
2013 ->
{connection_lost, <<"Lost connection during query"/utf8>>};
1064 ->
{query_failed,
<<"Syntax error: "/utf8, Message/binary>>,
{some, erlang:integer_to_binary(Code)}};
1146 ->
{query_failed,
<<"Table doesn't exist: "/utf8, Message/binary>>,
{some, erlang:integer_to_binary(Code)}};
1054 ->
{query_failed,
<<"Unknown column: "/utf8, Message/binary>>,
{some, erlang:integer_to_binary(Code)}};
_ ->
{adapter_specific, erlang:integer_to_binary(Code), Message}
end.
-file("src/cquill/error.gleam", 669).
?DOC(
" Classify a SQLite constraint violation based on the error message.\n"
"\n"
" SQLite's SQLITE_CONSTRAINT error (code 19) requires parsing the error\n"
" message to determine the specific constraint type. This function uses\n"
" a declarative approach with a list of patterns for better readability.\n"
).
-spec classify_sqlite_constraint(binary()) -> adapter_error().
classify_sqlite_constraint(Message) ->
Lower_message = string:lowercase(Message),
Constraint_patterns = [{<<"unique"/utf8>>,
fun(Msg) ->
{unique_violation, extract_constraint_name(Msg), Msg}
end},
{<<"foreign key"/utf8>>,
fun(Msg@1) ->
{foreign_key_violation, extract_constraint_name(Msg@1), Msg@1}
end},
{<<"not null"/utf8>>,
fun(Msg@2) -> {not_null_violation, extract_column_name(Msg@2)} end},
{<<"check"/utf8>>,
fun(Msg@3) ->
{check_violation, extract_constraint_name(Msg@3), Msg@3}
end}],
_pipe = Constraint_patterns,
_pipe@1 = gleam@list:find(
_pipe,
fun(Pattern) ->
gleam_stdlib:contains_string(
Lower_message,
erlang:element(1, Pattern)
)
end
),
_pipe@2 = gleam@result:map(
_pipe@1,
fun(Pattern@1) -> (erlang:element(2, Pattern@1))(Message) end
),
gleam@result:unwrap(
_pipe@2,
{constraint_violation, <<"unknown"/utf8>>, Message}
).
-file("src/cquill/error.gleam", 638).
?DOC(
" Map a SQLite error code to an AdapterError.\n"
"\n"
" SQLite uses integer result codes. Extended result codes provide more detail.\n"
" See: https://www.sqlite.org/rescode.html\n"
).
-spec from_sqlite_error(integer(), binary()) -> adapter_error().
from_sqlite_error(Code, Message) ->
case Code of
19 ->
classify_sqlite_constraint(Message);
5 ->
{connection_failed, <<"Database is locked"/utf8>>};
6 ->
{connection_failed, <<"Table is locked"/utf8>>};
26 ->
{connection_failed, <<"Not a database file"/utf8>>};
1 ->
{query_failed, Message, {some, erlang:integer_to_binary(Code)}};
_ ->
{adapter_specific, erlang:integer_to_binary(Code), Message}
end.
-file("src/cquill/error.gleam", 745).
?DOC(" Create a NotFound error\n").
-spec not_found() -> adapter_error().
not_found() ->
not_found.
-file("src/cquill/error.gleam", 750).
?DOC(" Create a QueryFailed error\n").
-spec query_failed(binary()) -> adapter_error().
query_failed(Message) ->
{query_failed, Message, none}.
-file("src/cquill/error.gleam", 755).
?DOC(" Create a QueryFailed error with code\n").
-spec query_failed_with_code(binary(), binary()) -> adapter_error().
query_failed_with_code(Message, Code) ->
{query_failed, Message, {some, Code}}.
-file("src/cquill/error.gleam", 760).
?DOC(" Create a ConnectionFailed error\n").
-spec connection_failed(binary()) -> adapter_error().
connection_failed(Reason) ->
{connection_failed, Reason}.
-file("src/cquill/error.gleam", 765).
?DOC(" Create a Timeout error\n").
-spec timeout() -> adapter_error().
timeout() ->
timeout.
-file("src/cquill/error.gleam", 770).
?DOC(" Create a UniqueViolation error\n").
-spec unique_violation(binary(), binary()) -> adapter_error().
unique_violation(Constraint, Detail) ->
{unique_violation, Constraint, Detail}.
-file("src/cquill/error.gleam", 775).
?DOC(" Create a NotSupported error\n").
-spec not_supported(binary()) -> adapter_error().
not_supported(Operation) ->
{not_supported, Operation}.
-file("src/cquill/error.gleam", 780).
?DOC(" Create an AdapterSpecific error\n").
-spec adapter_specific(binary(), binary()) -> adapter_error().
adapter_specific(Code, Message) ->
{adapter_specific, Code, Message}.