-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.