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@dev.erl
Raw

src/cquill@dev.erl

-module(cquill@dev).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/cquill/dev.gleam").
-export([default_config/0, minimal_config/0, verbose_config/0, is_enabled/0, get_config/0, log_pool_stats/1, update_pool_stats/1, pool_stats/7, enable_with_config/1, enable/0, enable_from_env/0, disable/0, configure/1, stop/0]).
-export_type([dev_config/0, dev_message/0, dev_state/0, pool_stats/0, dev_error/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 dev_config() :: {dev_config,
boolean(),
boolean(),
boolean(),
integer(),
boolean(),
integer(),
list(binary()),
binary(),
boolean()}.
-type dev_message() :: {enable,
dev_config(),
gleam@erlang@process:subject({ok, nil} | {error, dev_error()})} |
{disable, gleam@erlang@process:subject({ok, nil} | {error, dev_error()})} |
{get_config,
gleam@erlang@process:subject(gleam@option:option(dev_config()))} |
{is_enabled, gleam@erlang@process:subject(boolean())} |
{update_config,
dev_config(),
gleam@erlang@process:subject({ok, nil} | {error, dev_error()})} |
{update_pool_stats, pool_stats()}.
-type dev_state() :: {dev_state,
gleam@option:option(dev_config()),
gleam@option:option(pool_stats())}.
-type pool_stats() :: {pool_stats,
binary(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()}.
-type dev_error() :: already_enabled |
not_enabled |
telemetry_required |
dev_mode_not_running.
-file("src/cquill/dev.gleam", 65).
?DOC(" Create a default configuration\n").
-spec default_config() -> dev_config().
default_config() ->
{dev_config,
true,
true,
true,
100,
false,
10000,
[<<"password"/utf8>>,
<<"token"/utf8>>,
<<"secret"/utf8>>,
<<"key"/utf8>>,
<<"credential"/utf8>>,
<<"api_key"/utf8>>],
<<"[REDACTED]"/utf8>>,
false}.
-file("src/cquill/dev.gleam", 80).
?DOC(" Create a minimal configuration (queries only, no params)\n").
-spec minimal_config() -> dev_config().
minimal_config() ->
{dev_config,
true,
true,
false,
500,
false,
30000,
[],
<<"[REDACTED]"/utf8>>,
false}.
-file("src/cquill/dev.gleam", 95).
?DOC(" Create a verbose configuration (all debugging enabled)\n").
-spec verbose_config() -> dev_config().
verbose_config() ->
{dev_config,
true,
true,
true,
50,
true,
5000,
[<<"password"/utf8>>,
<<"token"/utf8>>,
<<"secret"/utf8>>,
<<"key"/utf8>>,
<<"credential"/utf8>>,
<<"api_key"/utf8>>],
<<"[REDACTED]"/utf8>>,
true}.
-file("src/cquill/dev.gleam", 178).
?DOC(" Start the dev mode server\n").
-spec start_server() -> {ok, gleam@erlang@process:subject(dev_message())} |
{error, gleam@otp@actor:start_error()}.
start_server() ->
Initial_state = {dev_state, none, none},
_pipe = gleam@otp@actor:new(Initial_state),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun(State, Msg) -> case Msg of
{enable, Config, Reply_to} ->
case erlang:element(2, State) of
{some, _} ->
gleam@erlang@process:send(
Reply_to,
{error, already_enabled}
),
gleam@otp@actor:continue(State);
none ->
gleam@erlang@process:send(Reply_to, {ok, nil}),
gleam@otp@actor:continue(
{dev_state,
{some, Config},
erlang:element(3, State)}
)
end;
{disable, Reply_to@1} ->
case erlang:element(2, State) of
{some, _} ->
gleam@erlang@process:send(Reply_to@1, {ok, nil}),
gleam@otp@actor:continue({dev_state, none, none});
none ->
gleam@erlang@process:send(
Reply_to@1,
{error, not_enabled}
),
gleam@otp@actor:continue(State)
end;
{get_config, Reply_to@2} ->
gleam@erlang@process:send(
Reply_to@2,
erlang:element(2, State)
),
gleam@otp@actor:continue(State);
{is_enabled, Reply_to@3} ->
gleam@erlang@process:send(
Reply_to@3,
gleam@option:is_some(erlang:element(2, State))
),
gleam@otp@actor:continue(State);
{update_config, Config@1, Reply_to@4} ->
case erlang:element(2, State) of
{some, _} ->
gleam@erlang@process:send(Reply_to@4, {ok, nil}),
gleam@otp@actor:continue(
{dev_state,
{some, Config@1},
erlang:element(3, State)}
);
none ->
gleam@erlang@process:send(
Reply_to@4,
{error, not_enabled}
),
gleam@otp@actor:continue(State)
end;
{update_pool_stats, Stats} ->
gleam@otp@actor:continue(
{dev_state, erlang:element(2, State), {some, Stats}}
)
end end),
_pipe@2 = gleam@otp@actor:start(_pipe@1),
gleam@result:map(_pipe@2, fun(Started) -> erlang:element(3, Started) end).
-file("src/cquill/dev.gleam", 312).
?DOC(" Check if development mode is enabled\n").
-spec is_enabled() -> boolean().
is_enabled() ->
case cquill_dev_ffi:get_dev_server() of
{error, _} ->
false;
{ok, Server} ->
gleam@erlang@process:call(
Server,
5000,
fun(Reply_to) -> {is_enabled, Reply_to} end
)
end.
-file("src/cquill/dev.gleam", 322).
?DOC(" Get the current configuration (if enabled)\n").
-spec get_config() -> gleam@option:option(dev_config()).
get_config() ->
case cquill_dev_ffi:get_dev_server() of
{error, _} ->
none;
{ok, Server} ->
gleam@erlang@process:call(
Server,
5000,
fun(Reply_to) -> {get_config, Reply_to} end
)
end.
-file("src/cquill/dev.gleam", 568).
?DOC(" Pool events handler\n").
-spec dev_pool_handler() -> fun((cquill@telemetry:event(), gleam@dict:dict(binary(), gleam@dynamic:dynamic_())) -> nil).
dev_pool_handler() ->
fun(Event, _) -> case Event of
{pool_checkout, E} ->
Wait_ms = erlang:element(3, E) div 1000,
case Wait_ms > 10 of
true ->
gleam_stdlib:println(
erlang:list_to_binary(
[<<"[cquill] Pool checkout: "/utf8>>,
erlang:element(2, E),
<<" (waited "/utf8>>,
erlang:integer_to_binary(Wait_ms),
<<"ms, queue: "/utf8>>,
erlang:integer_to_binary(
erlang:element(4, E)
),
<<")"/utf8>>]
)
);
false ->
nil
end;
{pool_timeout, E@1} ->
Wait_ms@1 = erlang:element(3, E@1) div 1000,
gleam_stdlib:println_error(
erlang:list_to_binary(
[<<"[cquill] \x{26A0}\x{FE0F} Pool TIMEOUT: "/utf8>>,
erlang:element(2, E@1),
<<" after "/utf8>>,
erlang:integer_to_binary(Wait_ms@1),
<<"ms (queue: "/utf8>>,
erlang:integer_to_binary(erlang:element(4, E@1)),
<<")"/utf8>>]
)
),
gleam_stdlib:println_error(
<<" Hint: Consider increasing pool size"/utf8>>
);
_ ->
nil
end end.
-file("src/cquill/dev.gleam", 612).
?DOC(" Transaction events handler\n").
-spec dev_transaction_handler() -> fun((cquill@telemetry:event(), gleam@dict:dict(binary(), gleam@dynamic:dynamic_())) -> nil).
dev_transaction_handler() ->
fun(Event, _) -> case Event of
{transaction_start, E} ->
gleam_stdlib:println(
<<"[cquill] Transaction started: "/utf8,
(erlang:element(2, E))/binary>>
);
{transaction_commit, E@1} ->
Duration_ms = erlang:element(3, E@1) div 1000,
gleam_stdlib:println(
erlang:list_to_binary(
[<<"[cquill] Transaction committed: "/utf8>>,
erlang:element(2, E@1),
<<" ["/utf8>>,
erlang:integer_to_binary(Duration_ms),
<<"ms, "/utf8>>,
erlang:integer_to_binary(erlang:element(4, E@1)),
<<" queries]"/utf8>>]
)
);
{transaction_rollback, E@2} ->
Duration_ms@1 = erlang:element(3, E@2) div 1000,
Reason_str = case erlang:element(4, E@2) of
{some, R} ->
<<" - "/utf8, R/binary>>;
none ->
<<""/utf8>>
end,
gleam_stdlib:println_error(
erlang:list_to_binary(
[<<"[cquill] Transaction rolled back: "/utf8>>,
erlang:element(2, E@2),
Reason_str,
<<" ["/utf8>>,
erlang:integer_to_binary(Duration_ms@1),
<<"ms]"/utf8>>]
)
);
_ ->
nil
end end.
-file("src/cquill/dev.gleam", 662).
?DOC(" Log current pool statistics\n").
-spec log_pool_stats(pool_stats()) -> nil.
log_pool_stats(Stats) ->
gleam_stdlib:println(<<"[cquill] Pool stats:"/utf8>>),
gleam_stdlib:println(
<<" - Name: "/utf8, (erlang:element(2, Stats))/binary>>
),
gleam_stdlib:println(
<<" - Size: "/utf8,
(erlang:integer_to_binary(erlang:element(3, Stats)))/binary>>
),
gleam_stdlib:println(
<<" - In use: "/utf8,
(erlang:integer_to_binary(erlang:element(4, Stats)))/binary>>
),
gleam_stdlib:println(
<<" - Available: "/utf8,
(erlang:integer_to_binary(erlang:element(5, Stats)))/binary>>
),
gleam_stdlib:println(
<<" - Waiting: "/utf8,
(erlang:integer_to_binary(erlang:element(6, Stats)))/binary>>
),
gleam_stdlib:println(
<<" - Checkouts: "/utf8,
(erlang:integer_to_binary(erlang:element(7, Stats)))/binary>>
),
gleam_stdlib:println(
<<" - Timeouts: "/utf8,
(erlang:integer_to_binary(erlang:element(8, Stats)))/binary>>
).
-file("src/cquill/dev.gleam", 674).
?DOC(" Update pool statistics in dev mode server\n").
-spec update_pool_stats(pool_stats()) -> nil.
update_pool_stats(Stats) ->
case cquill_dev_ffi:get_dev_server() of
{error, _} ->
nil;
{ok, Server} ->
gleam@erlang@process:send(Server, {update_pool_stats, Stats})
end.
-file("src/cquill/dev.gleam", 684).
?DOC(" Create pool stats from values\n").
-spec pool_stats(
binary(),
integer(),
integer(),
integer(),
integer(),
integer(),
integer()
) -> pool_stats().
pool_stats(
Pool_name,
Size,
In_use,
Available,
Waiting,
Total_checkouts,
Total_timeouts
) ->
{pool_stats,
Pool_name,
Size,
In_use,
Available,
Waiting,
Total_checkouts,
Total_timeouts}.
-file("src/cquill/dev.gleam", 753).
?DOC(" Check if a value should be masked based on heuristics\n").
-spec should_mask_value(binary(), list(binary())) -> boolean().
should_mask_value(Value, _) ->
Is_long_string = string:length(Value) > 32,
Looks_like_hash = gleam_stdlib:contains_string(Value, <<"$2"/utf8>>) orelse gleam_stdlib:contains_string(
Value,
<<"sha"/utf8>>
),
Looks_like_token = (gleam_stdlib:contains_string(Value, <<"bearer"/utf8>>)
orelse gleam_stdlib:contains_string(Value, <<"token"/utf8>>))
orelse gleam_stdlib:contains_string(Value, <<"api_key"/utf8>>),
Is_long_string andalso (Looks_like_hash orelse Looks_like_token).
-file("src/cquill/dev.gleam", 767).
?DOC(" Escape special characters in a string for display\n").
-spec escape_string(binary()) -> binary().
escape_string(S) ->
_pipe = S,
_pipe@1 = gleam@string:replace(_pipe, <<"\\"/utf8>>, <<"\\\\"/utf8>>),
_pipe@2 = gleam@string:replace(_pipe@1, <<"\""/utf8>>, <<"\\\""/utf8>>),
_pipe@3 = gleam@string:replace(_pipe@2, <<"\n"/utf8>>, <<"\\n"/utf8>>),
gleam@string:replace(_pipe@3, <<"\t"/utf8>>, <<"\\t"/utf8>>).
-file("src/cquill/dev.gleam", 734).
?DOC(" Format a single value for display\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} ->
gleam@string:inspect(F);
{string_value, S} ->
<<<<"\""/utf8, (escape_string(S))/binary>>/binary, "\""/utf8>>;
{bool_value, B} ->
gleam@bool:to_string(B);
null_value ->
<<"NULL"/utf8>>;
{param_value, P} ->
<<"$"/utf8, (erlang:integer_to_binary(P))/binary>>;
{list_value, Values} ->
Formatted = begin
_pipe = Values,
_pipe@1 = gleam@list:map(_pipe, fun format_value/1),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<"["/utf8, Formatted/binary>>/binary, "]"/utf8>>
end.
-file("src/cquill/dev.gleam", 709).
?DOC(" Format query parameters with sensitive field masking\n").
-spec format_params(list(cquill@query@ast:value()), list(binary()), binary()) -> binary().
format_params(Params, Mask_fields, Mask_pattern) ->
Formatted = begin
_pipe = Params,
_pipe@1 = gleam@list:index_map(
_pipe,
fun(Param, _) ->
Value_str = format_value(Param),
case should_mask_value(Value_str, Mask_fields) of
true ->
Mask_pattern;
false ->
Value_str
end
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
<<<<"["/utf8, Formatted/binary>>/binary, "]"/utf8>>.
-file("src/cquill/dev.gleam", 776).
?DOC(" Analyze a query and provide optimization hints\n").
-spec analyze_query_for_hints(binary(), integer()) -> list(binary()).
analyze_query_for_hints(Query, Row_count) ->
Query_lower = string:lowercase(Query),
Hints = [],
Hints@1 = case gleam_stdlib:contains_string(Query_lower, <<"like '%"/utf8>>) of
true ->
lists:append(
Hints,
[<<"LIKE with leading wildcard '%...' cannot use indexes. Consider full-text search."/utf8>>]
);
false ->
Hints
end,
Hints@2 = case gleam_stdlib:contains_string(
Query_lower,
<<"select *"/utf8>>
) of
true ->
lists:append(
Hints@1,
[<<"SELECT * retrieves all columns. Consider selecting only needed columns."/utf8>>]
);
false ->
Hints@1
end,
Hints@3 = case Row_count > 1000 of
true ->
lists:append(
Hints@2,
[<<<<"Large result set ("/utf8,
(erlang:integer_to_binary(Row_count))/binary>>/binary,
" rows). Consider pagination with LIMIT/OFFSET."/utf8>>]
);
false ->
Hints@2
end,
Has_order_by = gleam_stdlib:contains_string(
Query_lower,
<<"order by"/utf8>>
),
Has_limit = gleam_stdlib:contains_string(Query_lower, <<"limit"/utf8>>),
Hints@4 = case (Has_order_by andalso not Has_limit) andalso (Row_count > 100) of
true ->
lists:append(
Hints@3,
[<<"ORDER BY without LIMIT on large results is expensive. Consider adding an index."/utf8>>]
);
false ->
Hints@3
end,
Has_join = (gleam_stdlib:contains_string(Query_lower, <<" join "/utf8>>)
orelse gleam_stdlib:contains_string(Query_lower, <<"inner join"/utf8>>))
orelse gleam_stdlib:contains_string(Query_lower, <<"left join"/utf8>>),
Has_where = gleam_stdlib:contains_string(Query_lower, <<"where"/utf8>>),
Hints@5 = case Has_join andalso not Has_where of
true ->
lists:append(
Hints@4,
[<<"JOIN without WHERE clause may return unexpected large results."/utf8>>]
);
false ->
Hints@4
end,
Hints@6 = case (gleam_stdlib:contains_string(
Query_lower,
<<"where lower("/utf8>>
)
orelse gleam_stdlib:contains_string(Query_lower, <<"where upper("/utf8>>))
orelse gleam_stdlib:contains_string(Query_lower, <<"where date("/utf8>>) of
true ->
lists:append(
Hints@5,
[<<"Functions in WHERE clause prevent index usage. Consider functional indexes."/utf8>>]
);
false ->
Hints@5
end,
Hints@6.
-file("src/cquill/dev.gleam", 528).
?DOC(" Slow query handler with helpful hints\n").
-spec dev_slow_query_handler(integer()) -> fun((cquill@telemetry:event(), gleam@dict:dict(binary(), gleam@dynamic:dynamic_())) -> nil).
dev_slow_query_handler(Threshold_ms) ->
Threshold_us = Threshold_ms * 1000,
fun(Event, _) -> case Event of
{query_stop, E} ->
case erlang:element(4, E) > Threshold_us of
true ->
Duration_ms = erlang:element(4, E) div 1000,
gleam_stdlib:println_error(
erlang:list_to_binary(
[<<"[cquill] \x{26A0}\x{FE0F} SLOW QUERY ("/utf8>>,
erlang:integer_to_binary(Duration_ms),
<<"ms):"/utf8>>]
)
),
gleam_stdlib:println_error(
<<" "/utf8, (erlang:element(2, E))/binary>>
),
gleam_stdlib:println_error(
<<" rows: "/utf8,
(erlang:integer_to_binary(erlang:element(5, E)))/binary>>
),
Hints = analyze_query_for_hints(
erlang:element(2, E),
erlang:element(5, E)
),
case Hints of
[] ->
nil;
_ ->
gleam_stdlib:println_error(<<""/utf8>>),
gleam_stdlib:println_error(
<<" Hints:"/utf8>>
),
gleam@list:each(
Hints,
fun(Hint) ->
gleam_stdlib:println_error(
<<" - "/utf8,
Hint/binary>>
)
end
)
end;
false ->
nil
end;
_ ->
nil
end end.
-file("src/cquill/dev.gleam", 851).
?DOC(" Format an adapter error for display\n").
-spec format_error(cquill@error:adapter_error()) -> binary().
format_error(Err) ->
case Err of
not_found ->
<<"Record not found"/utf8>>;
{too_many_rows, Expected, Got} ->
<<<<<<"Expected "/utf8,
(erlang:integer_to_binary(Expected))/binary>>/binary,
" row(s), got "/utf8>>/binary,
(erlang:integer_to_binary(Got))/binary>>;
{connection_failed, Reason} ->
<<"Connection failed: "/utf8, Reason/binary>>;
connection_timeout ->
<<"Connection timeout"/utf8>>;
pool_exhausted ->
<<"Connection pool exhausted"/utf8>>;
{connection_lost, Reason@1} ->
<<"Connection lost: "/utf8, Reason@1/binary>>;
{query_failed, Message, Code} ->
<<<<<<"Query failed ["/utf8,
(gleam@option:unwrap(Code, <<"?"/utf8>>))/binary>>/binary,
"]: "/utf8>>/binary,
Message/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>>/binary,
")"/utf8>>;
timeout ->
<<"Query timeout"/utf8>>;
{unique_violation, Constraint, Detail} ->
<<<<<<"Unique 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 violation: "/utf8, Constraint@2/binary>>/binary,
" - "/utf8>>/binary,
Detail@2/binary>>;
{not_null_violation, Column@1} ->
<<"NOT NULL violation: "/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,
", got "/utf8>>/binary,
Actual/binary>>/binary,
")"/utf8>>;
{data_integrity_error, Message@1} ->
<<"Data integrity error: "/utf8, Message@1/binary>>;
{not_supported, Operation} ->
<<"Not supported: "/utf8, Operation/binary>>;
{adapter_specific, Code@1, Message@2} ->
<<<<<<"Adapter error ["/utf8, Code@1/binary>>/binary, "]: "/utf8>>/binary,
Message@2/binary>>
end.
-file("src/cquill/dev.gleam", 467).
?DOC(" Query logging handler with parameter masking\n").
-spec dev_query_handler(dev_config()) -> fun((cquill@telemetry:event(), gleam@dict:dict(binary(), gleam@dynamic:dynamic_())) -> nil).
dev_query_handler(Config) ->
fun(Event, _) -> case Event of
{query_stop, E} ->
Duration_ms = erlang:element(4, E) div 1000,
Params_str = case erlang:element(4, Config) of
true ->
format_params(
erlang:element(3, E),
erlang:element(8, Config),
erlang:element(9, Config)
);
false ->
<<""/utf8>>
end,
gleam_stdlib:println(
erlang:list_to_binary(
[<<"[cquill] "/utf8>>,
erlang:element(2, E),
<<" ["/utf8>>,
erlang:integer_to_binary(Duration_ms),
<<"ms, "/utf8>>,
erlang:integer_to_binary(erlang:element(5, E)),
<<" rows]"/utf8>>]
)
),
case Params_str of
<<""/utf8>> ->
nil;
_ ->
gleam_stdlib:println(
<<" params: "/utf8, Params_str/binary>>
)
end;
{query_exception, E@1} ->
Duration_ms@1 = erlang:element(5, E@1) div 1000,
Params_str@1 = case erlang:element(4, Config) of
true ->
format_params(
erlang:element(3, E@1),
erlang:element(8, Config),
erlang:element(9, Config)
);
false ->
<<""/utf8>>
end,
gleam_stdlib:println_error(
erlang:list_to_binary(
[<<"[cquill] QUERY ERROR: "/utf8>>,
erlang:element(2, E@1),
<<" ["/utf8>>,
erlang:integer_to_binary(Duration_ms@1),
<<"ms]"/utf8>>]
)
),
case Params_str@1 of
<<""/utf8>> ->
nil;
_ ->
gleam_stdlib:println_error(
<<" params: "/utf8, Params_str@1/binary>>
)
end,
gleam_stdlib:println_error(
<<" error: "/utf8,
(format_error(erlang:element(4, E@1)))/binary>>
);
_ ->
nil
end end.
-file("src/cquill/dev.gleam", 391).
?DOC(
" Attach telemetry handlers based on configuration.\n"
" Telemetry attachment is fire-and-forget: failures don't prevent dev mode from working.\n"
" This is intentional since telemetry is observability infrastructure, not core functionality.\n"
).
-spec attach_handlers(dev_config()) -> {ok, nil} | {error, dev_error()}.
attach_handlers(Config) ->
case erlang:element(3, Config) of
true ->
_ = cquill@telemetry:attach(
<<"cquill_dev_query"/utf8>>,
[query_start_type, query_stop_type, query_exception_type],
dev_query_handler(Config)
),
nil;
false ->
nil
end,
_ = cquill@telemetry:attach(
<<"cquill_dev_slow_query"/utf8>>,
[query_stop_type],
dev_slow_query_handler(erlang:element(5, Config))
),
case erlang:element(6, Config) of
true ->
_ = cquill@telemetry:attach(
<<"cquill_dev_pool"/utf8>>,
[pool_checkout_type, pool_checkin_type, pool_timeout_type],
dev_pool_handler()
),
nil;
false ->
nil
end,
_ = cquill@telemetry:attach(
<<"cquill_dev_transaction"/utf8>>,
[transaction_start_type,
transaction_commit_type,
transaction_rollback_type],
dev_transaction_handler()
),
{ok, nil}.
-file("src/cquill/dev.gleam", 252).
?DOC(" Enable development mode with custom configuration\n").
-spec enable_with_config(dev_config()) -> {ok, nil} | {error, dev_error()}.
enable_with_config(Config) ->
case cquill@telemetry:start() of
{ok, _} ->
nil;
{error, _} ->
nil
end,
Server = case cquill_dev_ffi:get_dev_server() of
{ok, S} ->
{ok, S};
{error, _} ->
case start_server() of
{ok, S@1} ->
cquill_dev_ffi:set_dev_server(S@1),
{ok, S@1};
{error, _} ->
{error, dev_mode_not_running}
end
end,
case Server of
{error, E} ->
{error, E};
{ok, S@2} ->
Result = gleam@erlang@process:call(
S@2,
5000,
fun(Reply_to) -> {enable, Config, Reply_to} end
),
case Result of
{ok, _} ->
attach_handlers(Config);
{error, E@1} ->
{error, E@1}
end
end.
-file("src/cquill/dev.gleam", 247).
?DOC(" Enable development mode with default configuration\n").
-spec enable() -> {ok, nil} | {error, dev_error()}.
enable() ->
enable_with_config(default_config()).
-file("src/cquill/dev.gleam", 355).
?DOC(
" Enable dev mode from environment variable\n"
" Call this at application startup to auto-enable if CQUILL_DEV=1\n"
).
-spec enable_from_env() -> {ok, nil} | {error, dev_error()}.
enable_from_env() ->
case cquill_dev_ffi:get_env(<<"CQUILL_DEV"/utf8>>) of
{ok, Value} ->
case Value of
<<"1"/utf8>> ->
enable();
<<"true"/utf8>> ->
enable();
<<"yes"/utf8>> ->
enable();
<<"on"/utf8>> ->
enable();
_ ->
{ok, nil}
end;
{error, _} ->
{ok, nil}
end.
-file("src/cquill/dev.gleam", 454).
?DOC(
" Detach all dev mode handlers.\n"
" Detachment is fire-and-forget cleanup: failures are silently ignored.\n"
" This ensures cleanup always completes, even if some handlers were never attached.\n"
).
-spec detach_handlers() -> nil.
detach_handlers() ->
_ = cquill@telemetry:detach(<<"cquill_dev_query"/utf8>>),
_ = cquill@telemetry:detach(<<"cquill_dev_slow_query"/utf8>>),
_ = cquill@telemetry:detach(<<"cquill_dev_pool"/utf8>>),
_ = cquill@telemetry:detach(<<"cquill_dev_transaction"/utf8>>),
nil.
-file("src/cquill/dev.gleam", 292).
?DOC(" Disable development mode\n").
-spec disable() -> {ok, nil} | {error, dev_error()}.
disable() ->
case cquill_dev_ffi:get_dev_server() of
{error, _} ->
{error, dev_mode_not_running};
{ok, Server} ->
Result = gleam@erlang@process:call(
Server,
5000,
fun(Reply_to) -> {disable, Reply_to} end
),
case Result of
{ok, _} ->
detach_handlers(),
{ok, nil};
{error, E} ->
{error, E}
end
end.
-file("src/cquill/dev.gleam", 332).
?DOC(" Update configuration while dev mode is running\n").
-spec configure(dev_config()) -> {ok, nil} | {error, dev_error()}.
configure(Config) ->
case cquill_dev_ffi:get_dev_server() of
{error, _} ->
{error, dev_mode_not_running};
{ok, Server} ->
Result = gleam@erlang@process:call(
Server,
5000,
fun(Reply_to) -> {update_config, Config, Reply_to} end
),
case Result of
{ok, _} ->
detach_handlers(),
attach_handlers(Config);
{error, E} ->
{error, E}
end
end.
-file("src/cquill/dev.gleam", 368).
?DOC(" Stop the dev mode server completely\n").
-spec stop() -> nil.
stop() ->
_ = disable(),
cquill_dev_ffi:clear_dev_server().