-module(cquill@error@format). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/cquill/error/format.gleam"). -export([empty_context/0, with_query/2, with_params/2, with_source_location/4, with_table/2, with_operation/2, format_value/1, format_unique_violation/4, format_foreign_key_violation/5, format_decode_error/4, format_connection_failed/2, format_connection_failed_simple/1, format_connection_timeout/1, format_pool_exhausted/0, format_connection_lost/1, format_foreign_key_violation_error/3, format_check_violation/3, format_not_null_violation/2, format_not_found/1, format_too_many_rows/3, format_rich_transaction_error/2, format_rich_savepoint_error/2, format_query_failed/3, format_timeout/1, format_unique_violation_error/3, format_rich_error/2]). -export_type([error_context/0, source_location/0, connection_config/0]). -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 error_context() :: {error_context, gleam@option:option(binary()), gleam@option:option(list(cquill@query@ast:value())), gleam@option:option(source_location()), gleam@option:option(binary()), gleam@option:option(binary())}. -type source_location() :: {source_location, binary(), integer(), binary()}. -type connection_config() :: {connection_config, binary(), integer(), binary(), binary()}. -file("src/cquill/error/format.gleam", 68). ?DOC(" Create an empty error context\n"). -spec empty_context() -> error_context(). empty_context() -> {error_context, none, none, none, none, none}. -file("src/cquill/error/format.gleam", 79). ?DOC(" Create a context with query information\n"). -spec with_query(error_context(), binary()) -> error_context(). with_query(Context, Query) -> {error_context, {some, Query}, erlang:element(3, Context), erlang:element(4, Context), erlang:element(5, Context), erlang:element(6, Context)}. -file("src/cquill/error/format.gleam", 84). ?DOC(" Create a context with query parameters\n"). -spec with_params(error_context(), list(cquill@query@ast:value())) -> error_context(). with_params(Context, Params) -> {error_context, erlang:element(2, Context), {some, Params}, erlang:element(4, Context), erlang:element(5, Context), erlang:element(6, Context)}. -file("src/cquill/error/format.gleam", 89). ?DOC(" Create a context with source location\n"). -spec with_source_location(error_context(), binary(), integer(), binary()) -> error_context(). with_source_location(Context, File, Line, Function) -> {error_context, erlang:element(2, Context), erlang:element(3, Context), {some, {source_location, File, Line, Function}}, erlang:element(5, Context), erlang:element(6, Context)}. -file("src/cquill/error/format.gleam", 102). ?DOC(" Create a context with table name\n"). -spec with_table(error_context(), binary()) -> error_context(). with_table(Context, Table) -> {error_context, erlang:element(2, Context), erlang:element(3, Context), erlang:element(4, Context), {some, Table}, erlang:element(6, Context)}. -file("src/cquill/error/format.gleam", 107). ?DOC(" Create a context with operation name\n"). -spec with_operation(error_context(), binary()) -> error_context(). with_operation(Context, Operation) -> {error_context, erlang:element(2, Context), erlang:element(3, Context), erlang:element(4, Context), erlang:element(5, Context), {some, Operation}}. -file("src/cquill/error/format.gleam", 131). ?DOC(" Format a float value for display\n"). -spec format_float(float()) -> binary(). format_float(F) -> gleam@string:inspect(F). -file("src/cquill/error/format.gleam", 137). ?DOC(" Mask potentially sensitive values (emails, etc.)\n"). -spec mask_sensitive_value(binary()) -> binary(). mask_sensitive_value(Value) -> Length = string:length(Value), case Length of L when L =< 3 -> Value; L@1 when L@1 =< 8 -> Visible = gleam@string:slice(Value, 0, 2), <>, L@1 - 2))/binary>>; _ -> Visible_start = gleam@string:slice(Value, 0, 3), Visible_end = gleam@string:slice(Value, Length - 2, 2), <<<>/binary, Visible_end/binary>> end. -file("src/cquill/error/format.gleam", 116). ?DOC(" Format a Value for display in error messages\n"). -spec format_value(cquill@query@ast:value()) -> binary(). format_value(Value) -> case Value of {int_value, I} -> erlang:integer_to_binary(I); {float_value, F} -> format_float(F); {string_value, S} -> <<<<"\""/utf8, (mask_sensitive_value(S))/binary>>/binary, "\""/utf8>>; {bool_value, true} -> <<"true"/utf8>>; {bool_value, false} -> <<"false"/utf8>>; null_value -> <<"NULL"/utf8>>; {param_value, Pos} -> <<"$"/utf8, (erlang:integer_to_binary(Pos))/binary>>; {list_value, Values} -> <<<<"["/utf8, (gleam@string:join( gleam@list:map(Values, fun format_value/1), <<", "/utf8>> ))/binary>>/binary, "]"/utf8>> end. -file("src/cquill/error/format.gleam", 158). ?DOC(" Format a unique constraint violation with rich context\n"). -spec format_unique_violation( binary(), binary(), binary(), cquill@query@ast:value() ) -> binary(). format_unique_violation(Constraint, Table, Column, Value) -> Value_str = format_value(Value), Column_underline = gleam@string:repeat(<<"^"/utf8>>, string:length(Column)), gleam@string:join( [<<"Error: UniqueConstraintViolation"/utf8>>, <<""/utf8>>, <<<<<<<<<<<<" INSERT INTO "/utf8, Table/binary>>/binary, " ("/utf8>>/binary, Column/binary>>/binary, ", ...) VALUES ("/utf8>>/binary, Value_str/binary>>/binary, ", ...)"/utf8>>, <<" "/utf8, Column_underline/binary>>, <<""/utf8>>, <<<<" Unique constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<<<<<<<" A record with "/utf8, Column/binary>>/binary, " = "/utf8>>/binary, Value_str/binary>>/binary, " already exists."/utf8>>, <<""/utf8>>, <<" Hint: Use `on_conflict_do_nothing()` to ignore duplicates,"/utf8>>, <<" or check existence first with `repo.exists(...)`."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 230). ?DOC(" Format a foreign key constraint violation with rich context\n"). -spec format_foreign_key_violation( binary(), binary(), binary(), binary(), binary() ) -> binary(). format_foreign_key_violation( Constraint, Table, Column, References_table, References_column ) -> gleam@string:join( [<<"Error: ForeignKeyViolation"/utf8>>, <<""/utf8>>, <<<<" Foreign key constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<<<<<<<<<<<<<<<" The value in "/utf8, Table/binary>>/binary, "."/utf8>>/binary, Column/binary>>/binary, " does not exist in "/utf8>>/binary, References_table/binary>>/binary, "."/utf8>>/binary, References_column/binary>>/binary, "."/utf8>>, <<""/utf8>>, <<" Hint: Ensure the referenced record exists before inserting,"/utf8>>, <<" or use ON DELETE SET NULL if the reference is optional."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 352). ?DOC(" Format a decode error with detailed context\n"). -spec format_decode_error(integer(), binary(), binary(), binary()) -> binary(). format_decode_error(Row, Column, Expected, Found) -> gleam@string:join( [<<"Error: DecodeError"/utf8>>, <<""/utf8>>, <<<<<<<<" Failed to decode row "/utf8, (erlang:integer_to_binary(Row))/binary>>/binary, ", column \""/utf8>>/binary, Column/binary>>/binary, "\"."/utf8>>, <<""/utf8>>, <<" Expected: "/utf8, Expected/binary>>, <<" Found: "/utf8, Found/binary>>, <<""/utf8>>, <<" Hint: Check that your decoder matches the database column type."/utf8>>, <<" The schema might be out of sync — verify column types match."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 478). ?DOC(" Format a connection failed error with troubleshooting hints\n"). -spec format_connection_failed(binary(), connection_config()) -> binary(). format_connection_failed(Reason, Config) -> Host_str = <<<<(erlang:element(2, Config))/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(erlang:element(3, Config)))/binary>>, gleam@string:join( [<<"Error: ConnectionFailed"/utf8>>, <<""/utf8>>, <<" Could not connect to database at "/utf8, Host_str/binary>>, <<""/utf8>>, <<" Reason: "/utf8, Reason/binary>>, <<""/utf8>>, <<" Check:"/utf8>>, <<" - Is the database server running?"/utf8>>, <<<<" - Is the database \""/utf8, (erlang:element(4, Config))/binary>>/binary, "\" created?"/utf8>>, <<<<" - Are the credentials for user \""/utf8, (erlang:element(5, Config))/binary>>/binary, "\" correct?"/utf8>>, <<<<" - Is port "/utf8, (erlang:integer_to_binary(erlang:element(3, Config)))/binary>>/binary, " accessible (firewall/network)?"/utf8>>, <<" - Is the connection string/host correct?"/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 507). ?DOC(" Format a connection failed error with minimal context\n"). -spec format_connection_failed_simple(binary()) -> binary(). format_connection_failed_simple(Reason) -> gleam@string:join( [<<"Error: ConnectionFailed"/utf8>>, <<""/utf8>>, <<" Could not establish database connection."/utf8>>, <<""/utf8>>, <<" Reason: "/utf8, Reason/binary>>, <<""/utf8>>, <<" Check:"/utf8>>, <<" - Is the database server running?"/utf8>>, <<" - Is the database created?"/utf8>>, <<" - Are the credentials correct?"/utf8>>, <<" - Is the host and port accessible?"/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 528). ?DOC(" Format a connection timeout error\n"). -spec format_connection_timeout(gleam@option:option(connection_config())) -> binary(). format_connection_timeout(Config) -> Host_info = case Config of {some, C} -> <<<<<<" to "/utf8, (erlang:element(2, C))/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(erlang:element(3, C)))/binary>>; none -> <<""/utf8>> end, gleam@string:join( [<<"Error: ConnectionTimeout"/utf8>>, <<""/utf8>>, <<<<" Connection attempt"/utf8, Host_info/binary>>/binary, " timed out."/utf8>>, <<""/utf8>>, <<" Possible causes:"/utf8>>, <<" - Database server is not responding"/utf8>>, <<" - Network connectivity issues"/utf8>>, <<" - Firewall blocking the connection"/utf8>>, <<" - Server is overloaded"/utf8>>, <<""/utf8>>, <<" Hint: Check network connectivity and server status."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 554). ?DOC(" Format a pool exhausted error\n"). -spec format_pool_exhausted() -> binary(). format_pool_exhausted() -> gleam@string:join( [<<"Error: PoolExhausted"/utf8>>, <<""/utf8>>, <<" All database connections in the pool are in use."/utf8>>, <<""/utf8>>, <<" Possible causes:"/utf8>>, <<" - Too many concurrent requests"/utf8>>, <<" - Long-running queries holding connections"/utf8>>, <<" - Connection leaks (connections not being returned)"/utf8>>, <<""/utf8>>, <<" Hint: Increase pool size, optimize slow queries,"/utf8>>, <<" or check for connection leaks in your application."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 575). ?DOC(" Format a connection lost error\n"). -spec format_connection_lost(binary()) -> binary(). format_connection_lost(Reason) -> gleam@string:join( [<<"Error: ConnectionLost"/utf8>>, <<""/utf8>>, <<" The database connection was lost during the operation."/utf8>>, <<""/utf8>>, <<" Reason: "/utf8, Reason/binary>>, <<""/utf8>>, <<" Possible causes:"/utf8>>, <<" - Database server was restarted"/utf8>>, <<" - Network interruption"/utf8>>, <<" - Server terminated the connection (idle timeout)"/utf8>>, <<""/utf8>>, <<" Hint: This error is often transient — retry the operation."/utf8>>, <<" If persistent, check database server logs."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 975). ?DOC(" Format a not supported error\n"). -spec format_not_supported(binary()) -> binary(). format_not_supported(Operation) -> gleam@string:join( [<<"Error: NotSupported"/utf8>>, <<""/utf8>>, <<<<" Operation \""/utf8, Operation/binary>>/binary, "\" is not supported by this adapter."/utf8>>, <<""/utf8>>, <<" Hint: Check the adapter documentation for supported operations,"/utf8>>, <<" or use a different adapter that supports this feature."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 1015). ?DOC(" Format the operation line from context\n"). -spec format_operation_line(error_context()) -> binary(). format_operation_line(Context) -> case {erlang:element(6, Context), erlang:element(5, Context)} of {{some, Op}, {some, Table}} -> <<<<<<" During: "/utf8, Op/binary>>/binary, " on "/utf8>>/binary, Table/binary>>; {{some, Op@1}, none} -> <<" During: "/utf8, Op@1/binary>>; {none, {some, Table@1}} -> <<" Table: "/utf8, Table@1/binary>>; {none, none} -> <<""/utf8>> end. -file("src/cquill/error/format.gleam", 1042). ?DOC(" Format source location if available\n"). -spec format_source_location(gleam@option:option(source_location())) -> binary(). format_source_location(Location) -> case Location of {some, Loc} -> <<<<<<<<<<<<" at "/utf8, (erlang:element(2, Loc))/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(erlang:element(3, Loc)))/binary>>/binary, " in "/utf8>>/binary, (erlang:element(4, Loc))/binary>>/binary, "()"/utf8>>; none -> <<""/utf8>> end. -file("src/cquill/error/format.gleam", 262). ?DOC(" Format a foreign key violation from an AdapterError\n"). -spec format_foreign_key_violation_error(binary(), binary(), error_context()) -> binary(). format_foreign_key_violation_error(Constraint, Detail, Context) -> Table = gleam@option:unwrap(erlang:element(5, Context), <<"table"/utf8>>), gleam@string:join( [<<"Error: ForeignKeyViolation"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<" Foreign key constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<" Detail: "/utf8, Detail/binary>>, <<""/utf8>>, <<" The referenced record in the parent table does not exist."/utf8>>, <<""/utf8>>, <<<<" Hint: Ensure the referenced record exists before inserting into "/utf8, Table/binary>>/binary, ","/utf8>>, <<" or verify the foreign key value is correct."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 293). ?DOC(" Format a check constraint violation\n"). -spec format_check_violation(binary(), binary(), error_context()) -> binary(). format_check_violation(Constraint, Detail, Context) -> gleam@string:join( [<<"Error: CheckConstraintViolation"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<" Check constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<" Detail: "/utf8, Detail/binary>>, <<""/utf8>>, <<" The value did not satisfy the check constraint condition."/utf8>>, <<""/utf8>>, <<" Hint: Review the constraint definition and ensure"/utf8>>, <<" the data meets all validation requirements."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 320). ?DOC(" Format a NOT NULL constraint violation\n"). -spec format_not_null_violation(binary(), error_context()) -> binary(). format_not_null_violation(Column, Context) -> Table = gleam@option:unwrap(erlang:element(5, Context), <<"table"/utf8>>), gleam@string:join( [<<"Error: NotNullViolation"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<<<<<" Column \""/utf8, Column/binary>>/binary, "\" in table \""/utf8>>/binary, Table/binary>>/binary, "\" cannot be NULL."/utf8>>, <<""/utf8>>, <<<<" Hint: Provide a value for the \""/utf8, Column/binary>>/binary, "\" column,"/utf8>>, <<" or alter the column to allow NULL values."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 407). ?DOC(" Format a \"not found\" error\n"). -spec format_not_found(error_context()) -> binary(). format_not_found(Context) -> Table = gleam@option:unwrap( erlang:element(5, Context), <<"the table"/utf8>> ), gleam@string:join( [<<"Error: RecordNotFound"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<" No record was found in "/utf8, Table/binary>>/binary, " matching the query."/utf8>>, <<""/utf8>>, <<" Hint: Verify the query conditions are correct,"/utf8>>, <<" or use `repo.one_or_none(...)` if the record may not exist."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 428). ?DOC(" Format a \"too many rows\" error\n"). -spec format_too_many_rows(integer(), integer(), error_context()) -> binary(). format_too_many_rows(Expected, Got, Context) -> gleam@string:join( [<<"Error: TooManyRows"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<<<<<" Expected "/utf8, (erlang:integer_to_binary(Expected))/binary>>/binary, " row(s), but found "/utf8>>/binary, (erlang:integer_to_binary(Got))/binary>>/binary, "."/utf8>>, <<""/utf8>>, <<" Hint: Add a LIMIT clause or use more specific conditions,"/utf8>>, <<" or use `repo.all(...)` if multiple results are expected."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 602). ?DOC(" Format a transaction error with rich context\n"). -spec format_rich_transaction_error( cquill@error:transaction_error(any()), error_context() ) -> binary(). format_rich_transaction_error(Error, Context) -> case Error of {user_error, _} -> gleam@string:join( [<<"Error: TransactionAborted"/utf8>>, <<""/utf8>>, <<" Transaction was aborted due to a user error."/utf8>>, <<""/utf8>>, <<" The transaction function returned an error and changes"/utf8>>, <<" were rolled back automatically."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ); {adapter_transaction_error, Adapter_err} -> gleam@string:join( [<<"Error: TransactionAdapterError"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<" "/utf8, (cquill@error:format_error(Adapter_err))/binary>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ); {begin_failed, Reason} -> gleam@string:join( [<<"Error: TransactionBeginFailed"/utf8>>, <<""/utf8>>, <<" Failed to begin transaction: "/utf8, Reason/binary>>, <<""/utf8>>, <<" Hint: Check database connectivity and permissions."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); {commit_failed, Reason@1} -> gleam@string:join( [<<"Error: TransactionCommitFailed"/utf8>>, <<""/utf8>>, <<" Failed to commit transaction: "/utf8, Reason@1/binary>>, <<""/utf8>>, <<" Changes may have been rolled back."/utf8>>, <<""/utf8>>, <<" Hint: The transaction may have been invalidated by a constraint"/utf8>>, <<" violation or other error during execution."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); rolled_back -> gleam@string:join( [<<"Error: TransactionRolledBack"/utf8>>, <<""/utf8>>, <<" Transaction was explicitly rolled back."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); {transaction_rollback, Reason@2} -> gleam@string:join( [<<"Error: TransactionRolledBack"/utf8>>, <<""/utf8>>, <<" Transaction was rolled back: "/utf8, Reason@2/binary>>, <<""/utf8>>], <<"\n"/utf8>> ); transaction_connection_lost -> gleam@string:join( [<<"Error: TransactionConnectionLost"/utf8>>, <<""/utf8>>, <<" The database connection was lost during the transaction."/utf8>>, <<""/utf8>>, <<" All changes in this transaction were rolled back."/utf8>>, <<""/utf8>>, <<" Hint: This error is often transient — retry the entire transaction."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); nested_transaction_error -> gleam@string:join( [<<"Error: NestedTransactionError"/utf8>>, <<""/utf8>>, <<" Attempted to start a nested transaction."/utf8>>, <<""/utf8>>, <<" Nested transactions are not supported by this adapter."/utf8>>, <<""/utf8>>, <<" Hint: Use savepoints instead with `repo.savepoint(...)` for"/utf8>>, <<" partial rollback capabilities within a transaction."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); transaction_timeout -> gleam@string:join( [<<"Error: TransactionTimeout"/utf8>>, <<""/utf8>>, <<" The transaction timed out."/utf8>>, <<""/utf8>>, <<" Possible causes:"/utf8>>, <<" - Long-running queries within the transaction"/utf8>>, <<" - Deadlock with another transaction"/utf8>>, <<" - Lock contention"/utf8>>, <<""/utf8>>, <<" Hint: Optimize queries, reduce transaction scope,"/utf8>>, <<" or increase the timeout if appropriate."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); serialization_failure -> gleam@string:join( [<<"Error: SerializationFailure"/utf8>>, <<""/utf8>>, <<" Transaction could not serialize access due to concurrent updates."/utf8>>, <<""/utf8>>, <<" Another transaction modified data that this transaction was"/utf8>>, <<" reading or writing."/utf8>>, <<""/utf8>>, <<" Hint: This error indicates a conflict — retry the transaction."/utf8>>, <<" For frequently conflicting operations, consider using"/utf8>>, <<" explicit locking or adjusting the isolation level."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ) end. -file("src/cquill/error/format.gleam", 762). ?DOC(" Format a savepoint error with rich context\n"). -spec format_rich_savepoint_error( cquill@error:savepoint_error(any()), error_context() ) -> binary(). format_rich_savepoint_error(Error, Context) -> case Error of {savepoint_not_found, Name} -> gleam@string:join( [<<"Error: SavepointNotFound"/utf8>>, <<""/utf8>>, <<<<" Savepoint \""/utf8, Name/binary>>/binary, "\" does not exist."/utf8>>, <<""/utf8>>, <<" Hint: Ensure the savepoint was created with `repo.savepoint(...)`"/utf8>>, <<" and has not been released or rolled back."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ); {savepoint_adapter_error, Adapter_err} -> gleam@string:join( [<<"Error: SavepointAdapterError"/utf8>>, <<""/utf8>>, <<" "/utf8, (cquill@error:format_error(Adapter_err))/binary>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ); {savepoint_user_error, _} -> gleam@string:join( [<<"Error: SavepointAborted"/utf8>>, <<""/utf8>>, <<" Savepoint was aborted due to a user error."/utf8>>, <<""/utf8>>, <<" Changes since the savepoint were rolled back."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ); {savepoint_creation_failed, Reason} -> gleam@string:join( [<<"Error: SavepointCreationFailed"/utf8>>, <<""/utf8>>, <<" Failed to create savepoint: "/utf8, Reason/binary>>, <<""/utf8>>, <<" Hint: Ensure you are within an active transaction."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ); {savepoint_release_failed, Reason@1} -> gleam@string:join( [<<"Error: SavepointReleaseFailed"/utf8>>, <<""/utf8>>, <<" Failed to release savepoint: "/utf8, Reason@1/binary>>, <<""/utf8>>], <<"\n"/utf8>> ); savepoint_no_transaction -> gleam@string:join( [<<"Error: SavepointNoTransaction"/utf8>>, <<""/utf8>>, <<" Cannot use savepoint outside of a transaction."/utf8>>, <<""/utf8>>, <<" Savepoints require an active transaction context."/utf8>>, <<""/utf8>>, <<" Hint: Wrap your code in `repo.transaction(...)` first,"/utf8>>, <<" then use `repo.savepoint(...)` within it."/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ) end. -file("src/cquill/error/format.gleam", 906). ?DOC(" Format a generic constraint violation\n"). -spec format_generic_constraint_violation(binary(), binary(), error_context()) -> binary(). format_generic_constraint_violation(Constraint, Detail, Context) -> gleam@string:join( [<<"Error: ConstraintViolation"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<" Constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<" Detail: "/utf8, Detail/binary>>, <<""/utf8>>, <<" Hint: Review the constraint definition and ensure"/utf8>>, <<" the data meets all requirements."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 931). ?DOC(" Format a stale data error\n"). -spec format_stale_data(binary(), binary(), error_context()) -> binary(). format_stale_data(Expected, Actual, Context) -> gleam@string:join( [<<"Error: StaleData"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<" The record was modified by another process."/utf8>>, <<""/utf8>>, <<" Expected version: "/utf8, Expected/binary>>, <<" Actual version: "/utf8, Actual/binary>>, <<""/utf8>>, <<" Hint: Refresh the record and retry the operation,"/utf8>>, <<" or use optimistic locking with retry logic."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 957). ?DOC(" Format a data integrity error\n"). -spec format_data_integrity_error(binary(), error_context()) -> binary(). format_data_integrity_error(Message, Context) -> gleam@string:join( [<<"Error: DataIntegrityError"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<" "/utf8, Message/binary>>, <<""/utf8>>, <<" The database detected an integrity issue."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 991). ?DOC(" Format an adapter-specific error\n"). -spec format_adapter_specific(binary(), binary(), error_context()) -> binary(). format_adapter_specific(Code, Message, Context) -> gleam@string:join( [<<<<"Error: AdapterSpecific ["/utf8, Code/binary>>/binary, "]"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<" "/utf8, Message/binary>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 1082). ?DOC(" Get hint based on error message content\n"). -spec get_hint_from_message(binary()) -> binary(). get_hint_from_message(Lower_message) -> case gleam_stdlib:contains_string(Lower_message, <<"syntax"/utf8>>) of true -> <<" Hint: Check the query syntax for errors."/utf8>>; false -> case gleam_stdlib:contains_string( Lower_message, <<"permission"/utf8>> ) orelse gleam_stdlib:contains_string( Lower_message, <<"privilege"/utf8>> ) of true -> <<" Hint: Check database user permissions."/utf8>>; false -> case gleam_stdlib:contains_string( Lower_message, <<"table"/utf8>> ) of true -> <<" Hint: Verify the table exists and is accessible."/utf8>>; false -> case gleam_stdlib:contains_string( Lower_message, <<"column"/utf8>> ) of true -> <<" Hint: Verify the column name is correct."/utf8>>; false -> <<" Hint: Check the query and parameters for errors."/utf8>> end end end end. -file("src/cquill/error/format.gleam", 1057). ?DOC(" Generate a hint based on the query error message and code\n"). -spec format_query_hint(binary(), gleam@option:option(binary())) -> binary(). format_query_hint(Message, Code) -> Lower_message = string:lowercase(Message), case Code of {some, <<"42P01"/utf8>>} -> <<" Hint: The table does not exist. Check the table name spelling,\n"/utf8, " run migrations, or verify the schema."/utf8>>; {some, <<"42703"/utf8>>} -> <<" Hint: The column does not exist. Check the column name spelling\n"/utf8, " or verify the schema definition."/utf8>>; {some, <<"42601"/utf8>>} -> <<" Hint: There is a syntax error in the query. Check for typos,\n"/utf8, " missing commas, or incorrect SQL syntax."/utf8>>; {some, <<"42501"/utf8>>} -> <<" Hint: Insufficient privileges. Check that the database user\n"/utf8, " has the required permissions for this operation."/utf8>>; _ -> get_hint_from_message(Lower_message) end. -file("src/cquill/error/format.gleam", 1105). ?DOC(" Truncate a long query for display\n"). -spec truncate_query(binary()) -> binary(). truncate_query(Query) -> Max_length = 200, case string:length(Query) > Max_length of true -> <<(gleam@string:slice(Query, 0, Max_length))/binary, "..."/utf8>>; false -> Query end. -file("src/cquill/error/format.gleam", 1025). ?DOC(" Format query context (query + params)\n"). -spec format_query_context(error_context()) -> binary(). format_query_context(Context) -> case erlang:element(2, Context) of {some, Query} -> Params_str = case erlang:element(3, Context) of {some, Params} -> <<<<"\n Params: ["/utf8, (gleam@string:join( gleam@list:map(Params, fun format_value/1), <<", "/utf8>> ))/binary>>/binary, "]"/utf8>>; none -> <<""/utf8>> end, <<<<" Query: "/utf8, (truncate_query(Query))/binary>>/binary, Params_str/binary>>; none -> format_operation_line(Context) end. -file("src/cquill/error/format.gleam", 380). ?DOC(" Format a query failed error with context\n"). -spec format_query_failed( binary(), gleam@option:option(binary()), error_context() ) -> binary(). format_query_failed(Message, Code, Context) -> Code_str = case Code of {some, C} -> <<<<" ["/utf8, C/binary>>/binary, "]"/utf8>>; none -> <<""/utf8>> end, gleam@string:join( [<<"Error: QueryFailed"/utf8, Code_str/binary>>, <<""/utf8>>, format_query_context(Context), <<""/utf8>>, <<" "/utf8, Message/binary>>, <<""/utf8>>, format_query_hint(Message, Code), <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 455). ?DOC(" Format a timeout error\n"). -spec format_timeout(error_context()) -> binary(). format_timeout(Context) -> gleam@string:join( [<<"Error: Timeout"/utf8>>, <<""/utf8>>, format_query_context(Context), <<""/utf8>>, <<" The operation timed out waiting for a response."/utf8>>, <<""/utf8>>, <<" Hint: The query may be too slow — consider adding indexes,"/utf8>>, <<" optimizing the query, or increasing the timeout."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 1114). ?DOC(" Extract column name from unique constraint detail\n"). -spec extract_column_from_unique_detail(binary()) -> binary(). extract_column_from_unique_detail(Detail) -> case gleam@string:split(Detail, <<"("/utf8>>) of [_, Rest | _] -> case gleam@string:split(Rest, <<")"/utf8>>) of [Column | _] -> Column; _ -> <<"column"/utf8>> end; _ -> <<"column"/utf8>> end. -file("src/cquill/error/format.gleam", 1127). ?DOC(" Extract value from unique constraint detail\n"). -spec extract_value_from_unique_detail(binary()) -> binary(). extract_value_from_unique_detail(Detail) -> case gleam@string:split(Detail, <<"=("/utf8>>) of [_, Rest | _] -> case gleam@string:split(Rest, <<")"/utf8>>) of [Value | _] -> mask_sensitive_value(Value); _ -> <<"(value)"/utf8>> end; _ -> <<"(value)"/utf8>> end. -file("src/cquill/error/format.gleam", 193). ?DOC(" Format a unique violation from an AdapterError\n"). -spec format_unique_violation_error(binary(), binary(), error_context()) -> binary(). format_unique_violation_error(Constraint, Detail, Context) -> Table = gleam@option:unwrap(erlang:element(5, Context), <<"table"/utf8>>), Column = extract_column_from_unique_detail(Detail), Value_str = extract_value_from_unique_detail(Detail), gleam@string:join( [<<"Error: UniqueConstraintViolation"/utf8>>, <<""/utf8>>, format_operation_line(Context), <<""/utf8>>, <<<<" Unique constraint \""/utf8, Constraint/binary>>/binary, "\" violated."/utf8>>, <<""/utf8>>, <<" Detail: "/utf8, Detail/binary>>, <<""/utf8>>, <<<<<<<<<<<<" A record with "/utf8, Column/binary>>/binary, " = "/utf8>>/binary, Value_str/binary>>/binary, " already exists in "/utf8>>/binary, Table/binary>>/binary, "."/utf8>>, <<""/utf8>>, <<" Hint: Use `on_conflict_do_nothing()` to ignore duplicates,"/utf8>>, <<" or check existence first with `repo.exists(...)`."/utf8>>, <<""/utf8>>, format_source_location(erlang:element(4, Context))], <<"\n"/utf8>> ). -file("src/cquill/error/format.gleam", 855). ?DOC(" Format any AdapterError with rich context\n"). -spec format_rich_error(cquill@error:adapter_error(), error_context()) -> binary(). format_rich_error(Error, Context) -> case Error of not_found -> format_not_found(Context); {too_many_rows, Expected, Got} -> format_too_many_rows(Expected, Got, Context); {connection_failed, Reason} -> format_connection_failed_simple(Reason); connection_timeout -> format_connection_timeout(none); pool_exhausted -> format_pool_exhausted(); {connection_lost, Reason@1} -> format_connection_lost(Reason@1); {query_failed, Message, Code} -> format_query_failed(Message, Code, Context); {decode_failed, Row, Column, Expected@1, Got@1} -> format_decode_error(Row, Column, Expected@1, Got@1); timeout -> format_timeout(Context); {unique_violation, Constraint, Detail} -> format_unique_violation_error(Constraint, Detail, Context); {foreign_key_violation, Constraint@1, Detail@1} -> format_foreign_key_violation_error(Constraint@1, Detail@1, Context); {check_violation, Constraint@2, Detail@2} -> format_check_violation(Constraint@2, Detail@2, Context); {not_null_violation, Column@1} -> format_not_null_violation(Column@1, Context); {constraint_violation, Constraint@3, Detail@3} -> format_generic_constraint_violation(Constraint@3, Detail@3, Context); {stale_data, Expected@2, Actual} -> format_stale_data(Expected@2, Actual, Context); {data_integrity_error, Message@1} -> format_data_integrity_error(Message@1, Context); {not_supported, Operation} -> format_not_supported(Operation); {adapter_specific, Code@1, Message@2} -> format_adapter_specific(Code@1, Message@2, Context) end.