Current section

Files

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

src/sqlode@codegen@adapter.erl

-module(sqlode@codegen@adapter).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/sqlode/codegen/adapter.gleam").
-export([render/4]).
-export_type([adapter_config/0, render_context/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 adapter_config() :: {adapter_config,
binary(),
binary(),
binary(),
fun((sqlode@model:scalar_type()) -> binary()),
fun((sqlode@model:scalar_type()) -> binary()),
fun((list(sqlode@model:query_param()), binary()) -> binary()),
fun((binary(), binary(), binary(), binary(), list(sqlode@model:query_param())) -> list(binary())),
fun(() -> list(binary())),
fun(() -> list(binary())),
fun(() -> list(binary())),
fun((binary(), binary(), binary(), list(sqlode@model:query_param())) -> list(binary())),
binary(),
binary(),
binary()}.
-type render_context() :: {render_context,
sqlode@naming:naming_context(),
adapter_config(),
gleam@dict:dict(binary(), binary()),
boolean(),
boolean(),
sqlode@model:type_mapping()}.
-file("src/sqlode/codegen/adapter.gleam", 139).
-spec pog_value_to_driver_helper() -> binary().
pog_value_to_driver_helper() ->
<<"fn value_to_pog(value: runtime.Value) -> pog.Value {
case value {
runtime.SqlNull -> pog.null()
runtime.SqlString(v) -> pog.text(v)
runtime.SqlInt(v) -> pog.int(v)
runtime.SqlFloat(v) -> pog.float(v)
runtime.SqlBool(v) -> pog.bool(v)
runtime.SqlBytes(v) -> pog.bytea(v)
runtime.SqlArray(vs) -> pog.array(value_to_pog, vs)
}
}"/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 153).
-spec sqlight_value_to_driver_helper() -> binary().
sqlight_value_to_driver_helper() ->
<<"fn value_to_sqlight(value: runtime.Value) -> sqlight.Value {
case value {
runtime.SqlNull -> sqlight.null()
runtime.SqlString(v) -> sqlight.text(v)
runtime.SqlInt(v) -> sqlight.int(v)
runtime.SqlFloat(v) -> sqlight.float(v)
runtime.SqlBool(v) -> sqlight.bool(v)
runtime.SqlBytes(v) -> sqlight.blob(v)
runtime.SqlArray(_) -> panic as \"SqlArray is not supported in the SQLite native adapter. Use raw runtime for array parameters, or ensure sqlode.slice() values are expanded before reaching value_to_sqlight.\"
}
}"/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 208).
?DOC(
" Encode a `runtime.Value` into a `shork.Value`. shork's public\n"
" `Value` type currently exposes constructors for bool / int / float\n"
" / text / null / calendar but not for bytes — so we add a private\n"
" `bit_array_to_shork` FFI binding that calls into `shork_ffi.coerce`\n"
" (the same underlying identity FFI that `shork.text` and friends\n"
" dispatch through) and pass `BitArray` parameters through unchanged.\n"
" The Erlang `mysql` library underneath stores them as `BLOB` /\n"
" `BINARY` byte-for-byte. `SqlArray` still resolves to NULL because\n"
" MySQL has no first-class array type.\n"
"\n"
" `SqlBool` is encoded as `shork.int(1 | 0)` rather than\n"
" `shork.bool(...)`. The Erlang `mysql` library expects integers 1/0\n"
" on the wire for `TINYINT(1)` / `BOOLEAN` columns; passing the\n"
" Gleam `True` / `False` atoms verbatim (which is what `shork.bool`\n"
" does — it is a `coerce` identity FFI) trips `mysql:query/4` with\n"
" `badarg` during parameter binding.\n"
).
-spec shork_value_to_driver_helper() -> binary().
shork_value_to_driver_helper() ->
<<"@external(erlang, \"shork_ffi\", \"coerce\")
fn bit_array_to_shork(value: BitArray) -> shork.Value
fn value_to_shork(value: runtime.Value) -> shork.Value {
case value {
runtime.SqlNull -> shork.null()
runtime.SqlString(v) -> shork.text(v)
runtime.SqlInt(v) -> shork.int(v)
runtime.SqlFloat(v) -> shork.float(v)
runtime.SqlBool(True) -> shork.int(1)
runtime.SqlBool(False) -> shork.int(0)
runtime.SqlBytes(v) -> bit_array_to_shork(v)
runtime.SqlArray(_) -> panic as \"SqlArray is not supported in the MySQL native adapter. Use raw runtime for array parameters, or ensure sqlode.slice() values are expanded before reaching value_to_shork.\"
}
}"/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 308).
?DOC(
" Render a single `value_to_pog` / `value_to_sqlight` function per\n"
" adapter file. Generated query functions fold the `runtime.Value`\n"
" list returned by `runtime.prepare` through this helper, so param\n"
" encoding lives in one place instead of being inlined per-param.\n"
).
-spec value_to_driver_helper(adapter_config()) -> binary().
value_to_driver_helper(Config) ->
erlang:element(14, Config).
-file("src/sqlode/codegen/adapter.gleam", 365).
-spec render_params_arg(
sqlode@naming:naming_context(),
sqlode@model:analyzed_query(),
boolean()
) -> binary().
render_params_arg(Naming_ctx, Query, Has_params) ->
case Has_params of
true ->
<<<<", p: params."/utf8,
(sqlode@naming:to_pascal_case(
Naming_ctx,
erlang:element(2, erlang:element(2, Query))
))/binary>>/binary,
"Params"/utf8>>;
false ->
<<""/utf8>>
end.
-file("src/sqlode/codegen/adapter.gleam", 455).
-spec render_base_decoder(
sqlode@model:scalar_type(),
adapter_config(),
sqlode@model:type_mapping()
) -> binary().
render_base_decoder(Scalar_type, Config, Type_mapping) ->
case Scalar_type of
{enum_type, _} ->
sqlode@codegen@common:render_enum_or_set_decoder(
Scalar_type,
erlang:element(6, Config)
);
{set_type, _} ->
sqlode@codegen@common:render_enum_or_set_decoder(
Scalar_type,
erlang:element(6, Config)
);
_ ->
case (Type_mapping =:= strong_mapping) andalso sqlode@type_mapping:is_rich_type(
Scalar_type
) of
true ->
Constructor = sqlode@type_mapping:scalar_type_to_gleam_type(
Scalar_type,
strong_mapping
),
<<<<<<<<"decode.map("/utf8,
((erlang:element(6, Config))(Scalar_type))/binary>>/binary,
", models."/utf8>>/binary,
Constructor/binary>>/binary,
")"/utf8>>;
false ->
(erlang:element(6, Config))(Scalar_type)
end
end.
-file("src/sqlode/codegen/adapter.gleam", 485).
-spec wrap_nullable_decoder(binary(), boolean()) -> binary().
wrap_nullable_decoder(Base_decoder, Nullable) ->
case Nullable of
true ->
<<<<"decode.optional("/utf8, Base_decoder/binary>>/binary,
")"/utf8>>;
false ->
Base_decoder
end.
-file("src/sqlode/codegen/adapter.gleam", 492).
-spec render_field_decode_line(
binary(),
integer(),
sqlode@model:scalar_type(),
boolean(),
adapter_config(),
sqlode@model:type_mapping()
) -> binary().
render_field_decode_line(
Field_name,
Idx,
Scalar_type,
Nullable,
Config,
Type_mapping
) ->
Full_decoder = begin
_pipe = render_base_decoder(Scalar_type, Config, Type_mapping),
wrap_nullable_decoder(_pipe, Nullable)
end,
<<<<<<<<<<<<" use "/utf8, Field_name/binary>>/binary,
" <- decode.field("/utf8>>/binary,
(erlang:integer_to_binary(Idx))/binary>>/binary,
", "/utf8>>/binary,
Full_decoder/binary>>/binary,
")"/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 512).
-spec render_embedded_column_lines(
render_context(),
binary(),
binary(),
list(sqlode@model:column()),
integer()
) -> {integer(), list(binary())}.
render_embedded_column_lines(Ctx, Embed_name, Table_name, Embed_cols, Start_idx) ->
Embed_field_name = sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
Embed_name
),
Embed_type_name = sqlode@naming:table_type_name(
erlang:element(2, Ctx),
Table_name,
erlang:element(6, Ctx)
),
Embed_lines = gleam@list:index_map(
Embed_cols,
fun(Embed_col, Embed_idx) ->
Full_decoder = begin
_pipe = render_base_decoder(
erlang:element(3, Embed_col),
erlang:element(3, Ctx),
erlang:element(7, Ctx)
),
wrap_nullable_decoder(_pipe, erlang:element(4, Embed_col))
end,
<<<<<<<<<<<<" use "/utf8,
(sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
erlang:element(2, Embed_col)
))/binary>>/binary,
" <- decode.field("/utf8>>/binary,
(erlang:integer_to_binary(Start_idx + Embed_idx))/binary>>/binary,
", "/utf8>>/binary,
Full_decoder/binary>>/binary,
")"/utf8>>
end
),
Embed_constructor_fields = begin
_pipe@1 = gleam@list:map(
Embed_cols,
fun(C) ->
<<(sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
erlang:element(2, C)
))/binary,
":"/utf8>>
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
Constructor_line = <<<<<<<<<<<<" let "/utf8, Embed_field_name/binary>>/binary,
" = models."/utf8>>/binary,
Embed_type_name/binary>>/binary,
"("/utf8>>/binary,
Embed_constructor_fields/binary>>/binary,
")"/utf8>>,
All_lines = lists:append(Embed_lines, [Constructor_line]),
{Start_idx + erlang:length(Embed_cols), All_lines}.
-file("src/sqlode/codegen/adapter.gleam", 379).
-spec render_decoder(render_context(), sqlode@model:analyzed_query(), binary()) -> binary().
render_decoder(Ctx, Query, Type_name) ->
case erlang:element(4, Query) of
[] ->
<<"decode.success(Nil)"/utf8>>;
Columns ->
{_, Field_lines} = gleam@list:fold(
Columns,
{0, []},
fun(Acc, Col) ->
{Idx, Lines} = Acc,
case Col of
{scalar_result,
{result_column, Name, Scalar_type, Nullable, _}} ->
Line = render_field_decode_line(
sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
Name
),
Idx,
Scalar_type,
Nullable,
erlang:element(3, Ctx),
erlang:element(7, Ctx)
),
{Idx + 1, lists:append(Lines, [Line])};
{embedded_result,
{embedded_column,
Embed_name,
Table_name,
Embed_cols}} ->
{New_idx, Embed_lines} = render_embedded_column_lines(
Ctx,
Embed_name,
Table_name,
Embed_cols,
Idx
),
{New_idx, lists:append(Lines, Embed_lines)}
end
end
),
Constructor_fields = begin
_pipe = Columns,
_pipe@1 = gleam@list:map(_pipe, fun(Col@1) -> case Col@1 of
{scalar_result, {result_column, Name@1, _, _, _}} ->
<<(sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
Name@1
))/binary,
":"/utf8>>;
{embedded_result, {embedded_column, Name@2, _, _}} ->
<<(sqlode@naming:to_snake_case(
erlang:element(2, Ctx),
Name@2
))/binary,
":"/utf8>>
end end),
gleam@string:join(_pipe@1, <<", "/utf8>>)
end,
_pipe@2 = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(<<"{"/utf8>>),
sqlode@codegen@builder:lines(Field_lines),
sqlode@codegen@builder:line(
<<<<<<<<" decode.success(models."/utf8,
Type_name/binary>>/binary,
"("/utf8>>/binary,
Constructor_fields/binary>>/binary,
"))"/utf8>>
),
sqlode@codegen@builder:line(<<" }"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe@2)
end.
-file("src/sqlode/codegen/adapter.gleam", 634).
?DOC(
" Render the `pub fn name(db: Conn, p: Params) -> Result(R, E) {` line\n"
" shared by every adapter query function. Keeping the signature in a\n"
" dedicated helper keeps the callers free of deep `<>` chains.\n"
).
-spec query_fn_signature(binary(), binary(), binary(), binary(), binary()) -> binary().
query_fn_signature(
Fn_name,
Connection_type,
Params_arg,
Return_type,
Error_type
) ->
<<<<<<<<<<<<<<<<<<"pub fn "/utf8, Fn_name/binary>>/binary, "(db: "/utf8>>/binary,
Connection_type/binary>>/binary,
Params_arg/binary>>/binary,
") -> Result("/utf8>>/binary,
Return_type/binary>>/binary,
", "/utf8>>/binary,
Error_type/binary>>/binary,
") {"/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 588).
-spec render_adapter_query_result(
render_context(),
sqlode@model:analyzed_query(),
binary(),
boolean(),
binary(),
fun(() -> list(binary()))
) -> binary().
render_adapter_query_result(
Ctx,
Query,
Fn_name,
Has_params,
Return_type_wrapper,
Render_result
) ->
Type_name = <<(sqlode@naming:to_pascal_case(
erlang:element(2, Ctx),
erlang:element(2, erlang:element(2, Query))
))/binary,
"Row"/utf8>>,
Constructor_name = case gleam_stdlib:map_get(
erlang:element(4, Ctx),
erlang:element(3, erlang:element(2, Query))
) of
{ok, Table_type} ->
Table_type;
{error, _} ->
Type_name
end,
Params_arg = render_params_arg(erlang:element(2, Ctx), Query, Has_params),
Params_str = (erlang:element(7, erlang:element(3, Ctx)))(
erlang:element(3, Query),
<<"p"/utf8>>
),
Decoder = render_decoder(Ctx, Query, Constructor_name),
Return_type = <<<<<<Return_type_wrapper/binary, "(models."/utf8>>/binary,
Type_name/binary>>/binary,
")"/utf8>>,
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
query_fn_signature(
Fn_name,
erlang:element(3, erlang:element(3, Ctx)),
Params_arg,
Return_type,
erlang:element(4, erlang:element(3, Ctx))
)
),
sqlode@codegen@builder:line(
<<<<" let q = queries."/utf8, Fn_name/binary>>/binary,
"()"/utf8>>
),
sqlode@codegen@builder:lines(
(erlang:element(8, erlang:element(3, Ctx)))(
Fn_name,
Params_str,
Decoder,
<<"q.sql"/utf8>>,
erlang:element(3, Query)
)
),
sqlode@codegen@builder:lines(Render_result()),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).
-file("src/sqlode/codegen/adapter.gleam", 556).
-spec render_adapter_one(
render_context(),
sqlode@model:analyzed_query(),
binary(),
boolean()
) -> binary().
render_adapter_one(Ctx, Query, Fn_name, Has_params) ->
render_adapter_query_result(
Ctx,
Query,
Fn_name,
Has_params,
<<"Option"/utf8>>,
erlang:element(9, erlang:element(3, Ctx))
).
-file("src/sqlode/codegen/adapter.gleam", 572).
-spec render_adapter_many(
render_context(),
sqlode@model:analyzed_query(),
binary(),
boolean()
) -> binary().
render_adapter_many(Ctx, Query, Fn_name, Has_params) ->
render_adapter_query_result(
Ctx,
Query,
Fn_name,
Has_params,
<<"List"/utf8>>,
erlang:element(10, erlang:element(3, Ctx))
).
-file("src/sqlode/codegen/adapter.gleam", 653).
-spec render_adapter_exec(
sqlode@naming:naming_context(),
sqlode@model:analyzed_query(),
binary(),
boolean(),
adapter_config()
) -> binary().
render_adapter_exec(Naming_ctx, Query, Fn_name, Has_params, Config) ->
Params_arg = render_params_arg(Naming_ctx, Query, Has_params),
Params_str = (erlang:element(7, Config))(
erlang:element(3, Query),
<<"p"/utf8>>
),
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
query_fn_signature(
Fn_name,
erlang:element(3, Config),
Params_arg,
<<"Nil"/utf8>>,
erlang:element(4, Config)
)
),
sqlode@codegen@builder:line(
<<<<" let q = queries."/utf8, Fn_name/binary>>/binary,
"()"/utf8>>
),
sqlode@codegen@builder:lines(
(erlang:element(8, Config))(
Fn_name,
Params_str,
<<"decode.success(Nil)"/utf8>>,
<<"q.sql"/utf8>>,
erlang:element(3, Query)
)
),
sqlode@codegen@builder:line(
<<" |> result.map(fn(_) { Nil })"/utf8>>
),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).
-file("src/sqlode/codegen/adapter.gleam", 685).
-spec render_adapter_exec_rows(
sqlode@naming:naming_context(),
sqlode@model:analyzed_query(),
binary(),
boolean(),
adapter_config()
) -> binary().
render_adapter_exec_rows(Naming_ctx, Query, Fn_name, Has_params, Config) ->
Params_arg = render_params_arg(Naming_ctx, Query, Has_params),
Params_str = (erlang:element(7, Config))(
erlang:element(3, Query),
<<"p"/utf8>>
),
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
query_fn_signature(
Fn_name,
erlang:element(3, Config),
Params_arg,
<<"Int"/utf8>>,
erlang:element(4, Config)
)
),
sqlode@codegen@builder:line(
<<<<" let q = queries."/utf8, Fn_name/binary>>/binary,
"()"/utf8>>
),
sqlode@codegen@builder:lines(
(erlang:element(8, Config))(
Fn_name,
Params_str,
erlang:element(15, Config),
<<"q.sql"/utf8>>,
erlang:element(3, Query)
)
),
sqlode@codegen@builder:lines((erlang:element(11, Config))()),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).
-file("src/sqlode/codegen/adapter.gleam", 717).
-spec render_adapter_exec_last_id(
sqlode@naming:naming_context(),
sqlode@model:analyzed_query(),
binary(),
boolean(),
adapter_config()
) -> binary().
render_adapter_exec_last_id(Naming_ctx, Query, Fn_name, Has_params, Config) ->
Params_arg = render_params_arg(Naming_ctx, Query, Has_params),
Params_str = (erlang:element(7, Config))(
erlang:element(3, Query),
<<"p"/utf8>>
),
_pipe = sqlode@codegen@builder:concat(
[sqlode@codegen@builder:line(
query_fn_signature(
Fn_name,
erlang:element(3, Config),
Params_arg,
<<"Int"/utf8>>,
erlang:element(4, Config)
)
),
sqlode@codegen@builder:line(
<<<<" let q = queries."/utf8, Fn_name/binary>>/binary,
"()"/utf8>>
),
sqlode@codegen@builder:lines(
(erlang:element(12, Config))(
Fn_name,
Params_str,
<<"q.sql"/utf8>>,
erlang:element(3, Query)
)
),
sqlode@codegen@builder:line(<<"}"/utf8>>)]
),
sqlode@codegen@builder:render(_pipe).
-file("src/sqlode/codegen/adapter.gleam", 312).
-spec render_adapter_function(render_context(), sqlode@model:analyzed_query()) -> binary().
render_adapter_function(Ctx, Query) ->
Fn_name = erlang:element(3, erlang:element(2, Query)),
Has_params = not gleam@list:is_empty(erlang:element(3, Query)),
Comment = case erlang:element(5, Ctx) of
true ->
<<<<"// SQL: "/utf8,
(erlang:element(5, erlang:element(2, Query)))/binary>>/binary,
"\n"/utf8>>;
false ->
<<""/utf8>>
end,
<<Comment/binary, (case erlang:element(4, erlang:element(2, Query)) of
query_one ->
render_adapter_one(Ctx, Query, Fn_name, Has_params);
query_batch_one ->
render_adapter_one(Ctx, Query, Fn_name, Has_params);
query_many ->
render_adapter_many(Ctx, Query, Fn_name, Has_params);
query_batch_many ->
render_adapter_many(Ctx, Query, Fn_name, Has_params);
query_exec ->
render_adapter_exec(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
);
query_batch_exec ->
render_adapter_exec(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
);
query_copy_from ->
render_adapter_exec(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
);
query_exec_result ->
render_adapter_exec(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
);
query_exec_rows ->
render_adapter_exec_rows(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
);
query_exec_last_id ->
render_adapter_exec_last_id(
erlang:element(2, Ctx),
Query,
Fn_name,
Has_params,
erlang:element(3, Ctx)
)
end)/binary>>.
-file("src/sqlode/codegen/adapter.gleam", 769).
?DOC(
" No longer generates per-param `pog.parameter(...)` lines. Every\n"
" generated query now reuses `runtime.prepare(q, p)` and folds the\n"
" returned values through `value_to_pog`, so the param-string is\n"
" redundant. Kept for the `AdapterConfig.render_params` field so the\n"
" wider shape of the config record does not shift in this change.\n"
).
-spec render_pog_params(list(sqlode@model:query_param()), binary()) -> binary().
render_pog_params(_, _) ->
<<""/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 779).
?DOC(
" Shared prepare-and-fold block used by every pog/sqlight query\n"
" function. Emits one of two shapes depending on whether the query\n"
" takes parameters: when it does, unpack `runtime.prepare(q, p)` and\n"
" fold the returned values into `<driver>.query(sql)` through\n"
" `value_to_<driver>`. When it does not, call `prepare(q, Nil)` and\n"
" skip the fold entirely.\n"
).
-spec render_prepare_lines(binary(), binary(), list(sqlode@model:query_param())) -> list(binary()).
render_prepare_lines(Driver, Value_to_driver, Params) ->
case gleam@list:is_empty(Params) of
true ->
[<<" let #(sql, _values) = runtime.prepare(q, Nil)"/utf8>>,
<<<<" "/utf8, Driver/binary>>/binary, ".query(sql)"/utf8>>];
false ->
[<<" let #(sql, values) = runtime.prepare(q, p)"/utf8>>,
<<<<" let query = "/utf8, Driver/binary>>/binary,
".query(sql)"/utf8>>,
<<<<<<<<" let query = list.fold(values, query, fn(acc, v) { "/utf8,
Driver/binary>>/binary,
".parameter(acc, "/utf8>>/binary,
Value_to_driver/binary>>/binary,
"(v)) })"/utf8>>,
<<" query"/utf8>>]
end.
-file("src/sqlode/codegen/adapter.gleam", 751).
-spec render_pog_query_call(
binary(),
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_pog_query_call(_, _, Decoder, _, Params) ->
lists:append(
[render_prepare_lines(<<"pog"/utf8>>, <<"value_to_pog"/utf8>>, Params),
[<<<<" |> pog.returning("/utf8, Decoder/binary>>/binary, ")"/utf8>>,
<<" |> pog.execute(db)"/utf8>>]]
).
-file("src/sqlode/codegen/adapter.gleam", 806).
-spec render_pog_many_result() -> list(binary()).
render_pog_many_result() ->
[<<" |> result.map(fn(returned) { returned.rows })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 810).
-spec render_pog_exec_rows_result() -> list(binary()).
render_pog_exec_rows_result() ->
[<<" |> result.map(fn(returned) { returned.count })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 842).
-spec render_sqlight_query_call(
binary(),
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_sqlight_query_call(_, _, Decoder, _, Params) ->
Prepare_line = case gleam@list:is_empty(Params) of
true ->
<<" let #(sql, values) = runtime.prepare(q, Nil)"/utf8>>;
false ->
<<" let #(sql, values) = runtime.prepare(q, p)"/utf8>>
end,
[Prepare_line,
<<" sqlight.query("/utf8>>,
<<" sql,"/utf8>>,
<<" on: db,"/utf8>>,
<<" with: list.map(values, value_to_sqlight),"/utf8>>,
<<<<" expecting: "/utf8, Decoder/binary>>/binary, ","/utf8>>,
<<" )"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 866).
?DOC(
" Unused under the prepare-and-fold adapter shape; see\n"
" `render_pog_params` for the rationale.\n"
).
-spec render_sqlight_params(list(sqlode@model:query_param()), binary()) -> binary().
render_sqlight_params(_, _) ->
<<""/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 877).
-spec render_sqlight_many_result() -> list(binary()).
render_sqlight_many_result() ->
[].
-file("src/sqlode/codegen/adapter.gleam", 942).
-spec render_shork_query_call(
binary(),
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_shork_query_call(_, _, Decoder, _, Params) ->
lists:append(
[render_prepare_lines(
<<"shork"/utf8>>,
<<"value_to_shork"/utf8>>,
Params
),
[<<<<" |> shork.returning("/utf8, Decoder/binary>>/binary,
")"/utf8>>,
<<" |> shork.execute(db)"/utf8>>]]
).
-file("src/sqlode/codegen/adapter.gleam", 957).
?DOC(
" Unused under the prepare-and-fold adapter shape; kept so the\n"
" AdapterConfig record shape stays uniform across drivers.\n"
).
-spec render_shork_params(list(sqlode@model:query_param()), binary()) -> binary().
render_shork_params(_, _) ->
<<""/utf8>>.
-file("src/sqlode/codegen/adapter.gleam", 968).
-spec render_shork_many_result() -> list(binary()).
render_shork_many_result() ->
[<<" |> result.map(fn(returned) { returned.rows })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 974).
?DOC(
" `:execrows` — shork's synthetic INSERT/UPDATE/DELETE row has\n"
" `affected_rows` in column index 1.\n"
).
-spec render_shork_exec_rows_result() -> list(binary()).
render_shork_exec_rows_result() ->
[<<" |> result.map(fn(returned) {"/utf8>>,
<<" case returned.rows {"/utf8>>,
<<" [rows, ..] -> rows"/utf8>>,
<<" [] -> 0"/utf8>>,
<<" }"/utf8>>,
<<" })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 1010).
-spec render_one_result_with(binary(), binary()) -> list(binary()).
render_one_result_with(Param, Rows_expr) ->
[<<<<" |> result.map(fn("/utf8, Param/binary>>/binary, ") {"/utf8>>,
<<<<" case "/utf8, Rows_expr/binary>>/binary, " {"/utf8>>,
<<" [row, ..] -> Some(row)"/utf8>>,
<<" [] -> None"/utf8>>,
<<" }"/utf8>>,
<<" })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 802).
-spec render_pog_one_result() -> list(binary()).
render_pog_one_result() ->
render_one_result_with(<<"returned"/utf8>>, <<"returned.rows"/utf8>>).
-file("src/sqlode/codegen/adapter.gleam", 873).
-spec render_sqlight_one_result() -> list(binary()).
render_sqlight_one_result() ->
render_one_result_with(<<"rows"/utf8>>, <<"rows"/utf8>>).
-file("src/sqlode/codegen/adapter.gleam", 964).
-spec render_shork_one_result() -> list(binary()).
render_shork_one_result() ->
render_one_result_with(<<"returned"/utf8>>, <<"returned.rows"/utf8>>).
-file("src/sqlode/codegen/adapter.gleam", 1021).
-spec render_first_or_default(binary(), binary(), binary()) -> list(binary()).
render_first_or_default(Param, Rows_expr, Default) ->
[<<<<" |> result.map(fn("/utf8, Param/binary>>/binary, ") {"/utf8>>,
<<<<" case "/utf8, Rows_expr/binary>>/binary, " {"/utf8>>,
<<" [id, ..] -> id"/utf8>>,
<<" [] -> "/utf8, Default/binary>>,
<<" }"/utf8>>,
<<" })"/utf8>>].
-file("src/sqlode/codegen/adapter.gleam", 814).
-spec render_pog_exec_last_id(
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_pog_exec_last_id(_, _, _, Params) ->
Result_lines = [<<" |> pog.returning({"/utf8>>,
<<" use id <- decode.field(0, decode.int)"/utf8>>,
<<" decode.success(id)"/utf8>>,
<<" })"/utf8>>,
<<" |> pog.execute(db)"/utf8>> |
render_first_or_default(
<<"returned"/utf8>>,
<<"returned.rows"/utf8>>,
<<"0"/utf8>>
)],
lists:append(
[render_prepare_lines(<<"pog"/utf8>>, <<"value_to_pog"/utf8>>, Params),
Result_lines]
).
-file("src/sqlode/codegen/adapter.gleam", 98).
-spec pog_adapter_config() -> adapter_config().
pog_adapter_config() ->
{adapter_config,
<<"import pog"/utf8>>,
<<"pog.Connection"/utf8>>,
<<"pog.QueryError"/utf8>>,
fun(_capture) ->
sqlode@type_mapping:scalar_type_to_value_function(
postgre_s_q_l,
_capture
)
end,
fun(_capture@1) ->
sqlode@type_mapping:scalar_type_to_decoder(
postgre_s_q_l,
_capture@1
)
end,
fun render_pog_params/2,
fun render_pog_query_call/5,
fun render_pog_one_result/0,
fun render_pog_many_result/0,
fun render_pog_exec_rows_result/0,
fun render_pog_exec_last_id/4,
<<"$"/utf8>>,
pog_value_to_driver_helper(),
<<"decode.success(Nil)"/utf8>>}.
-file("src/sqlode/codegen/adapter.gleam", 881).
-spec render_sqlight_exec_rows_result() -> list(binary()).
render_sqlight_exec_rows_result() ->
lists:append(
[[<<" |> result.try(fn(_) {"/utf8>>,
<<" sqlight.query("/utf8>>,
<<" \"SELECT changes()\","/utf8>>,
<<" on: db,"/utf8>>,
<<" with: [],"/utf8>>,
<<" expecting: decode.at([0], decode.int),"/utf8>>,
<<" )"/utf8>>,
<<" })"/utf8>>],
render_first_or_default(
<<"rows"/utf8>>,
<<"rows"/utf8>>,
<<"0"/utf8>>
)]
).
-file("src/sqlode/codegen/adapter.gleam", 897).
-spec render_sqlight_exec_last_id(
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_sqlight_exec_last_id(_, _, _, Params) ->
Prepare_line = case gleam@list:is_empty(Params) of
true ->
<<" let #(sql, values) = runtime.prepare(q, Nil)"/utf8>>;
false ->
<<" let #(sql, values) = runtime.prepare(q, p)"/utf8>>
end,
lists:append(
[[Prepare_line,
<<" sqlight.query("/utf8>>,
<<" sql,"/utf8>>,
<<" on: db,"/utf8>>,
<<" with: list.map(values, value_to_sqlight),"/utf8>>,
<<" expecting: decode.success(Nil),"/utf8>>,
<<" )"/utf8>>,
<<" |> result.try(fn(_) {"/utf8>>,
<<" sqlight.query("/utf8>>,
<<" \"SELECT last_insert_rowid()\","/utf8>>,
<<" on: db,"/utf8>>,
<<" with: [],"/utf8>>,
<<" expecting: decode.at([0], decode.int),"/utf8>>,
<<" )"/utf8>>,
<<" })"/utf8>>],
render_first_or_default(
<<"rows"/utf8>>,
<<"rows"/utf8>>,
<<"0"/utf8>>
)]
).
-file("src/sqlode/codegen/adapter.gleam", 120).
-spec sqlight_adapter_config() -> adapter_config().
sqlight_adapter_config() ->
{adapter_config,
<<"import sqlight"/utf8>>,
<<"sqlight.Connection"/utf8>>,
<<"sqlight.Error"/utf8>>,
fun(_capture) ->
sqlode@type_mapping:scalar_type_to_value_function(
s_q_lite,
_capture
)
end,
fun(_capture@1) ->
sqlode@type_mapping:scalar_type_to_decoder(s_q_lite, _capture@1)
end,
fun render_sqlight_params/2,
fun render_sqlight_query_call/5,
fun render_sqlight_one_result/0,
fun render_sqlight_many_result/0,
fun render_sqlight_exec_rows_result/0,
fun render_sqlight_exec_last_id/4,
<<"?"/utf8>>,
sqlight_value_to_driver_helper(),
<<"decode.success(Nil)"/utf8>>}.
-file("src/sqlode/codegen/adapter.gleam", 987).
?DOC(
" `:execlastid` — shork's synthetic INSERT row has\n"
" `last_insert_id` in column index 0. No follow-up SELECT needed.\n"
).
-spec render_shork_exec_last_id(
binary(),
binary(),
binary(),
list(sqlode@model:query_param())
) -> list(binary()).
render_shork_exec_last_id(_, _, _, Params) ->
lists:append(
[render_prepare_lines(
<<"shork"/utf8>>,
<<"value_to_shork"/utf8>>,
Params
),
[<<" |> shork.returning({"/utf8>>,
<<" use id <- decode.field(0, decode.int)"/utf8>>,
<<" decode.success(id)"/utf8>>,
<<" })"/utf8>>,
<<" |> shork.execute(db)"/utf8>>],
render_first_or_default(
<<"returned"/utf8>>,
<<"returned.rows"/utf8>>,
<<"0"/utf8>>
)]
).
-file("src/sqlode/codegen/adapter.gleam", 167).
-spec shork_adapter_config() -> adapter_config().
shork_adapter_config() ->
{adapter_config,
<<"import shork"/utf8>>,
<<"shork.Connection"/utf8>>,
<<"shork.QueryError"/utf8>>,
fun(_capture) ->
sqlode@type_mapping:scalar_type_to_value_function(
my_s_q_l,
_capture
)
end,
fun(_capture@1) ->
sqlode@type_mapping:scalar_type_to_decoder(my_s_q_l, _capture@1)
end,
fun render_shork_params/2,
fun render_shork_query_call/5,
fun render_shork_one_result/0,
fun render_shork_many_result/0,
fun render_shork_exec_rows_result/0,
fun render_shork_exec_last_id/4,
<<"?"/utf8>>,
shork_value_to_driver_helper(),
<<"{
use affected <- decode.field(1, decode.int)
decode.success(affected)
}"/utf8>>}.
-file("src/sqlode/codegen/adapter.gleam", 1084).
-spec adapter_query_uses_option_constructors(sqlode@model:analyzed_query()) -> boolean().
adapter_query_uses_option_constructors(Query) ->
(erlang:element(4, erlang:element(2, Query)) =:= query_one) orelse (erlang:element(
4,
erlang:element(2, Query)
)
=:= query_batch_one).
-file("src/sqlode/codegen/adapter.gleam", 1061).
-spec adapter_needs_option_type(list(sqlode@model:analyzed_query())) -> boolean().
adapter_needs_option_type(Queries) ->
gleam@list:any(
Queries,
fun(Query) ->
Has_nullable_params = gleam@list:any(
erlang:element(3, Query),
fun(Param) -> erlang:element(5, Param) end
),
Has_nullable_results = gleam@list:any(
erlang:element(4, Query),
fun(Col) -> case Col of
{scalar_result, {result_column, _, _, true, _}} ->
true;
{scalar_result, _} ->
false;
{embedded_result, {embedded_column, _, _, Columns}} ->
gleam@list:any(
Columns,
fun(C) -> erlang:element(4, C) end
)
end end
),
(Has_nullable_params orelse Has_nullable_results) orelse adapter_query_uses_option_constructors(
Query
)
end
).
-file("src/sqlode/codegen/adapter.gleam", 1080).
-spec adapter_needs_option_constructors(list(sqlode@model:analyzed_query())) -> boolean().
adapter_needs_option_constructors(Queries) ->
gleam@list:any(Queries, fun adapter_query_uses_option_constructors/1).
-file("src/sqlode/codegen/adapter.gleam", 1046).
?DOC(
" Emit a `gleam/option` import line tailored to what the generated\n"
" adapter actually references. The `Option` type is needed\n"
" whenever any param / result column is nullable or whenever any\n"
" query is `QueryOne` / `QueryBatchOne` (the wrapper returns\n"
" `Option(Row)`); the `None` / `Some` constructors are only\n"
" referenced by the `QueryOne` / `QueryBatchOne` row-list match\n"
" (`[row, ..] -> Some(row)` / `[] -> None`). Pulling unused\n"
" constructors into the import trips `gleam build`'s unused-import\n"
" warnings under `warnings_as_errors`, which downstream users\n"
" cannot fix because the file is `// DO NOT EDIT`. (#463)\n"
).
-spec adapter_option_import(list(sqlode@model:analyzed_query())) -> list(binary()).
adapter_option_import(Queries) ->
Needs_type = adapter_needs_option_type(Queries),
Needs_constructors = adapter_needs_option_constructors(Queries),
case {Needs_type, Needs_constructors} of
{false, false} ->
[];
{true, true} ->
[<<"import gleam/option.{type Option, None, Some}"/utf8>>];
{true, false} ->
[<<"import gleam/option.{type Option}"/utf8>>];
{false, true} ->
[<<"import gleam/option.{None, Some}"/utf8>>]
end.
-file("src/sqlode/codegen/adapter.gleam", 230).
-spec render_adapter(
sqlode@naming:naming_context(),
sqlode@model:sql_block(),
list(sqlode@model:analyzed_query()),
gleam@dict:dict(binary(), binary()),
adapter_config()
) -> binary().
render_adapter(Naming_ctx, Block, Queries, Table_matches, Config) ->
{sql_block, _, _, _, _, Gleam, _} = Block,
{gleam_output, Out, _, _, _, _, _, _, _, _} = Gleam,
Module_path = sqlode@codegen@common:out_to_module_path(Out),
Has_results = gleam@list:any(
Queries,
fun(Query) ->
sqlode@model:is_result_command(
erlang:element(4, erlang:element(2, Query))
)
andalso not gleam@list:is_empty(erlang:element(4, Query))
end
),
Has_params = gleam@list:any(
Queries,
fun(Q) -> not gleam@list:is_empty(erlang:element(3, Q)) end
),
Has_enums = sqlode@codegen@common:queries_have_enums(Queries),
Imports = lists:append(
[[<<"// Code generated by sqlode. DO NOT EDIT."/utf8>>,
<<""/utf8>>,
<<"import gleam/dynamic/decode"/utf8>>],
case Has_params of
true ->
[<<"import gleam/list"/utf8>>];
false ->
[]
end,
[<<"import gleam/result"/utf8>>],
adapter_option_import(Queries),
[erlang:element(2, Config)],
[<<"import "/utf8,
(sqlode@codegen@common:runtime_import_path(Gleam))/binary>>],
case Has_results orelse Has_enums of
true ->
[<<<<"import "/utf8, Module_path/binary>>/binary,
"/models"/utf8>>];
false ->
[]
end,
case gleam@list:any(
Queries,
fun(Q@1) -> not gleam@list:is_empty(erlang:element(3, Q@1)) end
) of
true ->
[<<<<"import "/utf8, Module_path/binary>>/binary,
"/params"/utf8>>];
false ->
[]
end,
[<<<<"import "/utf8, Module_path/binary>>/binary, "/queries"/utf8>>]]
),
Ctx = {render_context,
Naming_ctx,
Config,
Table_matches,
erlang:element(5, Gleam),
erlang:element(6, Gleam),
erlang:element(4, Gleam)},
Functions = begin
_pipe = Queries,
_pipe@1 = gleam@list:map(
_pipe,
fun(_capture) -> render_adapter_function(Ctx, _capture) end
),
gleam@string:join(_pipe@1, <<"\n\n"/utf8>>)
end,
Helper = value_to_driver_helper(Config),
gleam@string:join(
lists:append([Imports, [<<""/utf8>>, Helper, <<""/utf8>>, Functions]]),
<<"\n"/utf8>>
).
-file("src/sqlode/codegen/adapter.gleam", 60).
-spec render(
sqlode@naming:naming_context(),
sqlode@model:sql_block(),
list(sqlode@model:analyzed_query()),
gleam@dict:dict(binary(), binary())
) -> binary().
render(Naming_ctx, Block, Queries, Table_matches) ->
case erlang:element(3, Block) of
postgre_s_q_l ->
render_adapter(
Naming_ctx,
Block,
Queries,
Table_matches,
pog_adapter_config()
);
s_q_lite ->
render_adapter(
Naming_ctx,
Block,
Queries,
Table_matches,
sqlight_adapter_config()
);
my_s_q_l ->
render_adapter(
Naming_ctx,
Block,
Queries,
Table_matches,
shork_adapter_config()
)
end.