Current section
Files
Jump to
Current section
Files
src/cquill@adapter@memory.erl
-module(cquill@adapter@memory).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/cquill/adapter/memory.gleam").
-export([new_store/0, new/0, reset/1, in_transaction/1, transaction_depth/1, create_table/3, create_table_from_schema/2, add_unique_constraint/4, get_all_rows/2, get_row/3, next_id/2, row_count/2, default_batch_config/0, delete_row/3, delete_all/3, delete_all_rows/2, insert_row/4, update_row/4, insert_all_with_config/4, insert_all/3, update_all/4, update_all_rows/3, insert_all_with_auto_keys/3, memory_capabilities/0, commit_and_continue/1, rollback_and_restore/1, execute_transaction/2, create_savepoint/2, rollback_to_savepoint/2, release_savepoint/2, execute_savepoint/3, has_savepoint/2, savepoint_names/1, memory_adapter/0]).
-export_type([memory_table/0, foreign_key_constraint/0, snapshot/0, memory_store/0, batch_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 memory_table() :: {memory_table,
binary(),
list(binary()),
list(binary()),
gleam@dict:dict(binary(), list(gleam@dynamic:dynamic_())),
integer(),
gleam@dict:dict(binary(), list(integer())),
list(integer()),
list(foreign_key_constraint())}.
-type foreign_key_constraint() :: {foreign_key_constraint,
integer(),
binary(),
binary()}.
-type snapshot() :: {snapshot,
gleam@option:option(binary()),
gleam@dict:dict(binary(), memory_table()),
gleam@dict:dict(binary(), integer())}.
-type memory_store() :: {memory_store,
gleam@dict:dict(binary(), memory_table()),
boolean(),
list(snapshot()),
gleam@option:option(snapshot())}.
-type batch_config() :: {batch_config, integer(), boolean()}.
-file("src/cquill/adapter/memory.gleam", 99).
?DOC(" Create a new empty memory store\n").
-spec new_store() -> memory_store().
new_store() ->
{memory_store, maps:new(), false, [], none}.
-file("src/cquill/adapter/memory.gleam", 109).
?DOC(" Create a new empty memory store (alias for new_store)\n").
-spec new() -> memory_store().
new() ->
new_store().
-file("src/cquill/adapter/memory.gleam", 114).
?DOC(" Reset the store, clearing all data but preserving table structure\n").
-spec reset(memory_store()) -> memory_store().
reset(Store) ->
Empty_tables = gleam@dict:map_values(
erlang:element(2, Store),
fun(_, Table) ->
{memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
maps:new(),
1,
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)}
end
),
{memory_store, Empty_tables, false, [], none}.
-file("src/cquill/adapter/memory.gleam", 128).
?DOC(" Check if the store is currently in a transaction\n").
-spec in_transaction(memory_store()) -> boolean().
in_transaction(Store) ->
erlang:element(3, Store).
-file("src/cquill/adapter/memory.gleam", 133).
?DOC(" Get the current transaction depth (0 = not in transaction)\n").
-spec transaction_depth(memory_store()) -> integer().
transaction_depth(Store) ->
erlang:length(erlang:element(4, Store)).
-file("src/cquill/adapter/memory.gleam", 138).
?DOC(" Create a table in the store (simple version with just primary key)\n").
-spec create_table(memory_store(), binary(), binary()) -> memory_store().
create_table(Store, Name, Primary_key) ->
Table = {memory_table,
Name,
[Primary_key],
[Primary_key],
maps:new(),
1,
maps:new(),
[],
[]},
Tables = gleam@dict:insert(erlang:element(2, Store), Name, Table),
{memory_store,
Tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}.
-file("src/cquill/adapter/memory.gleam", 159).
?DOC(" Create a table from a schema with full constraint support\n").
-spec create_table_from_schema(memory_store(), cquill@schema:schema()) -> memory_store().
create_table_from_schema(Store, Schema) ->
Fields = cquill@schema:get_fields(Schema),
Columns = gleam@list:map(Fields, fun cquill@schema@field:get_name/1),
Primary_key = cquill@schema:get_primary_key(Schema),
Unique_constraints = begin
_pipe = Fields,
_pipe@1 = gleam@list:index_map(_pipe, fun(F, Idx) -> {F, Idx} end),
_pipe@2 = gleam@list:filter_map(
_pipe@1,
fun(Pair) ->
{F@1, Idx@1} = Pair,
case cquill@schema@field:has_constraint(
F@1,
fun cquill@schema@field:is_unique_constraint/1
) of
true ->
{ok,
{<<(cquill@schema@field:get_name(F@1))/binary,
"_unique"/utf8>>,
[Idx@1]}};
false ->
{error, nil}
end
end
),
maps:from_list(_pipe@2)
end,
Pk_indices = gleam@list:filter_map(
Primary_key,
fun(Pk_col) ->
_pipe@3 = gleam@list:index_map(
Columns,
fun(Col, Idx@2) -> {Col, Idx@2} end
),
_pipe@4 = gleam@list:find(
_pipe@3,
fun(Pair@1) -> erlang:element(1, Pair@1) =:= Pk_col end
),
gleam@result:map(
_pipe@4,
fun(Pair@2) -> erlang:element(2, Pair@2) end
)
end
),
Unique_constraints@1 = gleam@dict:insert(
Unique_constraints,
<<(cquill@schema:get_source(Schema))/binary, "_pkey"/utf8>>,
Pk_indices
),
Not_null_columns = begin
_pipe@5 = Fields,
_pipe@6 = gleam@list:index_map(
_pipe@5,
fun(F@2, Idx@3) -> {F@2, Idx@3} end
),
gleam@list:filter_map(
_pipe@6,
fun(Pair@3) ->
{F@3, Idx@4} = Pair@3,
case not cquill@schema@field:is_nullable(F@3) of
true ->
{ok, Idx@4};
false ->
{error, nil}
end
end
)
end,
Foreign_keys = begin
_pipe@7 = Fields,
_pipe@8 = gleam@list:index_map(
_pipe@7,
fun(F@4, Idx@5) -> {F@4, Idx@5} end
),
gleam@list:filter_map(
_pipe@8,
fun(Pair@4) ->
{F@5, Idx@6} = Pair@4,
Fk_constraints = cquill@schema@field:get_constraints(
F@5,
fun cquill@schema@field:is_foreign_key_constraint/1
),
case Fk_constraints of
[{foreign_key, Table, Column, _} | _] ->
{ok, {foreign_key_constraint, Idx@6, Table, Column}};
_ ->
{error, nil}
end
end
)
end,
Table@1 = {memory_table,
cquill@schema:get_source(Schema),
Primary_key,
Columns,
maps:new(),
1,
Unique_constraints@1,
Not_null_columns,
Foreign_keys},
Tables = gleam@dict:insert(
erlang:element(2, Store),
cquill@schema:get_source(Schema),
Table@1
),
{memory_store,
Tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}.
-file("src/cquill/adapter/memory.gleam", 237).
?DOC(" Add a unique constraint to a table\n").
-spec add_unique_constraint(memory_store(), binary(), binary(), list(binary())) -> {ok,
memory_store()} |
{error, cquill@error:adapter_error()}.
add_unique_constraint(Store, Table_name, Constraint_name, Column_names) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
Column_indices = gleam@list:filter_map(
Column_names,
fun(Col_name) ->
_pipe = gleam@list:index_map(
erlang:element(4, Table),
fun(Col, Idx) -> {Col, Idx} end
),
_pipe@1 = gleam@list:find(
_pipe,
fun(Pair) -> erlang:element(1, Pair) =:= Col_name end
),
gleam@result:map(
_pipe@1,
fun(Pair@1) -> erlang:element(2, Pair@1) end
)
end
),
New_constraints = gleam@dict:insert(
erlang:element(7, Table),
Constraint_name,
Column_indices
),
New_table = {memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
erlang:element(5, Table),
erlang:element(6, Table),
New_constraints,
erlang:element(8, Table),
erlang:element(9, Table)},
New_tables = gleam@dict:insert(
erlang:element(2, Store),
Table_name,
New_table
),
{ok,
{memory_store,
New_tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}}
end.
-file("src/cquill/adapter/memory.gleam", 362).
?DOC(" Get all rows from a table\n").
-spec get_all_rows(memory_store(), binary()) -> {ok,
list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
get_all_rows(Store, Table_name) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
{ok, maps:values(erlang:element(5, Table))}
end.
-file("src/cquill/adapter/memory.gleam", 373).
?DOC(" Get a row by primary key\n").
-spec get_row(memory_store(), binary(), binary()) -> {ok,
list(gleam@dynamic:dynamic_())} |
{error, cquill@error:adapter_error()}.
get_row(Store, Table_name, Key) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
case gleam_stdlib:map_get(erlang:element(5, Table), Key) of
{error, _} ->
{error, not_found};
{ok, Row} ->
{ok, Row}
end
end.
-file("src/cquill/adapter/memory.gleam", 417).
?DOC(" Get the next auto-increment ID for a table\n").
-spec next_id(memory_store(), binary()) -> {ok, integer()} |
{error, cquill@error:adapter_error()}.
next_id(Store, Table_name) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
{ok, erlang:element(6, Table)}
end.
-file("src/cquill/adapter/memory.gleam", 428).
?DOC(" Get the row count for a table\n").
-spec row_count(memory_store(), binary()) -> {ok, integer()} |
{error, cquill@error:adapter_error()}.
row_count(Store, Table_name) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
{ok, maps:size(erlang:element(5, Table))}
end.
-file("src/cquill/adapter/memory.gleam", 453).
?DOC(" Default batch configuration\n").
-spec default_batch_config() -> batch_config().
default_batch_config() ->
{batch_config, 1000, true}.
-file("src/cquill/adapter/memory.gleam", 531).
-spec do_has_duplicate_keys(
list(binary()),
gleam@dict:dict(binary(), boolean())
) -> boolean().
do_has_duplicate_keys(Keys, Seen) ->
case Keys of
[] ->
false;
[Key | Rest] ->
case gleam@dict:has_key(Seen, Key) of
true ->
true;
false ->
do_has_duplicate_keys(
Rest,
gleam@dict:insert(Seen, Key, true)
)
end
end.
-file("src/cquill/adapter/memory.gleam", 527).
?DOC(" Check if a list has duplicate keys\n").
-spec has_duplicate_keys(list(binary())) -> boolean().
has_duplicate_keys(Keys) ->
do_has_duplicate_keys(Keys, maps:new()).
-file("src/cquill/adapter/memory.gleam", 932).
?DOC(" Extract values at specific indices from a row\n").
-spec extract_values_at_indices(list(gleam@dynamic:dynamic_()), list(integer())) -> list(gleam@dynamic:dynamic_()).
extract_values_at_indices(Row, Indices) ->
Indexed_row = gleam@list:index_map(Row, fun(Val, Idx) -> {Idx, Val} end),
gleam@list:filter_map(
Indices,
fun(Idx@1) ->
_pipe = gleam@list:find(
Indexed_row,
fun(Pair) -> erlang:element(1, Pair) =:= Idx@1 end
),
gleam@result:map(
_pipe,
fun(Pair@1) -> erlang:element(2, Pair@1) end
)
end
).
-file("src/cquill/adapter/memory.gleam", 958).
?DOC(" Convert a dynamic value to string for comparison\n").
-spec dynamic_to_string(gleam@dynamic:dynamic_()) -> binary().
dynamic_to_string(Value) ->
gleam@string:inspect(Value).
-file("src/cquill/adapter/memory.gleam", 875).
?DOC(" Check if any foreign keys reference this row before deletion\n").
-spec check_foreign_key_references(memory_store(), binary(), binary()) -> {ok,
nil} |
{error, cquill@error:adapter_error()}.
check_foreign_key_references(Store, Table_name, Key) ->
_pipe = maps:to_list(erlang:element(2, Store)),
_pipe@3 = gleam@list:find_map(
_pipe,
fun(Table_entry) ->
{_, Checking_table} = Table_entry,
gleam@list:find_map(
erlang:element(9, Checking_table),
fun(Fk) ->
{foreign_key_constraint, Col_idx, Ref_table, _} = Fk,
case Ref_table =:= Table_name of
false ->
{error, nil};
true ->
_pipe@1 = maps:values(
erlang:element(5, Checking_table)
),
gleam@list:find_map(
_pipe@1,
fun(Row) ->
case begin
_pipe@2 = gleam@list:index_map(
Row,
fun(Val, Idx) -> {Idx, Val} end
),
gleam@list:find(
_pipe@2,
fun(Pair) ->
erlang:element(1, Pair) =:= Col_idx
end
)
end of
{error, _} ->
{error, nil};
{ok, {_, Fk_value}} ->
case dynamic_to_string(Fk_value) =:= Key of
false ->
{error, nil};
true ->
Detail = <<<<"Referenced by "/utf8,
(erlang:element(
2,
Checking_table
))/binary>>/binary,
" (row exists with this foreign key)"/utf8>>,
{ok,
{error,
{foreign_key_violation,
<<(erlang:element(
2,
Checking_table
))/binary,
"_fkey"/utf8>>,
Detail}}}
end
end
end
)
end
end
)
end
),
_pipe@4 = gleam@option:from_result(_pipe@3),
gleam@option:unwrap(_pipe@4, {ok, nil}).
-file("src/cquill/adapter/memory.gleam", 389).
?DOC(" Delete a row by primary key\n").
-spec delete_row(memory_store(), binary(), binary()) -> {ok, memory_store()} |
{error, cquill@error:adapter_error()}.
delete_row(Store, Table_name, Key) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
case gleam@dict:has_key(erlang:element(5, Table), Key) of
false ->
{error, not_found};
true ->
case check_foreign_key_references(Store, Table_name, Key) of
{error, E} ->
{error, E};
{ok, _} ->
New_rows = gleam@dict:delete(
erlang:element(5, Table),
Key
),
New_table = {memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
New_rows,
erlang:element(6, Table),
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)},
New_tables = gleam@dict:insert(
erlang:element(2, Store),
Table_name,
New_table
),
{ok,
{memory_store,
New_tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}}
end
end
end.
-file("src/cquill/adapter/memory.gleam", 681).
-spec do_delete_all(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())}),
integer()
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
do_delete_all(Store, Table_name, Rows, Count) ->
case Rows of
[] ->
{ok, {Store, Count}};
[{Key, _} | Rest] ->
case delete_row(Store, Table_name, Key) of
{error, E} ->
{error, E};
{ok, New_store} ->
do_delete_all(New_store, Table_name, Rest, Count + 1)
end
end.
-file("src/cquill/adapter/memory.gleam", 662).
?DOC(
" Delete all rows matching a predicate.\n"
" Returns the number of deleted rows.\n"
).
-spec delete_all(
memory_store(),
binary(),
fun((binary(), list(gleam@dynamic:dynamic_())) -> boolean())
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
delete_all(Store, Table_name, Predicate) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
Matching = begin
_pipe = maps:to_list(erlang:element(5, Table)),
gleam@list:filter(
_pipe,
fun(Pair) ->
Predicate(
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
)
end,
do_delete_all(Store, Table_name, Matching, 0)
end.
-file("src/cquill/adapter/memory.gleam", 699).
?DOC(
" Delete all rows in a table (truncate).\n"
" Returns the number of deleted rows.\n"
).
-spec delete_all_rows(memory_store(), binary()) -> {ok,
{memory_store(), integer()}} |
{error, cquill@error:adapter_error()}.
delete_all_rows(Store, Table_name) ->
delete_all(Store, Table_name, fun(_, _) -> true end).
-file("src/cquill/adapter/memory.gleam", 953).
?DOC(" Check if two dynamic values are equal (by string representation)\n").
-spec dynamic_equals(gleam@dynamic:dynamic_(), gleam@dynamic:dynamic_()) -> boolean().
dynamic_equals(A, B) ->
dynamic_to_string(A) =:= dynamic_to_string(B).
-file("src/cquill/adapter/memory.gleam", 944).
?DOC(" Check if two lists of dynamic values are equal\n").
-spec values_equal(
list(gleam@dynamic:dynamic_()),
list(gleam@dynamic:dynamic_())
) -> boolean().
values_equal(A, B) ->
case {A, B} of
{[], []} ->
true;
{[X | Xs], [Y | Ys]} ->
dynamic_equals(X, Y) andalso values_equal(Xs, Ys);
{_, _} ->
false
end.
-file("src/cquill/adapter/memory.gleam", 772).
?DOC(" Check unique constraints on a row\n").
-spec check_unique_constraints(
memory_table(),
list(gleam@dynamic:dynamic_()),
gleam@option:option(binary())
) -> {ok, nil} | {error, cquill@error:adapter_error()}.
check_unique_constraints(Table, Row, Exclude_key) ->
Existing_rows = case Exclude_key of
none ->
maps:to_list(erlang:element(5, Table));
{some, Key} ->
_pipe = maps:to_list(erlang:element(5, Table)),
gleam@list:filter(
_pipe,
fun(Pair) -> erlang:element(1, Pair) /= Key end
)
end,
_pipe@1 = maps:to_list(erlang:element(7, Table)),
_pipe@2 = gleam@list:find_map(
_pipe@1,
fun(Constraint) ->
{Constraint_name, Column_indices} = Constraint,
New_values = extract_values_at_indices(Row, Column_indices),
Violation = gleam@list:find(
Existing_rows,
fun(Existing) ->
Existing_values = extract_values_at_indices(
erlang:element(2, Existing),
Column_indices
),
values_equal(New_values, Existing_values)
end
),
case Violation of
{ok, _} ->
Detail = <<"Duplicate value for unique constraint"/utf8>>,
{ok, {error, {unique_violation, Constraint_name, Detail}}};
{error, _} ->
{error, nil}
end
end
),
_pipe@3 = gleam@option:from_result(_pipe@2),
gleam@option:unwrap(_pipe@3, {ok, nil}).
-file("src/cquill/adapter/memory.gleam", 965).
?DOC(" Check if a dynamic value is null\n").
-spec is_null_value(gleam@dynamic:dynamic_()) -> boolean().
is_null_value(Value) ->
Str_repr = gleam@string:inspect(Value),
((Str_repr =:= <<"Nil"/utf8>>) orelse (Str_repr =:= <<"None"/utf8>>)) orelse (Str_repr
=:= <<"null"/utf8>>).
-file("src/cquill/adapter/memory.gleam", 739).
?DOC(" Check not-null constraints on a row\n").
-spec check_not_null_constraints(memory_table(), list(gleam@dynamic:dynamic_())) -> {ok,
nil} |
{error, cquill@error:adapter_error()}.
check_not_null_constraints(Table, Row) ->
Row_values = gleam@list:index_map(Row, fun(Val, Idx) -> {Idx, Val} end),
Violations = gleam@list:filter_map(
erlang:element(8, Table),
fun(Col_idx) ->
case gleam@list:find(
Row_values,
fun(Pair) -> erlang:element(1, Pair) =:= Col_idx end
) of
{error, _} ->
{error, nil};
{ok, {_, Value}} ->
case is_null_value(Value) of
true ->
Column_name = begin
_pipe = gleam@list:index_map(
erlang:element(4, Table),
fun(Col, Idx@1) -> {Idx@1, Col} end
),
_pipe@1 = gleam@list:find(
_pipe,
fun(Pair@1) ->
erlang:element(1, Pair@1) =:= Col_idx
end
),
_pipe@2 = gleam@option:from_result(_pipe@1),
_pipe@3 = gleam@option:map(
_pipe@2,
fun(Pair@2) -> erlang:element(2, Pair@2) end
),
gleam@option:unwrap(_pipe@3, <<"unknown"/utf8>>)
end,
{ok, Column_name};
false ->
{error, nil}
end
end
end
),
case Violations of
[Column | _] ->
{error, {not_null_violation, Column}};
[] ->
{ok, nil}
end.
-file("src/cquill/adapter/memory.gleam", 811).
?DOC(" Check foreign key constraints on a row\n").
-spec check_foreign_key_constraints(
memory_store(),
memory_table(),
list(gleam@dynamic:dynamic_())
) -> {ok, nil} | {error, cquill@error:adapter_error()}.
check_foreign_key_constraints(Store, Table, Row) ->
_pipe@1 = gleam@list:find_map(
erlang:element(9, Table),
fun(Fk) ->
{foreign_key_constraint, Col_idx, Ref_table, Ref_column} = Fk,
case begin
_pipe = gleam@list:index_map(
Row,
fun(Val, Idx) -> {Idx, Val} end
),
gleam@list:find(
_pipe,
fun(Pair) -> erlang:element(1, Pair) =:= Col_idx end
)
end of
{error, _} ->
{error, nil};
{ok, {_, Fk_value}} ->
case is_null_value(Fk_value) of
true ->
{error, nil};
false ->
case gleam_stdlib:map_get(
erlang:element(2, Store),
Ref_table
) of
{error, _} ->
Detail = <<<<"Referenced table "/utf8,
Ref_table/binary>>/binary,
" does not exist"/utf8>>,
{ok,
{error,
{foreign_key_violation,
<<<<<<(erlang:element(2, Table))/binary,
"_"/utf8>>/binary,
Ref_column/binary>>/binary,
"_fkey"/utf8>>,
Detail}}};
{ok, Ref_table_data} ->
Fk_string = dynamic_to_string(Fk_value),
case gleam@dict:has_key(
erlang:element(5, Ref_table_data),
Fk_string
) of
true ->
{error, nil};
false ->
Detail@1 = <<<<<<<<<<"Key ("/utf8,
Fk_string/binary>>/binary,
") not found in "/utf8>>/binary,
Ref_table/binary>>/binary,
"."/utf8>>/binary,
Ref_column/binary>>,
{ok,
{error,
{foreign_key_violation,
<<<<<<(erlang:element(
2,
Table
))/binary,
"_"/utf8>>/binary,
Ref_column/binary>>/binary,
"_fkey"/utf8>>,
Detail@1}}}
end
end
end
end
end
),
_pipe@2 = gleam@option:from_result(_pipe@1),
gleam@option:unwrap(_pipe@2, {ok, nil}).
-file("src/cquill/adapter/memory.gleam", 268).
?DOC(" Insert a row into a table with full constraint checking\n").
-spec insert_row(
memory_store(),
binary(),
binary(),
list(gleam@dynamic:dynamic_())
) -> {ok, memory_store()} | {error, cquill@error:adapter_error()}.
insert_row(Store, Table_name, Key, Row) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
case gleam@dict:has_key(erlang:element(5, Table), Key) of
true ->
{error,
{unique_violation,
<<Table_name/binary, "_pkey"/utf8>>,
<<<<"Key ("/utf8, Key/binary>>/binary,
") already exists"/utf8>>}};
false ->
case check_not_null_constraints(Table, Row) of
{error, E} ->
{error, E};
{ok, _} ->
case check_unique_constraints(Table, Row, none) of
{error, E@1} ->
{error, E@1};
{ok, _} ->
case check_foreign_key_constraints(
Store,
Table,
Row
) of
{error, E@2} ->
{error, E@2};
{ok, _} ->
New_rows = gleam@dict:insert(
erlang:element(5, Table),
Key,
Row
),
New_table = {memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
New_rows,
erlang:element(6, Table) + 1,
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)},
New_tables = gleam@dict:insert(
erlang:element(2, Store),
Table_name,
New_table
),
{ok,
{memory_store,
New_tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}}
end
end
end
end
end.
-file("src/cquill/adapter/memory.gleam", 320).
?DOC(" Update a row in a table with constraint checking\n").
-spec update_row(
memory_store(),
binary(),
binary(),
list(gleam@dynamic:dynamic_())
) -> {ok, memory_store()} | {error, cquill@error:adapter_error()}.
update_row(Store, Table_name, Key, Row) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
case gleam@dict:has_key(erlang:element(5, Table), Key) of
false ->
{error, not_found};
true ->
case check_not_null_constraints(Table, Row) of
{error, E} ->
{error, E};
{ok, _} ->
case check_unique_constraints(
Table,
Row,
{some, Key}
) of
{error, E@1} ->
{error, E@1};
{ok, _} ->
case check_foreign_key_constraints(
Store,
Table,
Row
) of
{error, E@2} ->
{error, E@2};
{ok, _} ->
New_rows = gleam@dict:insert(
erlang:element(5, Table),
Key,
Row
),
New_table = {memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
New_rows,
erlang:element(6, Table),
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)},
New_tables = gleam@dict:insert(
erlang:element(2, Store),
Table_name,
New_table
),
{ok,
{memory_store,
New_tables,
erlang:element(3, Store),
erlang:element(4, Store),
erlang:element(5, Store)}}
end
end
end
end
end.
-file("src/cquill/adapter/memory.gleam", 543).
?DOC(" Validate all rows for insert constraints\n").
-spec validate_rows_for_insert(
memory_store(),
memory_table(),
list({binary(), list(gleam@dynamic:dynamic_())})
) -> {ok, nil} | {error, cquill@error:adapter_error()}.
validate_rows_for_insert(Store, Table, Rows) ->
case Rows of
[] ->
{ok, nil};
[{Key, Row} | Rest] ->
case gleam@dict:has_key(erlang:element(5, Table), Key) of
true ->
{error,
{unique_violation,
<<(erlang:element(2, Table))/binary, "_pkey"/utf8>>,
<<<<"Key ("/utf8, Key/binary>>/binary,
") already exists"/utf8>>}};
false ->
case check_not_null_constraints(Table, Row) of
{error, E} ->
{error, E};
{ok, _} ->
case check_unique_constraints(Table, Row, none) of
{error, E@1} ->
{error, E@1};
{ok, _} ->
case check_foreign_key_constraints(
Store,
Table,
Row
) of
{error, E@2} ->
{error, E@2};
{ok, _} ->
validate_rows_for_insert(
Store,
Table,
Rest
)
end
end
end
end
end.
-file("src/cquill/adapter/memory.gleam", 506).
?DOC(" Validate all rows before inserting (for atomic operations)\n").
-spec validate_batch_insert(
memory_store(),
memory_table(),
list({binary(), list(gleam@dynamic:dynamic_())})
) -> {ok, nil} | {error, cquill@error:adapter_error()}.
validate_batch_insert(Store, Table, Rows) ->
Keys = gleam@list:map(Rows, fun(Pair) -> erlang:element(1, Pair) end),
case has_duplicate_keys(Keys) of
true ->
{error,
{unique_violation,
<<(erlang:element(2, Table))/binary, "_pkey"/utf8>>,
<<"Duplicate keys within batch"/utf8>>}};
false ->
validate_rows_for_insert(Store, Table, Rows)
end.
-file("src/cquill/adapter/memory.gleam", 583).
?DOC(" Actually insert all validated rows\n").
-spec do_insert_all(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())}),
integer()
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
do_insert_all(Store, Table_name, Rows, Count) ->
case Rows of
[] ->
{ok, {Store, Count}};
[{Key, Row} | Rest] ->
case insert_row(Store, Table_name, Key, Row) of
{error, E} ->
{error, E};
{ok, New_store} ->
do_insert_all(New_store, Table_name, Rest, Count + 1)
end
end.
-file("src/cquill/adapter/memory.gleam", 484).
?DOC(" Insert all rows atomically - all succeed or none\n").
-spec insert_all_atomic(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())})
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
insert_all_atomic(Store, Table_name, Rows) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
case validate_batch_insert(Store, Table, Rows) of
{error, E} ->
{error, E};
{ok, _} ->
do_insert_all(Store, Table_name, Rows, 0)
end
end.
-file("src/cquill/adapter/memory.gleam", 600).
?DOC(" Insert rows non-atomically (stop on first error, keep prior inserts)\n").
-spec insert_all_non_atomic(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())})
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
insert_all_non_atomic(Store, Table_name, Rows) ->
do_insert_all(Store, Table_name, Rows, 0).
-file("src/cquill/adapter/memory.gleam", 471).
?DOC(
" Insert multiple rows with configuration options.\n"
" When use_transaction is True, all rows are inserted atomically.\n"
" Returns the number of inserted rows on success.\n"
).
-spec insert_all_with_config(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())}),
batch_config()
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
insert_all_with_config(Store, Table_name, Rows, Config) ->
case erlang:element(3, Config) of
true ->
insert_all_atomic(Store, Table_name, Rows);
false ->
insert_all_non_atomic(Store, Table_name, Rows)
end.
-file("src/cquill/adapter/memory.gleam", 460).
?DOC(
" Insert multiple rows atomically.\n"
" All rows are inserted or none are (atomic behavior).\n"
" Returns the number of inserted rows on success.\n"
).
-spec insert_all(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())})
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
insert_all(Store, Table_name, Rows) ->
insert_all_with_config(Store, Table_name, Rows, default_batch_config()).
-file("src/cquill/adapter/memory.gleam", 630).
-spec do_update_all(
memory_store(),
binary(),
list({binary(), list(gleam@dynamic:dynamic_())}),
fun((list(gleam@dynamic:dynamic_())) -> list(gleam@dynamic:dynamic_())),
integer()
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
do_update_all(Store, Table_name, Rows, Updater, Count) ->
case Rows of
[] ->
{ok, {Store, Count}};
[{Key, Row} | Rest] ->
Updated_row = Updater(Row),
case update_row(Store, Table_name, Key, Updated_row) of
{error, E} ->
{error, E};
{ok, New_store} ->
do_update_all(
New_store,
Table_name,
Rest,
Updater,
Count + 1
)
end
end.
-file("src/cquill/adapter/memory.gleam", 610).
?DOC(
" Update all rows matching a predicate.\n"
" Returns the number of updated rows.\n"
).
-spec update_all(
memory_store(),
binary(),
fun((binary(), list(gleam@dynamic:dynamic_())) -> boolean()),
fun((list(gleam@dynamic:dynamic_())) -> list(gleam@dynamic:dynamic_()))
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
update_all(Store, Table_name, Predicate, Updater) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
Matching = begin
_pipe = maps:to_list(erlang:element(5, Table)),
gleam@list:filter(
_pipe,
fun(Pair) ->
Predicate(
erlang:element(1, Pair),
erlang:element(2, Pair)
)
end
)
end,
do_update_all(Store, Table_name, Matching, Updater, 0)
end.
-file("src/cquill/adapter/memory.gleam", 652).
?DOC(
" Update all rows with new values (simple version without predicate).\n"
" Useful for \"UPDATE table SET column = value\" style updates.\n"
).
-spec update_all_rows(
memory_store(),
binary(),
fun((list(gleam@dynamic:dynamic_())) -> list(gleam@dynamic:dynamic_()))
) -> {ok, {memory_store(), integer()}} | {error, cquill@error:adapter_error()}.
update_all_rows(Store, Table_name, Updater) ->
update_all(Store, Table_name, fun(_, _) -> true end, Updater).
-file("src/cquill/adapter/memory.gleam", 708).
?DOC(
" Insert multiple rows using auto-generated keys.\n"
" Returns the inserted keys and updated store.\n"
).
-spec insert_all_with_auto_keys(
memory_store(),
binary(),
list(list(gleam@dynamic:dynamic_()))
) -> {ok, {memory_store(), list(binary()), integer()}} |
{error, cquill@error:adapter_error()}.
insert_all_with_auto_keys(Store, Table_name, Rows) ->
case gleam_stdlib:map_get(erlang:element(2, Store), Table_name) of
{error, _} ->
{error, {adapter_specific, <<"TABLE_NOT_FOUND"/utf8>>, Table_name}};
{ok, Table} ->
Start_id = erlang:element(6, Table),
Rows_with_keys = gleam@list:index_map(
Rows,
fun(Row, Idx) ->
{erlang:integer_to_binary(Start_id + Idx), Row}
end
),
case insert_all(Store, Table_name, Rows_with_keys) of
{error, E} ->
{error, E};
{ok, {New_store, Count}} ->
Keys = gleam@list:map(
Rows_with_keys,
fun(Pair) -> erlang:element(1, Pair) end
),
{ok, {New_store, Keys, Count}}
end
end.
-file("src/cquill/adapter/memory.gleam", 976).
?DOC(" Memory adapter capabilities\n").
-spec memory_capabilities() -> cquill@adapter:adapter_capabilities().
memory_capabilities() ->
{adapter_capabilities, true, true, true, true, none, false, true}.
-file("src/cquill/adapter/memory.gleam", 1095).
?DOC(
" Begin a transaction by taking a snapshot\n"
" Supports nested transactions via snapshot stack\n"
).
-spec begin_transaction(memory_store()) -> {ok, memory_store()} |
{error, cquill@error:adapter_error()}.
begin_transaction(Store) ->
Id_counters = gleam@dict:map_values(
erlang:element(2, Store),
fun(_, Table) -> erlang:element(6, Table) end
),
Snapshot = {snapshot, none, erlang:element(2, Store), Id_counters},
{ok,
{memory_store,
erlang:element(2, Store),
true,
[Snapshot | erlang:element(4, Store)],
{some, Snapshot}}}.
-file("src/cquill/adapter/memory.gleam", 1114).
?DOC(" Commit a transaction by popping the snapshot\n").
-spec commit_transaction(memory_store()) -> {ok, nil} |
{error, cquill@error:adapter_error()}.
commit_transaction(Store) ->
case {erlang:element(3, Store), erlang:element(4, Store)} of
{false, _} ->
{error, {query_failed, <<"Not in transaction"/utf8>>, none}};
{true, []} ->
{error, {query_failed, <<"No transaction to commit"/utf8>>, none}};
{true, _} ->
{ok, nil}
end.
-file("src/cquill/adapter/memory.gleam", 1124).
?DOC(
" Get the store state after committing a transaction\n"
" This is needed for the memory adapter since commit_transaction returns Nil\n"
).
-spec commit_and_continue(memory_store()) -> {ok, memory_store()} |
{error, cquill@error:adapter_error()}.
commit_and_continue(Store) ->
case {erlang:element(3, Store), erlang:element(4, Store)} of
{false, _} ->
{error, {query_failed, <<"Not in transaction"/utf8>>, none}};
{true, []} ->
{error, {query_failed, <<"No transaction to commit"/utf8>>, none}};
{true, [_ | Rest]} ->
Still_in_transaction = not gleam@list:is_empty(Rest),
New_snapshot = case Rest of
[S | _] ->
{some, S};
[] ->
none
end,
{ok,
{memory_store,
erlang:element(2, Store),
Still_in_transaction,
Rest,
New_snapshot}}
end.
-file("src/cquill/adapter/memory.gleam", 1150).
?DOC(" Rollback a transaction by restoring the snapshot\n").
-spec rollback_transaction(memory_store()) -> {ok, nil} |
{error, cquill@error:adapter_error()}.
rollback_transaction(Store) ->
case {erlang:element(3, Store), erlang:element(4, Store)} of
{false, _} ->
{error, {query_failed, <<"Not in transaction"/utf8>>, none}};
{true, []} ->
{error, {query_failed, <<"No snapshot to restore"/utf8>>, none}};
{true, [_ | _]} ->
{ok, nil}
end.
-file("src/cquill/adapter/memory.gleam", 1160).
?DOC(
" Get the restored store after a rollback\n"
" This is a helper for tests since rollback_transaction returns Nil\n"
).
-spec rollback_and_restore(memory_store()) -> {ok, memory_store()} |
{error, cquill@error:adapter_error()}.
rollback_and_restore(Store) ->
case {erlang:element(3, Store), erlang:element(4, Store)} of
{false, _} ->
{error, {query_failed, <<"Not in transaction"/utf8>>, none}};
{true, []} ->
{error, {query_failed, <<"No snapshot to restore"/utf8>>, none}};
{true, [Snapshot | Rest]} ->
Restored_tables = gleam@dict:map_values(
erlang:element(3, Snapshot),
fun(Name, Table) ->
case gleam_stdlib:map_get(erlang:element(4, Snapshot), Name) of
{ok, Id} ->
{memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
erlang:element(5, Table),
Id,
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)};
{error, _} ->
Table
end
end
),
Still_in_transaction = not gleam@list:is_empty(Rest),
New_snapshot = case Rest of
[S | _] ->
{some, S};
[] ->
none
end,
{ok,
{memory_store,
Restored_tables,
Still_in_transaction,
Rest,
New_snapshot}}
end.
-file("src/cquill/adapter/memory.gleam", 1194).
?DOC(
" Execute a function within a transaction on the memory store.\n"
" Automatically commits on success and rolls back on error.\n"
" Returns the updated store along with the result.\n"
).
-spec execute_transaction(
memory_store(),
fun((memory_store()) -> {ok, {memory_store(), OWR}} |
{error, cquill@error:adapter_error()})
) -> {ok, {memory_store(), OWR}} | {error, cquill@error:transaction_error(nil)}.
execute_transaction(Store, Operation) ->
case begin_transaction(Store) of
{error, E} ->
{error,
{begin_failed,
<<"Could not begin transaction: "/utf8,
(cquill@error:format_error(E))/binary>>}};
{ok, Tx_store} ->
case Operation(Tx_store) of
{ok, {Updated_store, Result}} ->
case commit_and_continue(Updated_store) of
{ok, Committed_store} ->
{ok, {Committed_store, Result}};
{error, E@1} ->
{error,
{commit_failed,
<<"Commit failed: "/utf8,
(cquill@error:format_error(E@1))/binary>>}}
end;
{error, Adapter_err} ->
Rolled_back = case rollback_and_restore(Tx_store) of
{ok, S} ->
S;
{error, _} ->
Store
end,
{error, {adapter_transaction_error, Adapter_err}}
end
end.
-file("src/cquill/adapter/memory.gleam", 1236).
?DOC(
" Create a savepoint with the given name.\n"
" Requires an active transaction.\n"
).
-spec create_savepoint(memory_store(), binary()) -> {ok, memory_store()} |
{error, cquill@error:savepoint_error(nil)}.
create_savepoint(Store, Name) ->
case erlang:element(3, Store) of
false ->
{error, savepoint_no_transaction};
true ->
Id_counters = gleam@dict:map_values(
erlang:element(2, Store),
fun(_, Table) -> erlang:element(6, Table) end
),
Snapshot = {snapshot,
{some, Name},
erlang:element(2, Store),
Id_counters},
{ok,
{memory_store,
erlang:element(2, Store),
erlang:element(3, Store),
[Snapshot | erlang:element(4, Store)],
{some, Snapshot}}}
end.
-file("src/cquill/adapter/memory.gleam", 1370).
-spec do_find_savepoint(list(snapshot()), binary(), list(snapshot())) -> {ok,
{snapshot(), list(snapshot())}} |
{error, nil}.
do_find_savepoint(Snapshots, Name, _) ->
case Snapshots of
[] ->
{error, nil};
[Snapshot | Rest] ->
case erlang:element(2, Snapshot) of
{some, Sp_name} when Sp_name =:= Name ->
{ok, {Snapshot, Rest}};
_ ->
do_find_savepoint(Rest, Name, [])
end
end.
-file("src/cquill/adapter/memory.gleam", 1363).
?DOC(
" Find a savepoint by name in the snapshot stack.\n"
" Returns the snapshot and the remaining stack (snapshots after the found one).\n"
).
-spec find_savepoint(list(snapshot()), binary()) -> {ok,
{snapshot(), list(snapshot())}} |
{error, nil}.
find_savepoint(Snapshots, Name) ->
do_find_savepoint(Snapshots, Name, []).
-file("src/cquill/adapter/memory.gleam", 1263).
?DOC(
" Rollback to a named savepoint, discarding all changes since it was created.\n"
" Also removes the savepoint and any savepoints created after it.\n"
).
-spec rollback_to_savepoint(memory_store(), binary()) -> {ok, memory_store()} |
{error, cquill@error:savepoint_error(nil)}.
rollback_to_savepoint(Store, Name) ->
case erlang:element(3, Store) of
false ->
{error, savepoint_no_transaction};
true ->
case find_savepoint(erlang:element(4, Store), Name) of
{error, _} ->
{error, {savepoint_not_found, Name}};
{ok, {Snapshot, Remaining}} ->
Restored_tables = gleam@dict:map_values(
erlang:element(3, Snapshot),
fun(Table_name, Table) ->
case gleam_stdlib:map_get(
erlang:element(4, Snapshot),
Table_name
) of
{ok, Id} ->
{memory_table,
erlang:element(2, Table),
erlang:element(3, Table),
erlang:element(4, Table),
erlang:element(5, Table),
Id,
erlang:element(7, Table),
erlang:element(8, Table),
erlang:element(9, Table)};
{error, _} ->
Table
end
end
),
New_snapshot = case Remaining of
[S | _] ->
{some, S};
[] ->
none
end,
{ok,
{memory_store,
Restored_tables,
erlang:element(3, Store),
Remaining,
New_snapshot}}
end
end.
-file("src/cquill/adapter/memory.gleam", 1395).
-spec do_remove_savepoint(list(snapshot()), binary(), list(snapshot())) -> {ok,
list(snapshot())} |
{error, nil}.
do_remove_savepoint(Snapshots, Name, Before) ->
case Snapshots of
[] ->
{error, nil};
[Snapshot | Rest] ->
case erlang:element(2, Snapshot) of
{some, Sp_name} when Sp_name =:= Name ->
{ok,
begin
_pipe = lists:reverse(Before),
lists:append(_pipe, Rest)
end};
_ ->
do_remove_savepoint(Rest, Name, [Snapshot | Before])
end
end.
-file("src/cquill/adapter/memory.gleam", 1388).
?DOC(
" Remove a savepoint from the stack without restoring its state.\n"
" Returns the modified stack with the savepoint removed.\n"
).
-spec remove_savepoint(list(snapshot()), binary()) -> {ok, list(snapshot())} |
{error, nil}.
remove_savepoint(Snapshots, Name) ->
do_remove_savepoint(Snapshots, Name, []).
-file("src/cquill/adapter/memory.gleam", 1304).
?DOC(
" Release a savepoint without rolling back.\n"
" This removes the savepoint, making its changes permanent (within the transaction).\n"
).
-spec release_savepoint(memory_store(), binary()) -> {ok, memory_store()} |
{error, cquill@error:savepoint_error(nil)}.
release_savepoint(Store, Name) ->
case erlang:element(3, Store) of
false ->
{error, savepoint_no_transaction};
true ->
case remove_savepoint(erlang:element(4, Store), Name) of
{error, _} ->
{error, {savepoint_not_found, Name}};
{ok, Remaining} ->
New_snapshot = case Remaining of
[S | _] ->
{some, S};
[] ->
none
end,
{ok,
{memory_store,
erlang:element(2, Store),
erlang:element(3, Store),
Remaining,
New_snapshot}}
end
end.
-file("src/cquill/adapter/memory.gleam", 1330).
?DOC(
" Execute a function within a savepoint.\n"
" If the function returns an error, rolls back to the savepoint.\n"
" If successful, releases the savepoint.\n"
).
-spec execute_savepoint(
memory_store(),
binary(),
fun((memory_store()) -> {ok, {memory_store(), OXG}} |
{error, cquill@error:adapter_error()})
) -> {ok, {memory_store(), OXG}} | {error, cquill@error:savepoint_error(nil)}.
execute_savepoint(Store, Name, Operation) ->
case create_savepoint(Store, Name) of
{error, E} ->
{error, E};
{ok, Sp_store} ->
case Operation(Sp_store) of
{ok, {Updated_store, Result}} ->
case release_savepoint(Updated_store, Name) of
{ok, Final_store} ->
{ok, {Final_store, Result}};
{error, E@1} ->
{error, E@1}
end;
{error, Adapter_err} ->
case rollback_to_savepoint(Sp_store, Name) of
{ok, Rolled_back_store} ->
{error, {savepoint_adapter_error, Adapter_err}};
{error, _} ->
{error, {savepoint_adapter_error, Adapter_err}}
end
end
end.
-file("src/cquill/adapter/memory.gleam", 1415).
?DOC(" Check if a savepoint with the given name exists\n").
-spec has_savepoint(memory_store(), binary()) -> boolean().
has_savepoint(Store, Name) ->
case find_savepoint(erlang:element(4, Store), Name) of
{ok, _} ->
true;
{error, _} ->
false
end.
-file("src/cquill/adapter/memory.gleam", 1423).
?DOC(" Get the names of all active savepoints\n").
-spec savepoint_names(memory_store()) -> list(binary()).
savepoint_names(Store) ->
_pipe = erlang:element(4, Store),
gleam@list:filter_map(
_pipe,
fun(Snapshot) -> case erlang:element(2, Snapshot) of
{some, Name} ->
{ok, Name};
none ->
{error, nil}
end end
).
-file("src/cquill/adapter/memory.gleam", 1438).
?DOC(" Extract table name from SQL (very simplified parser)\n").
-spec extract_table_name(binary(), binary()) -> {ok, binary()} | {error, nil}.
extract_table_name(Sql, Keyword) ->
Sql_upper = string:uppercase(Sql),
Keyword_upper = string:uppercase(Keyword),
case gleam@string:split(Sql_upper, <<Keyword_upper/binary, " "/utf8>>) of
[_, Rest] ->
case gleam@string:split(Rest, <<" "/utf8>>) of
[Table | _] ->
{ok, string:lowercase(Table)};
_ ->
{error, nil}
end;
_ ->
{error, nil}
end.
-file("src/cquill/adapter/memory.gleam", 1043).
?DOC(" Execute a mutation (INSERT/UPDATE/DELETE)\n").
-spec execute_mutation(memory_store(), cquill@adapter:compiled_query()) -> {ok,
integer()} |
{error, cquill@error:adapter_error()}.
execute_mutation(_, Query) ->
Sql_upper = string:uppercase(erlang:element(2, Query)),
Is_insert = gleam_stdlib:string_starts_with(Sql_upper, <<"INSERT"/utf8>>),
Is_update = gleam_stdlib:string_starts_with(Sql_upper, <<"UPDATE"/utf8>>),
Is_delete = gleam_stdlib:string_starts_with(Sql_upper, <<"DELETE"/utf8>>),
case {Is_insert, Is_update, Is_delete} of
{true, _, _} ->
{ok, 1};
{_, true, _} ->
{ok, 1};
{_, _, true} ->
case extract_table_name(erlang:element(2, Query), <<"FROM"/utf8>>) of
{error, _} ->
{error,
{query_failed, <<"Could not parse DELETE"/utf8>>, none}};
{ok, _} ->
{ok, 1}
end;
{_, _, _} ->
{error, {query_failed, <<"Unknown mutation type"/utf8>>, none}}
end.
-file("src/cquill/adapter/memory.gleam", 1453).
?DOC(" Extract ID from WHERE clause (very simplified)\n").
-spec extract_where_id(binary(), list(cquill@adapter:query_param())) -> gleam@option:option(binary()).
extract_where_id(Sql, Params) ->
Sql_upper = string:uppercase(Sql),
case gleam_stdlib:contains_string(Sql_upper, <<"WHERE"/utf8>>) of
false ->
none;
true ->
case {gleam_stdlib:contains_string(Sql_upper, <<"ID = $1"/utf8>>),
Params} of
{true, [{param_int, Id} | _]} ->
{some, erlang:integer_to_binary(Id)};
{true, [{param_string, Id@1} | _]} ->
{some, Id@1};
{_, _} ->
none
end
end.
-file("src/cquill/adapter/memory.gleam", 1018).
?DOC(" Execute a query - simplified implementation that just parses table name\n").
-spec execute_query(memory_store(), cquill@adapter:compiled_query()) -> {ok,
list(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_query(Store, Query) ->
case extract_table_name(erlang:element(2, Query), <<"FROM"/utf8>>) of
{error, _} ->
{error,
{query_failed,
<<"Could not parse query: "/utf8,
(erlang:element(2, Query))/binary>>,
none}};
{ok, Table_name} ->
case extract_where_id(
erlang:element(2, Query),
erlang:element(3, Query)
) of
{some, Id} ->
case get_row(Store, Table_name, Id) of
{ok, Row} ->
{ok, [Row]};
{error, not_found} ->
{ok, []};
{error, E} ->
{error, E}
end;
none ->
get_all_rows(Store, Table_name)
end
end.
-file("src/cquill/adapter/memory.gleam", 1471).
?DOC(" Convert query params to dynamic values\n").
-spec params_to_dynamics(list(cquill@adapter:query_param())) -> list(gleam@dynamic:dynamic_()).
params_to_dynamics(Params) ->
gleam@list:map(Params, fun(Param) -> case Param of
{param_int, I} ->
gleam_stdlib:identity(I);
{param_float, F} ->
gleam_stdlib:identity(F);
{param_string, S} ->
gleam_stdlib:identity(S);
{param_bool, B} ->
gleam_stdlib:identity(B);
param_null ->
gleam@dynamic:nil();
{param_bytes, B@1} ->
gleam_stdlib:identity(B@1);
{param_custom, _, V} ->
gleam_stdlib:identity(V)
end end).
-file("src/cquill/adapter/memory.gleam", 1074).
?DOC(" Execute an INSERT with RETURNING\n").
-spec execute_returning(memory_store(), cquill@adapter:compiled_query()) -> {ok,
gleam@option:option(list(gleam@dynamic:dynamic_()))} |
{error, cquill@error:adapter_error()}.
execute_returning(Store, Query) ->
case extract_table_name(erlang:element(2, Query), <<"INTO"/utf8>>) of
{error, _} ->
{error, {query_failed, <<"Could not parse INSERT"/utf8>>, none}};
{ok, Table_name} ->
case next_id(Store, Table_name) of
{error, E} ->
{error, E};
{ok, Id} ->
Row = [gleam_stdlib:identity(Id) |
params_to_dynamics(erlang:element(3, Query))],
{ok, {some, Row}}
end
end.
-file("src/cquill/adapter/memory.gleam", 1000).
?DOC(
" Create the memory adapter.\n"
"\n"
" Note: In a real implementation, the connection type would be a reference\n"
" to mutable state (e.g., an Actor). This simplified version passes the\n"
" store directly for demonstration purposes.\n"
).
-spec memory_adapter() -> cquill@adapter:adapter(memory_store(), list(gleam@dynamic:dynamic_())).
memory_adapter() ->
cquill@adapter:new(
<<"memory"/utf8>>,
memory_capabilities(),
fun execute_query/2,
fun execute_mutation/2,
fun execute_returning/2,
fun begin_transaction/1,
fun commit_transaction/1,
fun rollback_transaction/1
).