Current section
Files
Jump to
Current section
Files
src/glsql@resolve.erl
-module(glsql@resolve).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glsql/resolve.gleam").
-export([snake_case/1, pascal_case/1, resolve/2]).
-export_type([resolved_schema/0, resolved_table/0, resolved_column/0]).
-type resolved_schema() :: {resolved_schema, list(resolved_table())}.
-type resolved_table() :: {resolved_table,
binary(),
binary(),
binary(),
list(resolved_column())}.
-type resolved_column() :: {resolved_column,
binary(),
binary(),
binary(),
binary(),
binary(),
binary(),
boolean(),
boolean(),
list(binary())}.
-file("src/glsql/resolve.gleam", 186).
-spec snake_case(binary()) -> binary().
snake_case(Name) ->
_pipe = Name,
_pipe@1 = string:lowercase(_pipe),
_pipe@2 = gleam@string:replace(_pipe@1, <<" "/utf8>>, <<"_"/utf8>>),
gleam@string:replace(_pipe@2, <<"-"/utf8>>, <<"_"/utf8>>).
-file("src/glsql/resolve.gleam", 168).
-spec is_nullable(glsql@ast:column(), boolean()) -> boolean().
is_nullable(Column, Primary_key) ->
Not_null = gleam@list:any(erlang:element(4, Column), fun(C) -> case C of
{not_null, _} ->
true;
_ ->
false
end end),
Serial = gleam@list:contains(
[<<"serial"/utf8>>, <<"bigserial"/utf8>>, <<"smallserial"/utf8>>],
string:lowercase(erlang:element(2, erlang:element(3, Column)))
),
not ((Not_null orelse Primary_key) orelse Serial).
-file("src/glsql/resolve.gleam", 159).
-spec has_primary_key(glsql@ast:column()) -> boolean().
has_primary_key(Column) ->
gleam@list:any(erlang:element(4, Column), fun(C) -> case C of
{primary_key, _} ->
true;
_ ->
false
end end).
-file("src/glsql/resolve.gleam", 144).
-spec lookup_type(binary(), integer(), glsql@config:config()) -> {ok,
glsql@mapping:type_mapping()} |
{error, glsql@error:error()}.
lookup_type(Name, Pos, Cfg) ->
Builtins = glsql@dialect@postgres:builtin_types(),
case gleam_stdlib:map_get(erlang:element(5, Cfg), Name) of
{ok, M} ->
{ok, M};
{error, nil} ->
case gleam_stdlib:map_get(Builtins, Name) of
{ok, M@1} ->
{ok, M@1};
{error, nil} ->
Candidates = lists:append(
maps:keys(Builtins),
maps:keys(erlang:element(5, Cfg))
),
{error,
{unknown_type,
Name,
Pos,
glsql@suggest:closest(Name, Candidates)}}
end
end.
-file("src/glsql/resolve.gleam", 96).
-spec resolve_column(
glsql@ast:column(),
glsql@ast:table(),
glsql@config:config()
) -> {ok, resolved_column()} | {error, glsql@error:error()}.
resolve_column(Column, Table, Cfg) ->
Type_name = string:lowercase(erlang:element(2, erlang:element(3, Column))),
gleam@result:'try'(
lookup_type(
Type_name,
erlang:element(5, erlang:element(3, Column)),
Cfg
),
fun(Base) ->
Primary_key = has_primary_key(Column),
Nullable = is_nullable(Column, Primary_key),
{Gleam_type, Decoder, Encoder} = case erlang:element(
4,
erlang:element(3, Column)
)
> 0 of
true ->
{<<<<"List("/utf8, (erlang:element(2, Base))/binary>>/binary,
")"/utf8>>,
<<<<"decode.list("/utf8,
(erlang:element(3, Base))/binary>>/binary,
")"/utf8>>,
erlang:element(4, Base)};
false ->
{erlang:element(2, Base),
erlang:element(3, Base),
erlang:element(4, Base)}
end,
{Gleam_type@1, Decoder@1} = case Nullable of
true ->
{<<<<"Option("/utf8, Gleam_type/binary>>/binary, ")"/utf8>>,
<<<<"decode.optional("/utf8, Decoder/binary>>/binary,
")"/utf8>>};
false ->
{Gleam_type, Decoder}
end,
Field_name = case gleam_stdlib:map_get(
erlang:element(6, Cfg),
<<<<(erlang:element(2, Table))/binary, "."/utf8>>/binary,
(erlang:element(2, Column))/binary>>
) of
{ok, New_name} ->
New_name;
{error, nil} ->
snake_case(erlang:element(2, Column))
end,
{ok,
{resolved_column,
erlang:element(2, Column),
Field_name,
Gleam_type@1,
Decoder@1,
Encoder,
Type_name,
Nullable,
Primary_key,
erlang:element(5, Base)}}
end
).
-file("src/glsql/resolve.gleam", 200).
-spec capitalise(binary()) -> binary().
capitalise(Word) ->
case gleam_stdlib:string_pop_grapheme(Word) of
{ok, {First, Rest}} ->
<<(string:uppercase(First))/binary, Rest/binary>>;
{error, nil} ->
Word
end.
-file("src/glsql/resolve.gleam", 193).
-spec pascal_case(binary()) -> binary().
pascal_case(Name) ->
_pipe = snake_case(Name),
_pipe@1 = gleam@string:split(_pipe, <<"_"/utf8>>),
_pipe@2 = gleam@list:map(_pipe@1, fun capitalise/1),
gleam@string:join(_pipe@2, <<""/utf8>>).
-file("src/glsql/resolve.gleam", 59).
-spec resolve_table(glsql@ast:table(), glsql@config:config()) -> {ok,
resolved_table()} |
{error, list(glsql@error:error())}.
resolve_table(Table, Cfg) ->
Naming = gleam_stdlib:map_get(
erlang:element(7, Cfg),
erlang:element(2, Table)
),
Module_name = case Naming of
{ok, {table_naming, {some, M}, _}} ->
M;
_ ->
snake_case(erlang:element(2, Table))
end,
Type_name = case Naming of
{ok, {table_naming, _, {some, T}}} ->
T;
_ ->
pascal_case(erlang:element(2, Table))
end,
Results = gleam@list:map(
erlang:element(4, Table),
fun(_capture) -> resolve_column(_capture, Table, Cfg) end
),
Errors = gleam@list:flat_map(Results, fun(R) -> case R of
{error, E} ->
[E];
{ok, _} ->
[]
end end),
case Errors of
[] ->
{ok,
{resolved_table,
erlang:element(2, Table),
Module_name,
Type_name,
gleam@list:filter_map(Results, fun(R@1) -> R@1 end)}};
_ ->
{error, Errors}
end.
-file("src/glsql/resolve.gleam", 40).
-spec resolve(glsql@ast:schema_ast(), glsql@config:config()) -> {ok,
resolved_schema()} |
{error, list(glsql@error:error())}.
resolve(Schema, Cfg) ->
Results = gleam@list:map(
erlang:element(2, Schema),
fun(_capture) -> resolve_table(_capture, Cfg) end
),
Errors = gleam@list:flat_map(Results, fun(R) -> case R of
{error, Errs} ->
Errs;
{ok, _} ->
[]
end end),
case Errors of
[] ->
{ok,
{resolved_schema,
gleam@list:filter_map(Results, fun(R@1) -> R@1 end)}};
_ ->
{error, Errors}
end.