Current section

Files

Jump to
sqlode src sqlode@codegen@common.erl
Raw

src/sqlode@codegen@common.erl

-module(sqlode@codegen@common).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/sqlode/codegen/common.gleam").
-export([has_slices/1, queries_have_slices/1, render_enum_or_set_decoder/2, qualified_field_type/2, queries_have_enum_params/1, queries_have_enums/1, custom_type_imports/1, result_scalar_types/1, param_scalar_types/1, catalog_scalar_types/1, escape_string/1, out_to_module_path/1, runtime_import_path/1, gleam_type/2, gleam_fn/4]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-file("src/sqlode/codegen/common.gleam", 9).
-spec has_slices(list(sqlode@model:query_param())) -> boolean().
has_slices(Params) ->
gleam@list:any(Params, fun(P) -> erlang:element(6, P) end).
-file("src/sqlode/codegen/common.gleam", 13).
-spec queries_have_slices(list(sqlode@model:analyzed_query())) -> boolean().
queries_have_slices(Queries) ->
gleam@list:any(
Queries,
fun(Query) -> has_slices(erlang:element(3, Query)) end
).
-file("src/sqlode/codegen/common.gleam", 23).
?DOC(
" Wrap the base decoder for `EnumType` and `SetType` columns so the\n"
" decoded value reaches the consuming record as the generated sum\n"
" type (or list of sum-type values for SET) rather than the raw\n"
" wire string. `fallback` is the decoder to use for every other\n"
" scalar type (adapter-specific in the caller — e.g. pog's\n"
" `decode.bool` vs sqlight's int-to-bool adapter).\n"
).
-spec render_enum_or_set_decoder(
sqlode@model:scalar_type(),
fun((sqlode@model:scalar_type()) -> binary())
) -> binary().
render_enum_or_set_decoder(Scalar_type, Fallback) ->
case Scalar_type of
{enum_type, Enum_name} ->
<<<<<<<<<<<<"decode.then(decode.string, fn(s) { case models."/utf8,
(sqlode@type_mapping:enum_from_string_fn(
Enum_name
))/binary>>/binary,
"(s) { Ok(v) -> decode.success(v) Error(_) -> decode.failure(models."/utf8>>/binary,
(sqlode@type_mapping:enum_default_fn(Enum_name))/binary>>/binary,
"(), \"valid "/utf8>>/binary,
Enum_name/binary>>/binary,
" value\") } })"/utf8>>;
{set_type, Set_name} ->
<<<<<<<<"decode.then(decode.string, fn(s) { case models."/utf8,
(sqlode@type_mapping:set_from_string_fn(Set_name))/binary>>/binary,
"(s) { Ok(v) -> decode.success(v) Error(_) -> decode.failure([], \"valid "/utf8>>/binary,
Set_name/binary>>/binary,
" set\") } })"/utf8>>;
_ ->
Fallback(Scalar_type)
end.
-file("src/sqlode/codegen/common.gleam", 58).
?DOC(
" Render a param / record field's Gleam type for generated modules\n"
" that are NOT `models.gleam` itself (currently `params.gleam` and\n"
" `queries.gleam`). They reach the generated `EnumType` / `SetType`\n"
" definitions through a plain `import db/models`, so every external\n"
" reference must be qualified with `models.` — the bare names only\n"
" work inside `models.gleam` where the types are declared.\n"
" `ArrayType` recurses so arrays of enum / set stay qualified.\n"
).
-spec qualified_field_type(
sqlode@model:scalar_type(),
sqlode@model:type_mapping()
) -> binary().
qualified_field_type(Scalar_type, Type_mapping_mode) ->
case Scalar_type of
{enum_type, _} ->
<<"models."/utf8,
(sqlode@type_mapping:scalar_type_to_gleam_type(
Scalar_type,
Type_mapping_mode
))/binary>>;
{set_type, Name} ->
<<<<"List(models."/utf8,
(sqlode@type_mapping:set_value_type_name(Name))/binary>>/binary,
")"/utf8>>;
{array_type, Element} ->
<<<<"List("/utf8,
(qualified_field_type(Element, Type_mapping_mode))/binary>>/binary,
")"/utf8>>;
_ ->
sqlode@type_mapping:scalar_type_to_gleam_type(
Scalar_type,
Type_mapping_mode
)
end.
-file("src/sqlode/codegen/common.gleam", 74).
-spec queries_have_enum_params(list(sqlode@model:analyzed_query())) -> boolean().
queries_have_enum_params(Queries) ->
gleam@list:any(
Queries,
fun(Query) ->
gleam@list:any(
erlang:element(3, Query),
fun(Param) -> case erlang:element(4, Param) of
{enum_type, _} ->
true;
{set_type, _} ->
true;
_ ->
false
end end
)
end
).
-file("src/sqlode/codegen/common.gleam", 85).
-spec queries_have_enums(list(sqlode@model:analyzed_query())) -> boolean().
queries_have_enums(Queries) ->
gleam@list:any(
Queries,
fun(Query) ->
gleam@list:any(
erlang:element(3, Query),
fun(Param) -> case erlang:element(4, Param) of
{enum_type, _} ->
true;
{set_type, _} ->
true;
_ ->
false
end end
)
orelse gleam@list:any(
erlang:element(4, Query),
fun(Col) -> case Col of
{scalar_result,
{result_column, _, {enum_type, _}, _, _}} ->
true;
{scalar_result, {result_column, _, {set_type, _}, _, _}} ->
true;
_ ->
false
end end
)
end
).
-file("src/sqlode/codegen/common.gleam", 110).
?DOC(" Collect import statements for module-qualified custom types from scalar types.\n").
-spec custom_type_imports(list(sqlode@model:scalar_type())) -> list(binary()).
custom_type_imports(Scalar_types) ->
_pipe = Scalar_types,
_pipe@1 = gleam@list:filter_map(_pipe, fun(St) -> case St of
{custom_type, Name, {some, Module}, _} ->
{ok,
<<<<<<<<"import "/utf8, Module/binary>>/binary,
".{type "/utf8>>/binary,
Name/binary>>/binary,
"}"/utf8>>};
_ ->
{error, nil}
end end),
_pipe@2 = gleam@list:unique(_pipe@1),
gleam@list:sort(_pipe@2, fun gleam@string:compare/2).
-file("src/sqlode/codegen/common.gleam", 124).
?DOC(" Collect all scalar types from query result columns.\n").
-spec result_scalar_types(list(sqlode@model:analyzed_query())) -> list(sqlode@model:scalar_type()).
result_scalar_types(Queries) ->
gleam@list:flat_map(
Queries,
fun(Query) ->
gleam@list:filter_map(
erlang:element(4, Query),
fun(Col) -> case Col of
{scalar_result, {result_column, _, Scalar_type, _, _}} ->
{ok, Scalar_type};
{embedded_result, {embedded_column, _, _, Columns}} ->
case gleam@list:find_map(
Columns,
fun(C) -> case erlang:element(3, C) of
{custom_type, _, _, _} ->
{ok, erlang:element(3, C)};
_ ->
{error, nil}
end end
) of
{ok, St} ->
{ok, St};
{error, _} ->
{error, nil}
end
end end
)
end
).
-file("src/sqlode/codegen/common.gleam", 150).
?DOC(" Collect all scalar types from query params.\n").
-spec param_scalar_types(list(sqlode@model:analyzed_query())) -> list(sqlode@model:scalar_type()).
param_scalar_types(Queries) ->
gleam@list:flat_map(
Queries,
fun(Query) ->
gleam@list:map(
erlang:element(3, Query),
fun(P) -> erlang:element(4, P) end
)
end
).
-file("src/sqlode/codegen/common.gleam", 159).
?DOC(" Collect all scalar types from catalog tables.\n").
-spec catalog_scalar_types(sqlode@model:catalog()) -> list(sqlode@model:scalar_type()).
catalog_scalar_types(Catalog) ->
gleam@list:flat_map(
erlang:element(2, Catalog),
fun(Table) ->
gleam@list:map(
erlang:element(3, Table),
fun(Col) -> erlang:element(3, Col) end
)
end
).
-file("src/sqlode/codegen/common.gleam", 165).
-spec escape_string(binary()) -> binary().
escape_string(Input) ->
_pipe = Input,
_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>>),
_pipe@4 = gleam@string:replace(_pipe@3, <<"\r"/utf8>>, <<"\\r"/utf8>>),
gleam@string:replace(_pipe@4, <<"\t"/utf8>>, <<"\\t"/utf8>>).
-file("src/sqlode/codegen/common.gleam", 177).
?DOC(
" Derive the Gleam module path from the output directory.\n"
" Strips the \"src/\" prefix so imports match the actual file location.\n"
" e.g. \"src/db\" -> \"db\", \"/abs/path/src/db\" -> \"db\"\n"
).
-spec out_to_module_path(binary()) -> binary().
out_to_module_path(Out) ->
case gleam_stdlib:string_starts_with(Out, <<"src/"/utf8>>) of
true ->
gleam@string:drop_start(Out, 4);
false ->
_pipe = gleam@string:split(Out, <<"/src/"/utf8>>),
_pipe@1 = gleam@list:last(_pipe),
gleam@result:unwrap(_pipe@1, Out)
end.
-file("src/sqlode/codegen/common.gleam", 192).
?DOC(
" Import path used by generated modules for the sqlode runtime. When\n"
" `gleam.vendor_runtime` is enabled, the runtime source is written\n"
" into `<out>/runtime.gleam` and the generated code points at that\n"
" local copy (e.g. `db/runtime`). Otherwise the shared\n"
" `sqlode/runtime` dependency is used.\n"
).
-spec runtime_import_path(sqlode@model:gleam_output()) -> binary().
runtime_import_path(Gleam) ->
case erlang:element(8, Gleam) of
true ->
<<(out_to_module_path(erlang:element(2, Gleam)))/binary,
"/runtime"/utf8>>;
false ->
<<"sqlode/runtime"/utf8>>
end.
-file("src/sqlode/codegen/common.gleam", 205).
?DOC(
" Render a single-constructor Gleam type declaration.\n"
"\n"
" gleam_type(\"UserId\", \"Int\") →\n"
" \"pub type UserId {\n"
" UserId(Int)\n"
" }\"\n"
).
-spec gleam_type(binary(), binary()) -> binary().
gleam_type(Name, Body) ->
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
<<<<"pub type "/utf8, Name/binary>>/binary, " {"/utf8>>
),
sqlode@codegen@builder:line(
<<<<<<<<" "/utf8, Name/binary>>/binary, "("/utf8>>/binary,
Body/binary>>/binary,
")"/utf8>>
),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).
-file("src/sqlode/codegen/common.gleam", 220).
?DOC(
" Render a Gleam function declaration as a single string.\n"
"\n"
" gleam_fn(\"double\", \"x: Int\", \"Int\", \"x * 2\") →\n"
" \"pub fn double(x: Int) -> Int {\n"
" x * 2\n"
" }\"\n"
).
-spec gleam_fn(binary(), binary(), binary(), binary()) -> binary().
gleam_fn(Name, Params, Return_type, Body) ->
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
<<<<<<<<<<<<"pub fn "/utf8, Name/binary>>/binary, "("/utf8>>/binary,
Params/binary>>/binary,
") -> "/utf8>>/binary,
Return_type/binary>>/binary,
" {"/utf8>>
),
sqlode@codegen@builder:line(<<" "/utf8, Body/binary>>),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).