Current section
Files
Jump to
Current section
Files
src/galchemy@session@unit_of_work.erl
-module(galchemy@session@unit_of_work).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src\\galchemy\\session\\unit_of_work.gleam").
-export([new/1, field/2, identity/1, register_new/3, register_dirty/4, register_deleted/3, queries/1, discard_entity_changes/4, flush_plan/1]).
-export_type([field_value/0, identity/0, pending_insert/0, pending_update/0, pending_delete/0, session/0, flush_plan/0, session_error/0]).
-type field_value() :: {field_value,
binary(),
galchemy@ast@expression:sql_value()}.
-type identity() :: {identity, list(field_value())}.
-type pending_insert() :: {pending_insert,
galchemy@schema@relation:table_ref(),
list(field_value())}.
-type pending_update() :: {pending_update,
galchemy@schema@relation:table_ref(),
identity(),
list(field_value())}.
-type pending_delete() :: {pending_delete,
galchemy@schema@relation:table_ref(),
identity()}.
-type session() :: {session,
galchemy@schema@model:schema_snapshot(),
list(pending_insert()),
list(pending_update()),
list(pending_delete())}.
-type flush_plan() :: {flush_plan,
list(galchemy@ast@query:'query'()),
list(galchemy@ast@query:'query'()),
list(galchemy@ast@query:'query'())}.
-type session_error() :: {unknown_table, galchemy@schema@relation:table_ref()} |
{unknown_column, galchemy@schema@relation:table_ref(), binary()} |
{empty_insert_values, galchemy@schema@relation:table_ref()} |
{empty_changes, galchemy@schema@relation:table_ref()} |
{empty_identity, galchemy@schema@relation:table_ref()}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 58).
-spec new(galchemy@schema@model:schema_snapshot()) -> session().
new(Snapshot) ->
{session, Snapshot, [], [], []}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 62).
-spec field(binary(), galchemy@ast@expression:sql_value()) -> field_value().
field(Column, Value) ->
{field_value, Column, Value}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 66).
-spec identity(list(field_value())) -> identity().
identity(Fields) ->
{identity, Fields}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 70).
-spec register_new(
session(),
galchemy@schema@relation:table_ref(),
list(field_value())
) -> session().
register_new(Session, Table, Values) ->
{session,
erlang:element(2, Session),
lists:append(
erlang:element(3, Session),
[{pending_insert, Table, Values}]
),
erlang:element(4, Session),
erlang:element(5, Session)}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 83).
-spec register_dirty(
session(),
galchemy@schema@relation:table_ref(),
identity(),
list(field_value())
) -> session().
register_dirty(Session, Table, Identity, Changes) ->
{session,
erlang:element(2, Session),
erlang:element(3, Session),
lists:append(
erlang:element(4, Session),
[{pending_update, Table, Identity, Changes}]
),
erlang:element(5, Session)}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 97).
-spec register_deleted(
session(),
galchemy@schema@relation:table_ref(),
identity()
) -> session().
register_deleted(Session, Table, Identity) ->
{session,
erlang:element(2, Session),
erlang:element(3, Session),
erlang:element(4, Session),
lists:append(
erlang:element(5, Session),
[{pending_delete, Table, Identity}]
)}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 139).
-spec queries(flush_plan()) -> list(galchemy@ast@query:'query'()).
queries(Plan) ->
_pipe = erlang:element(2, Plan),
_pipe@1 = lists:append(_pipe, erlang:element(3, Plan)),
lists:append(_pipe@1, erlang:element(4, Plan)).
-file("src\\galchemy\\session\\unit_of_work.gleam", 407).
-spec has_column(list(galchemy@schema@model:column_schema()), binary()) -> boolean().
has_column(Columns, Column_name) ->
case Columns of
[] ->
false;
[Column_schema | Rest] ->
case erlang:element(2, Column_schema) =:= Column_name of
true ->
true;
false ->
has_column(Rest, Column_name)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 429).
-spec find_table_schema_in(
list(galchemy@schema@model:table_schema()),
galchemy@schema@relation:table_ref()
) -> gleam@option:option(galchemy@schema@model:table_schema()).
find_table_schema_in(Tables, Table) ->
case Tables of
[] ->
none;
[Table_schema | Rest] ->
case (erlang:element(2, Table_schema) =:= erlang:element(2, Table))
andalso (erlang:element(3, Table_schema) =:= erlang:element(
3,
Table
)) of
true ->
{some, Table_schema};
false ->
find_table_schema_in(Rest, Table)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 419).
-spec find_table_schema(
galchemy@schema@model:schema_snapshot(),
galchemy@schema@relation:table_ref()
) -> {ok, galchemy@schema@model:table_schema()} | {error, session_error()}.
find_table_schema(Snapshot, Table) ->
case find_table_schema_in(erlang:element(2, Snapshot), Table) of
{some, Table_schema} ->
{ok, Table_schema};
none ->
{error, {unknown_table, Table}}
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 446).
-spec ast_table(galchemy@schema@relation:table_ref()) -> galchemy@ast@schema:table().
ast_table(Table) ->
{table, {some, erlang:element(2, Table)}, erlang:element(3, Table), none}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 396).
-spec column_meta_for(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
binary()
) -> {ok, galchemy@ast@schema:column_meta()} | {error, session_error()}.
column_meta_for(Table, Table_schema, Column_name) ->
case has_column(erlang:element(4, Table_schema), Column_name) of
true ->
{ok, {column_meta, ast_table(Table), Column_name}};
false ->
{error, {unknown_column, Table, Column_name}}
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 468).
-spec order_inserts_for_tables(
list(pending_insert()),
list(galchemy@schema@relation:table_ref()),
list(pending_insert())
) -> list(pending_insert()).
order_inserts_for_tables(Inserts, Table_order, Acc) ->
case Table_order of
[] ->
Acc;
[Table_ref | Rest] ->
order_inserts_for_tables(
Inserts,
Rest,
lists:append(
Acc,
gleam@list:filter(
Inserts,
fun(Insert_change) ->
erlang:element(2, Insert_change) =:= Table_ref
end
)
)
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 490).
-spec contains_insert(list(pending_insert()), pending_insert()) -> boolean().
contains_insert(Inserts, Target) ->
case Inserts of
[] ->
false;
[Insert_change | Rest] ->
case Insert_change =:= Target of
true ->
true;
false ->
contains_insert(Rest, Target)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 454).
-spec order_inserts(
list(pending_insert()),
list(galchemy@schema@relation:table_ref())
) -> list(pending_insert()).
order_inserts(Inserts, Table_order) ->
Ordered = order_inserts_for_tables(Inserts, Table_order, []),
lists:append(
Ordered,
gleam@list:filter(
Inserts,
fun(Insert_change) ->
not contains_insert(Ordered, Insert_change)
end
)
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 516).
-spec order_deletes_for_tables(
list(pending_delete()),
list(galchemy@schema@relation:table_ref()),
list(pending_delete())
) -> list(pending_delete()).
order_deletes_for_tables(Deletes, Table_order, Acc) ->
case Table_order of
[] ->
Acc;
[Table_ref | Rest] ->
order_deletes_for_tables(
Deletes,
Rest,
lists:append(
Acc,
gleam@list:filter(
Deletes,
fun(Delete_change) ->
erlang:element(2, Delete_change) =:= Table_ref
end
)
)
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 538).
-spec contains_delete(list(pending_delete()), pending_delete()) -> boolean().
contains_delete(Deletes, Target) ->
case Deletes of
[] ->
false;
[Delete_change | Rest] ->
case Delete_change =:= Target of
true ->
true;
false ->
contains_delete(Rest, Target)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 502).
-spec order_deletes(
list(pending_delete()),
list(galchemy@schema@relation:table_ref())
) -> list(pending_delete()).
order_deletes(Deletes, Table_order) ->
Ordered = order_deletes_for_tables(Deletes, Table_order, []),
lists:append(
Ordered,
gleam@list:filter(
Deletes,
fun(Delete_change) ->
not contains_delete(Ordered, Delete_change)
end
)
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 550).
-spec discard_inserts(
list(pending_insert()),
galchemy@schema@relation:table_ref(),
list(field_value())
) -> list(pending_insert()).
discard_inserts(Inserts, Table, Values) ->
case Inserts of
[] ->
[];
[Insert_change | Rest] ->
case (erlang:element(2, Insert_change) =:= Table) andalso (erlang:element(
3,
Insert_change
)
=:= Values) of
true ->
discard_inserts(Rest, Table, Values);
false ->
[Insert_change | discard_inserts(Rest, Table, Values)]
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 566).
-spec discard_updates(
list(pending_update()),
galchemy@schema@relation:table_ref(),
identity()
) -> list(pending_update()).
discard_updates(Updates, Table, Identity) ->
case Updates of
[] ->
[];
[Update_change | Rest] ->
case (erlang:element(2, Update_change) =:= Table) andalso (erlang:element(
3,
Update_change
)
=:= Identity) of
true ->
discard_updates(Rest, Table, Identity);
false ->
[Update_change | discard_updates(Rest, Table, Identity)]
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 582).
-spec discard_deletes(
list(pending_delete()),
galchemy@schema@relation:table_ref(),
identity()
) -> list(pending_delete()).
discard_deletes(Deletes, Table, Identity) ->
case Deletes of
[] ->
[];
[Delete_change | Rest] ->
case (erlang:element(2, Delete_change) =:= Table) andalso (erlang:element(
3,
Delete_change
)
=:= Identity) of
true ->
discard_deletes(Rest, Table, Identity);
false ->
[Delete_change | discard_deletes(Rest, Table, Identity)]
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 110).
-spec discard_entity_changes(
session(),
galchemy@schema@relation:table_ref(),
identity(),
list(field_value())
) -> session().
discard_entity_changes(Session, Table, Identity, Values) ->
{session,
erlang:element(2, Session),
discard_inserts(erlang:element(3, Session), Table, Values),
discard_updates(erlang:element(4, Session), Table, Identity),
discard_deletes(erlang:element(5, Session), Table, Identity)}.
-file("src\\galchemy\\session\\unit_of_work.gleam", 660).
-spec find_relations_for_table(
list(galchemy@schema@relation:table_relations()),
galchemy@schema@relation:table_ref()
) -> gleam@option:option(galchemy@schema@relation:table_relations()).
find_relations_for_table(Relations_by_table, Table) ->
case Relations_by_table of
[] ->
none;
[Table_relations | Rest] ->
case erlang:element(2, Table_relations) =:= Table of
true ->
{some, Table_relations};
false ->
find_relations_for_table(Rest, Table)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 637).
-spec dependencies_resolved(
galchemy@schema@relation:table_ref(),
list(galchemy@schema@relation:table_ref()),
list(galchemy@schema@relation:table_relations())
) -> boolean().
dependencies_resolved(Table, Remaining, Relations_by_table) ->
case find_relations_for_table(Relations_by_table, Table) of
none ->
true;
{some, Table_relations} ->
Dependencies = gleam@list:filter_map(
erlang:element(3, Table_relations),
fun(Next_relation) -> case erlang:element(4, Next_relation) of
belongs_to ->
{ok, erlang:element(5, Next_relation)};
has_many ->
{error, nil}
end end
),
gleam@list:fold(
Dependencies,
true,
fun(Acc, Dependency) ->
Acc andalso not gleam@list:contains(Remaining, Dependency)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 607).
-spec resolve_insert_order(
list(galchemy@schema@relation:table_ref()),
list(galchemy@schema@relation:table_relations()),
list(galchemy@schema@relation:table_ref())
) -> list(galchemy@schema@relation:table_ref()).
resolve_insert_order(Remaining, Relations_by_table, Resolved) ->
case Remaining of
[] ->
Resolved;
_ ->
Ready = gleam@list:filter(
Remaining,
fun(Table_ref) ->
dependencies_resolved(
Table_ref,
Remaining,
Relations_by_table
)
end
),
Blocked = gleam@list:filter(
Remaining,
fun(Table_ref@1) ->
not gleam@list:contains(Ready, Table_ref@1)
end
),
case Ready of
[] ->
lists:append(Resolved, Remaining);
_ ->
resolve_insert_order(
Blocked,
Relations_by_table,
lists:append(Resolved, Ready)
)
end
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 598).
-spec insert_table_order(galchemy@schema@model:schema_snapshot()) -> list(galchemy@schema@relation:table_ref()).
insert_table_order(Snapshot) ->
All_tables = gleam@list:map(
erlang:element(2, Snapshot),
fun(Table_schema) ->
galchemy@schema@relation:table_ref(
erlang:element(2, Table_schema),
erlang:element(3, Table_schema)
)
end
),
resolve_insert_order(
All_tables,
galchemy@schema@relation:infer(Snapshot),
[]
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 675).
-spec result_try(
{ok, IRX} | {error, IRY},
fun((IRX) -> {ok, ISB} | {error, IRY})
) -> {ok, ISB} | {error, IRY}.
result_try(Value, Next) ->
case Value of
{ok, Inner} ->
Next(Inner);
{error, Error} ->
{error, Error}
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 348).
-spec predicate_for_field(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
field_value()
) -> {ok, galchemy@ast@expression:predicate()} | {error, session_error()}.
predicate_for_field(Table, Table_schema, Field_value) ->
result_try(
column_meta_for(Table, Table_schema, erlang:element(2, Field_value)),
fun(Column_meta) ->
{ok,
{comparison,
{column_expr, Column_meta},
eq,
{value_expr, erlang:element(3, Field_value)}}}
end
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 324).
-spec predicate_for_identity_rest(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
list(field_value()),
galchemy@ast@expression:predicate()
) -> {ok, galchemy@ast@expression:predicate()} | {error, session_error()}.
predicate_for_identity_rest(Table, Table_schema, Fields, Acc) ->
case Fields of
[] ->
{ok, Acc};
[Field_value | Rest] ->
result_try(
predicate_for_field(Table, Table_schema, Field_value),
fun(Next_predicate) ->
predicate_for_identity_rest(
Table,
Table_schema,
Rest,
{'and', Acc, Next_predicate}
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 306).
-spec predicate_for_identity(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
identity()
) -> {ok, galchemy@ast@expression:predicate()} | {error, session_error()}.
predicate_for_identity(Table, Table_schema, Identity) ->
case erlang:element(2, Identity) of
[] ->
{error, {empty_identity, Table}};
[First | Rest] ->
result_try(
predicate_for_field(Table, Table_schema, First),
fun(First_predicate) ->
predicate_for_identity_rest(
Table,
Table_schema,
Rest,
First_predicate
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 281).
-spec delete_query(pending_delete(), galchemy@schema@model:schema_snapshot()) -> {ok,
galchemy@ast@query:'query'()} |
{error, session_error()}.
delete_query(Delete_change, Snapshot) ->
result_try(
find_table_schema(Snapshot, erlang:element(2, Delete_change)),
fun(Table_schema) ->
result_try(
predicate_for_identity(
erlang:element(2, Delete_change),
Table_schema,
erlang:element(3, Delete_change)
),
fun(Where_) ->
{ok,
{delete,
{delete_query,
ast_table(erlang:element(2, Delete_change)),
{some, Where_},
[]}}}
end
)
end
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 201).
-spec build_delete_queries_loop(
list(pending_delete()),
galchemy@schema@model:schema_snapshot(),
list(galchemy@ast@query:'query'())
) -> {ok, list(galchemy@ast@query:'query'())} | {error, session_error()}.
build_delete_queries_loop(Deletes, Snapshot, Acc) ->
case Deletes of
[] ->
{ok, lists:reverse(Acc)};
[Delete_change | Rest] ->
result_try(
delete_query(Delete_change, Snapshot),
fun(Next_query) ->
build_delete_queries_loop(
Rest,
Snapshot,
[Next_query | Acc]
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 190).
-spec build_delete_queries(
session(),
list(galchemy@schema@relation:table_ref())
) -> {ok, list(galchemy@ast@query:'query'())} | {error, session_error()}.
build_delete_queries(Session, Table_order) ->
build_delete_queries_loop(
order_deletes(erlang:element(5, Session), Table_order),
erlang:element(2, Session),
[]
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 374).
-spec assignments_for_loop(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
list(field_value()),
list({galchemy@ast@schema:column_meta(),
galchemy@ast@expression:expression()})
) -> {ok,
list({galchemy@ast@schema:column_meta(),
galchemy@ast@expression:expression()})} |
{error, session_error()}.
assignments_for_loop(Table, Table_schema, Fields, Acc) ->
case Fields of
[] ->
{ok, lists:reverse(Acc)};
[Field_value | Rest] ->
result_try(
column_meta_for(
Table,
Table_schema,
erlang:element(2, Field_value)
),
fun(Column_meta) ->
assignments_for_loop(
Table,
Table_schema,
Rest,
[{Column_meta,
{value_expr, erlang:element(3, Field_value)}} |
Acc]
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 366).
-spec assignments_for(
galchemy@schema@relation:table_ref(),
galchemy@schema@model:table_schema(),
list(field_value())
) -> {ok,
list({galchemy@ast@schema:column_meta(),
galchemy@ast@expression:expression()})} |
{error, session_error()}.
assignments_for(Table, Table_schema, Fields) ->
assignments_for_loop(Table, Table_schema, Fields, []).
-file("src\\galchemy\\session\\unit_of_work.gleam", 215).
-spec insert_query(pending_insert(), galchemy@schema@model:schema_snapshot()) -> {ok,
galchemy@ast@query:'query'()} |
{error, session_error()}.
insert_query(Insert_change, Snapshot) ->
case erlang:element(3, Insert_change) of
[] ->
{error, {empty_insert_values, erlang:element(2, Insert_change)}};
_ ->
result_try(
find_table_schema(Snapshot, erlang:element(2, Insert_change)),
fun(Table_schema) ->
result_try(
assignments_for(
erlang:element(2, Insert_change),
Table_schema,
erlang:element(3, Insert_change)
),
fun(Assignments) ->
{ok,
{insert,
{insert_query,
ast_table(
erlang:element(2, Insert_change)
),
[Assignments],
[]}}}
end
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 156).
-spec build_insert_queries_loop(
list(pending_insert()),
galchemy@schema@model:schema_snapshot(),
list(galchemy@ast@query:'query'())
) -> {ok, list(galchemy@ast@query:'query'())} | {error, session_error()}.
build_insert_queries_loop(Inserts, Snapshot, Acc) ->
case Inserts of
[] ->
{ok, lists:reverse(Acc)};
[Insert_change | Rest] ->
result_try(
insert_query(Insert_change, Snapshot),
fun(Next_query) ->
build_insert_queries_loop(
Rest,
Snapshot,
[Next_query | Acc]
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 145).
-spec build_insert_queries(
session(),
list(galchemy@schema@relation:table_ref())
) -> {ok, list(galchemy@ast@query:'query'())} | {error, session_error()}.
build_insert_queries(Session, Table_order) ->
build_insert_queries_loop(
order_inserts(erlang:element(3, Session), Table_order),
erlang:element(2, Session),
[]
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 245).
-spec update_query(pending_update(), galchemy@schema@model:schema_snapshot()) -> {ok,
galchemy@ast@query:'query'()} |
{error, session_error()}.
update_query(Update_change, Snapshot) ->
case erlang:element(4, Update_change) of
[] ->
{error, {empty_changes, erlang:element(2, Update_change)}};
_ ->
result_try(
find_table_schema(Snapshot, erlang:element(2, Update_change)),
fun(Table_schema) ->
result_try(
assignments_for(
erlang:element(2, Update_change),
Table_schema,
erlang:element(4, Update_change)
),
fun(Assignments) ->
result_try(
predicate_for_identity(
erlang:element(2, Update_change),
Table_schema,
erlang:element(3, Update_change)
),
fun(Where_) ->
{ok,
{update,
{update_query,
ast_table(
erlang:element(
2,
Update_change
)
),
Assignments,
{some, Where_},
[]}}}
end
)
end
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 176).
-spec build_update_queries_loop(
list(pending_update()),
galchemy@schema@model:schema_snapshot(),
list(galchemy@ast@query:'query'())
) -> {ok, list(galchemy@ast@query:'query'())} | {error, session_error()}.
build_update_queries_loop(Updates, Snapshot, Acc) ->
case Updates of
[] ->
{ok, lists:reverse(Acc)};
[Update_change | Rest] ->
result_try(
update_query(Update_change, Snapshot),
fun(Next_query) ->
build_update_queries_loop(
Rest,
Snapshot,
[Next_query | Acc]
)
end
)
end.
-file("src\\galchemy\\session\\unit_of_work.gleam", 170).
-spec build_update_queries(session()) -> {ok,
list(galchemy@ast@query:'query'())} |
{error, session_error()}.
build_update_queries(Session) ->
build_update_queries_loop(
erlang:element(4, Session),
erlang:element(2, Session),
[]
).
-file("src\\galchemy\\session\\unit_of_work.gleam", 124).
-spec flush_plan(session()) -> {ok, flush_plan()} | {error, session_error()}.
flush_plan(Session) ->
Insert_order = insert_table_order(erlang:element(2, Session)),
Delete_order = lists:reverse(Insert_order),
result_try(
build_insert_queries(Session, Insert_order),
fun(Insert_queries) ->
result_try(
build_update_queries(Session),
fun(Update_queries) ->
result_try(
build_delete_queries(Session, Delete_order),
fun(Delete_queries) ->
{ok,
{flush_plan,
Insert_queries,
Update_queries,
Delete_queries}}
end
)
end
)
end
).