-module(refrakt@cli@gen). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/refrakt/cli/gen.gleam"). -export([island/1, parse_fields/1, to_gleam_type/1, to_sql_type/1, live/1, resource/2, migration/1, auth/0, page/1]). -file("src/refrakt/cli/gen.gleam", 397). -spec live_socket(binary(), binary()) -> binary(). live_socket(App, Name) -> <<<<<<<<<<<<<<<<<<<<"/// WebSocket transport for the "/utf8, Name/binary>>/binary, " server component. /// /// This module handles the WebSocket connection between the Lustre /// server component and the browser client runtime. /// /// ## Setup /// /// 1. Add the WebSocket route to router.gleam. Because WebSocket /// upgrades bypass Wisp, handle it before the Wisp handler in /// your main module: /// /// ```gleam /// // In src/.gleam, before the wisp_mist.handler: /// import "/utf8>>/binary, App/binary>>/binary, "/web/live/"/utf8>>/binary, Name/binary>>/binary, "_socket /// /// // In the mist handler, check for WS upgrade: /// fn handle(req) { /// case request.path_segments(req) { /// [\""/utf8>>/binary, Name/binary>>/binary, "\", \"ws\"] -> "/utf8>>/binary, Name/binary>>/binary, "_socket.upgrade(req) /// _ -> wisp_handler(req) /// } /// } /// ``` /// /// 2. Start a Lustre factory supervisor in your main module to /// manage server component instances. /// /// See: https://hexdocs.pm/lustre/lustre/server_component.html /// import gleam/erlang/process import gleam/http/request.{type Request} import gleam/http/response import gleam/json import gleam/option.{None} import lustre/server_component import mist.{type Connection, type ResponseData} /// WebSocket connection state. pub type State { State } /// Upgrade an HTTP request to a WebSocket for the server component. pub fn upgrade( req: Request(Connection), ) -> response.Response(ResponseData) { mist.websocket( request: req, handler: fn(state, msg, conn) { case msg { mist.Text(text) -> { // Decode event from client and dispatch to server runtime // TODO: wire to your Lustre runtime Subject // case json.parse(text, server_component.runtime_message_decoder()) { // Ok(runtime_msg) -> process.send(runtime, runtime_msg) // Error(_) -> Nil // } mist.continue(state) } mist.Binary(_) -> mist.continue(state) mist.Custom(_) -> mist.continue(state) mist.Closed | mist.Shutdown -> mist.stop() } }, on_init: fn(_conn) { // TODO: Start a Lustre server component instance here. // Use lustre.supervised() or lustre.factory() to create // a managed runtime, then register a callback to send // patches over the WebSocket: // // server_component.register_callback(fn(msg) { // let patch = server_component.client_message_to_json(msg) // mist.send_text_frame(conn, json.to_string(patch)) // }) #(State, None) }, on_close: fn(_state) { Nil }, ) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 567). -spec island_module(binary()) -> binary(). island_module(Name) -> <<<<<<<<"/// Interactive island: "/utf8, Name/binary>>/binary, " /// /// This is a Lustre client-side app. Compile to JavaScript with: /// gleam build --target javascript /// import gleam/int import lustre import lustre/element.{text} import lustre/element/html.{button, div, p} import lustre/event pub type Model { Model(count: Int) } pub type Msg { Increment Decrement } pub fn init(_flags: Nil) -> Model { Model(count: 0) } pub fn update(model: Model, msg: Msg) -> Model { case msg { Increment -> Model(count: model.count + 1) Decrement -> Model(count: model.count - 1) } } pub fn view(model: Model) -> element.Element(Msg) { div([], [ button([event.on_click(Decrement)], [text(\"-\")]), p([], [text(int.to_string(model.count))]), button([event.on_click(Increment)], [text(\"+\")]), ]) } pub fn main() { let app = lustre.simple(init, update, view) let assert Ok(_) = lustre.start(app, \"#"/utf8>>/binary, Name/binary>>/binary, "\", Nil) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 614). -spec island_embed(binary(), binary()) -> binary(). island_embed(_, Name) -> <<<<<<<<<<<<"/// Server-side helper to embed the "/utf8, Name/binary>>/binary, " island in a view. /// import lustre/attribute.{id, src} import lustre/element.{type Element, text} import lustre/element/html.{div, script} /// Render the mount point for the island. pub fn render() -> Element(Nil) { div([id(\""/utf8>>/binary, Name/binary>>/binary, "\")], [text(\"Loading...\")]) } /// Render the script tag that loads the island JS. pub fn script_tag() -> Element(Nil) { script([src(\"/static/js/islands/"/utf8>>/binary, Name/binary>>/binary, ".js\")], \"\") } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 540). -spec island(binary()) -> nil. island(Name) -> App = refrakt@cli@project:app_name(), Island_dir = <<<<"src/"/utf8, App/binary>>/binary, "/web/islands"/utf8>>, _ = simplifile:create_directory_all(Island_dir), Island_path = <<<<<>/binary, Name/binary>>/binary, ".gleam"/utf8>>, Embed_path = <<<<<>/binary, Name/binary>>/binary, "_embed.gleam"/utf8>>, case simplifile:write(Island_path, island_module(Name)) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"island"/utf8>>, line => 549, value => _assert_fail, start => 16235, 'end' => 16304, pattern_start => 16246, pattern_end => 16251}) end, case simplifile:write(Embed_path, island_embed(App, Name)) of {ok, _} -> nil; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"island"/utf8>>, line => 550, value => _assert_fail@1, start => 16307, 'end' => 16379, pattern_start => 16318, pattern_end => 16323}) end, refrakt_format_ffi:format_files([Island_path, Embed_path]), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Island_path/binary>>), gleam_stdlib:println(<<" "/utf8, Embed_path/binary>>), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Usage in a view:"/utf8>>), gleam_stdlib:println( <<<<<<<<" import "/utf8, App/binary>>/binary, "/web/islands/"/utf8>>/binary, Name/binary>>/binary, "_embed"/utf8>> ), gleam_stdlib:println( <<<<" "/utf8, Name/binary>>/binary, "_embed.render()"/utf8>> ), gleam_stdlib:println( <<<<" "/utf8, Name/binary>>/binary, "_embed.script_tag()"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Build the island JS:"/utf8>>), gleam_stdlib:println(<<" gleam build --target javascript"/utf8>>). -file("src/refrakt/cli/gen.gleam", 661). -spec api_resource_handler( binary(), binary(), binary(), binary(), refrakt@cli@types:db_choice(), list({binary(), binary()}) ) -> binary(). api_resource_handler(App_name, _, Resource_singular, Type_name, Db, Fields) -> Db_arg = case Db of sqlite -> <<"ctx.db_path"/utf8>>; _ -> <<"ctx.db"/utf8>> end, Json_fields = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Name, Field_type} = F, Json_fn = case Field_type of <<"int"/utf8>> -> <<"json.int"/utf8>>; <<"float"/utf8>> -> <<"json.float"/utf8>>; <<"bool"/utf8>> -> <<"json.bool"/utf8>>; _ -> <<"json.string"/utf8>> end, <<<<<<<<<<<<" #(\""/utf8, Name/binary>>/binary, "\", "/utf8>>/binary, Json_fn/binary>>/binary, "(item."/utf8>>/binary, Name/binary>>/binary, ")),"/utf8>> end ), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, To_json = <<<<<<<<"fn to_json(item: "/utf8, Resource_singular/binary>>/binary, ".type_placeholder) -> json.Json { json.object([ #(\"id\", json.int(item.id)), "/utf8>>/binary, Json_fields/binary>>/binary, " ]) }"/utf8>>, To_json@1 = gleam@string:replace( To_json, <<"type_placeholder"/utf8>>, Type_name ), Extra_imports = case gleam@list:any( Fields, fun(F@1) -> erlang:element(2, F@1) =:= <<"float"/utf8>> end ) of true -> <<"\nimport gleam/float"/utf8>>; false -> <<""/utf8>> end, <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"import gleam/int"/utf8, Extra_imports/binary>>/binary, " import gleam/json import "/utf8>>/binary, App_name/binary>>/binary, "/context.{type Context} import "/utf8>>/binary, App_name/binary>>/binary, "/data/"/utf8>>/binary, Resource_singular/binary>>/binary, "_repo import "/utf8>>/binary, App_name/binary>>/binary, "/domain/"/utf8>>/binary, Resource_singular/binary>>/binary, " import wisp.{type Request, type Response} pub fn index(_req: Request, ctx: Context) -> Response { let items = "/utf8>>/binary, Resource_singular/binary>>/binary, "_repo.list("/utf8>>/binary, Db_arg/binary>>/binary, ") let body = json.array(items, to_json) |> json.to_string wisp.json_response(body, 200) } pub fn show(req: Request, ctx: Context, id: String) -> Response { case int.parse(id) { Error(_) -> wisp.json_response(\"{\\\"error\\\":\\\"not found\\\"}\", 404) Ok(id) -> case "/utf8>>/binary, Resource_singular/binary>>/binary, "_repo.get("/utf8>>/binary, Db_arg/binary>>/binary, ", id) { Error(_) -> wisp.json_response(\"{\\\"error\\\":\\\"not found\\\"}\", 404) Ok(item) -> { wisp.json_response(json.to_string(to_json(item)), 200) } } } } pub fn create(req: Request, ctx: Context) -> Response { use _json_body <- wisp.require_json(req) // TODO: decode JSON body into "/utf8>>/binary, Type_name/binary>>/binary, "Params and create wisp.json_response(\"{\\\"error\\\":\\\"not implemented\\\"}\", 501) } pub fn update(req: Request, ctx: Context, id: String) -> Response { use _json_body <- wisp.require_json(req) // TODO: decode JSON body into "/utf8>>/binary, Type_name/binary>>/binary, "Params and update wisp.json_response(\"{\\\"error\\\":\\\"not implemented\\\"}\", 501) } pub fn delete(req: Request, ctx: Context, id: String) -> Response { case int.parse(id) { Error(_) -> wisp.json_response(\"{\\\"error\\\":\\\"not found\\\"}\", 404) Ok(id) -> { let _ = "/utf8>>/binary, Resource_singular/binary>>/binary, "_repo.delete("/utf8>>/binary, Db_arg/binary>>/binary, ", id) wisp.json_response(\"{\\\"ok\\\":true}\", 200) } } } "/utf8>>/binary, To_json@1/binary>>/binary, " "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1108). -spec resource_repo_sqlite( binary(), binary(), binary(), list({binary(), binary()}) ) -> binary(). resource_repo_sqlite(App_name, Resource_singular, Type_name, Fields) -> Table = <>, Field_names = begin _pipe = gleam@list:map(Fields, fun(F) -> erlang:element(1, F) end), gleam@string:join(_pipe, <<", "/utf8>>) end, Select_fields = <<"id, "/utf8, Field_names/binary>>, Q = <<"\""/utf8>>, Decoder_fields = begin _pipe@1 = Fields, _pipe@2 = gleam@list:index_map( _pipe@1, fun(F@1, I) -> {Name, Field_type} = F@1, Decode_fn = case Field_type of <<"bool"/utf8>> -> <<"sqlight.decode_bool()"/utf8>>; <<"int"/utf8>> -> <<"decode.int"/utf8>>; <<"float"/utf8>> -> <<"decode.float"/utf8>>; _ -> <<"decode.string"/utf8>> end, <<<<<<<<<<<<" use "/utf8, Name/binary>>/binary, " <- decode.field("/utf8>>/binary, (erlang:integer_to_binary(I + 1))/binary>>/binary, ", "/utf8>>/binary, Decode_fn/binary>>/binary, ")"/utf8>> end ), gleam@string:join(_pipe@2, <<"\n"/utf8>>) end, Constructor_args = begin _pipe@3 = Fields, _pipe@4 = gleam@list:map( _pipe@3, fun(F@2) -> <<<<(erlang:element(1, F@2))/binary, ": "/utf8>>/binary, (erlang:element(1, F@2))/binary>> end ), gleam@string:join(_pipe@4, <<", "/utf8>>) end, Insert_placeholders = begin _pipe@5 = Fields, _pipe@6 = gleam@list:index_map(_pipe@5, fun(_, _) -> <<"?"/utf8>> end), gleam@string:join(_pipe@6, <<", "/utf8>>) end, Insert_params = begin _pipe@7 = Fields, _pipe@8 = gleam@list:map( _pipe@7, fun(F@3) -> {Name@1, Field_type@1} = F@3, Sq_fn = case Field_type@1 of <<"bool"/utf8>> -> <<"sqlight.bool"/utf8>>; <<"int"/utf8>> -> <<"sqlight.int"/utf8>>; <<"float"/utf8>> -> <<"sqlight.float"/utf8>>; _ -> <<"sqlight.text"/utf8>> end, <<<<<<<<" "/utf8, Sq_fn/binary>>/binary, "(params."/utf8>>/binary, Name@1/binary>>/binary, "),"/utf8>> end ), gleam@string:join(_pipe@8, <<"\n"/utf8>>) end, Update_sets = begin _pipe@9 = Fields, _pipe@10 = gleam@list:index_map( _pipe@9, fun(F@4, _) -> <<(erlang:element(1, F@4))/binary, " = ?"/utf8>> end ), gleam@string:join(_pipe@10, <<", "/utf8>>) end, gleam@string:join( [<<"import gleam/dynamic/decode"/utf8>>, <<"import gleam/result"/utf8>>, <<<<<<<<<<<<<<<<"import "/utf8, App_name/binary>>/binary, "/domain/"/utf8>>/binary, Resource_singular/binary>>/binary, ".{type "/utf8>>/binary, Type_name/binary>>/binary, ", "/utf8>>/binary, Type_name/binary>>/binary, "}"/utf8>>, <<<<<<<<<<<<"import "/utf8, App_name/binary>>/binary, "/web/forms/"/utf8>>/binary, Resource_singular/binary>>/binary, "_form.{type "/utf8>>/binary, Type_name/binary>>/binary, "Params}"/utf8>>, <<"import sqlight"/utf8>>, <<""/utf8>>, <<<<<<<<"fn "/utf8, Resource_singular/binary>>/binary, "_decoder() -> decode.Decoder("/utf8>>/binary, Type_name/binary>>/binary, ") {"/utf8>>, <<" use id <- decode.field(0, decode.int)"/utf8>>, Decoder_fields, <<<<<<<<" decode.success("/utf8, Type_name/binary>>/binary, "(id: id, "/utf8>>/binary, Constructor_args/binary>>/binary, "))"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<<<"pub fn list(db_path: String) -> List("/utf8, Type_name/binary>>/binary, ") {"/utf8>>, <<" use conn <- sqlight.with_connection(db_path)"/utf8>>, <<<<<<<<<<<<<<<<<<<<" case sqlight.query("/utf8, Q/binary>>/binary, "SELECT "/utf8>>/binary, Select_fields/binary>>/binary, " FROM "/utf8>>/binary, Table/binary>>/binary, " ORDER BY id DESC"/utf8>>/binary, Q/binary>>/binary, ", on: conn, with: [], expecting: "/utf8>>/binary, Resource_singular/binary>>/binary, "_decoder()) {"/utf8>>, <<" Ok(rows) -> rows"/utf8>>, <<" Error(_) -> []"/utf8>>, <<" }"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<<<"pub fn get(db_path: String, id: Int) -> Result("/utf8, Type_name/binary>>/binary, ", Nil) {"/utf8>>, <<" use conn <- sqlight.with_connection(db_path)"/utf8>>, <<<<<<<<<<<<<<<<<<<<" sqlight.query("/utf8, Q/binary>>/binary, "SELECT "/utf8>>/binary, Select_fields/binary>>/binary, " FROM "/utf8>>/binary, Table/binary>>/binary, " WHERE id = ?"/utf8>>/binary, Q/binary>>/binary, ", on: conn, with: [sqlight.int(id)], expecting: "/utf8>>/binary, Resource_singular/binary>>/binary, "_decoder())"/utf8>>, <<" |> result.replace_error(Nil)"/utf8>>, <<" |> result.try(fn(rows) {"/utf8>>, <<" case rows {"/utf8>>, <<" [item] -> Ok(item)"/utf8>>, <<" _ -> Error(Nil)"/utf8>>, <<" }"/utf8>>, <<" })"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<<<<<<<"pub fn create(db_path: String, params: "/utf8, Type_name/binary>>/binary, "Params) -> Result("/utf8>>/binary, Type_name/binary>>/binary, ", Nil) {"/utf8>>, <<" use conn <- sqlight.with_connection(db_path)"/utf8>>, <<" sqlight.query("/utf8>>, <<<<<<<<<<<<<<<<<<<<<<" "/utf8, Q/binary>>/binary, "INSERT INTO "/utf8>>/binary, Table/binary>>/binary, " ("/utf8>>/binary, Field_names/binary>>/binary, ") VALUES ("/utf8>>/binary, Insert_placeholders/binary>>/binary, ") RETURNING "/utf8>>/binary, Select_fields/binary>>/binary, Q/binary>>/binary, ","/utf8>>, <<" on: conn,"/utf8>>, <<" with: ["/utf8>>, Insert_params, <<" ],"/utf8>>, <<<<" expecting: "/utf8, Resource_singular/binary>>/binary, "_decoder(),"/utf8>>, <<" )"/utf8>>, <<" |> result.replace_error(Nil)"/utf8>>, <<" |> result.try(fn(rows) {"/utf8>>, <<" case rows {"/utf8>>, <<" [item] -> Ok(item)"/utf8>>, <<" _ -> Error(Nil)"/utf8>>, <<" }"/utf8>>, <<" })"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<"pub fn update("/utf8>>, <<" db_path: String,"/utf8>>, <<" id: Int,"/utf8>>, <<<<" params: "/utf8, Type_name/binary>>/binary, "Params,"/utf8>>, <<<<") -> Result("/utf8, Type_name/binary>>/binary, ", Nil) {"/utf8>>, <<" use conn <- sqlight.with_connection(db_path)"/utf8>>, <<" sqlight.query("/utf8>>, <<<<<<<<<<<<<<<<<<" "/utf8, Q/binary>>/binary, "UPDATE "/utf8>>/binary, Table/binary>>/binary, " SET "/utf8>>/binary, Update_sets/binary>>/binary, " WHERE id = ? RETURNING "/utf8>>/binary, Select_fields/binary>>/binary, Q/binary>>/binary, ","/utf8>>, <<" on: conn,"/utf8>>, <<" with: ["/utf8>>, Insert_params, <<" sqlight.int(id),"/utf8>>, <<" ],"/utf8>>, <<<<" expecting: "/utf8, Resource_singular/binary>>/binary, "_decoder(),"/utf8>>, <<" )"/utf8>>, <<" |> result.replace_error(Nil)"/utf8>>, <<" |> result.try(fn(rows) {"/utf8>>, <<" case rows {"/utf8>>, <<" [item] -> Ok(item)"/utf8>>, <<" _ -> Error(Nil)"/utf8>>, <<" }"/utf8>>, <<" })"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<"pub fn delete(db_path: String, id: Int) -> Result(Nil, Nil) {"/utf8>>, <<" use conn <- sqlight.with_connection(db_path)"/utf8>>, <<<<<<<<<<<<" sqlight.query("/utf8, Q/binary>>/binary, "DELETE FROM "/utf8>>/binary, Table/binary>>/binary, " WHERE id = ?"/utf8>>/binary, Q/binary>>/binary, ", on: conn, with: [sqlight.int(id)], expecting: decode.success(Nil))"/utf8>>, <<" |> result.replace(Nil)"/utf8>>, <<" |> result.replace_error(Nil)"/utf8>>, <<"}"/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/refrakt/cli/gen.gleam", 1331). -spec resource_repo_pog( binary(), binary(), binary(), list({binary(), binary()}) ) -> binary(). resource_repo_pog(App_name, Resource_singular, Type_name, Fields) -> Field_names = begin _pipe = Fields, _pipe@1 = gleam@list:map(_pipe, fun(F) -> erlang:element(1, F) end), gleam@string:join(_pipe@1, <<", "/utf8>>) end, Select_fields = <<"id, "/utf8, Field_names/binary>>, Decoder_fields = begin _pipe@2 = Fields, _pipe@3 = gleam@list:index_map( _pipe@2, fun(F@1, I) -> {Name, Field_type} = F@1, Decode_fn = case Field_type of <<"bool"/utf8>> -> <<"decode.bool"/utf8>>; <<"int"/utf8>> -> <<"decode.int"/utf8>>; <<"float"/utf8>> -> <<"decode.float"/utf8>>; _ -> <<"decode.string"/utf8>> end, <<<<<<<<<<<<" use "/utf8, Name/binary>>/binary, " <- decode.field("/utf8>>/binary, (erlang:integer_to_binary(I + 1))/binary>>/binary, ", "/utf8>>/binary, Decode_fn/binary>>/binary, ")"/utf8>> end ), gleam@string:join(_pipe@3, <<"\n"/utf8>>) end, Constructor_args = begin _pipe@4 = Fields, _pipe@5 = gleam@list:map( _pipe@4, fun(F@2) -> <<<<(erlang:element(1, F@2))/binary, ": "/utf8>>/binary, (erlang:element(1, F@2))/binary>> end ), gleam@string:join(_pipe@5, <<", "/utf8>>) end, Insert_placeholders = begin _pipe@6 = Fields, _pipe@7 = gleam@list:index_map( _pipe@6, fun(_, I@1) -> <<"$"/utf8, (erlang:integer_to_binary(I@1 + 1))/binary>> end ), gleam@string:join(_pipe@7, <<", "/utf8>>) end, Insert_params = begin _pipe@8 = Fields, _pipe@9 = gleam@list:map( _pipe@8, fun(F@3) -> {Name@1, Field_type@1} = F@3, Pog_fn = case Field_type@1 of <<"bool"/utf8>> -> <<"pog.bool"/utf8>>; <<"int"/utf8>> -> <<"pog.int"/utf8>>; <<"float"/utf8>> -> <<"pog.float"/utf8>>; _ -> <<"pog.text"/utf8>> end, <<<<<<<<" |> pog.parameter("/utf8, Pog_fn/binary>>/binary, "(params."/utf8>>/binary, Name@1/binary>>/binary, "))"/utf8>> end ), gleam@string:join(_pipe@9, <<"\n"/utf8>>) end, Update_sets = begin _pipe@10 = Fields, _pipe@11 = gleam@list:index_map( _pipe@10, fun(F@4, I@2) -> <<<<(erlang:element(1, F@4))/binary, " = $"/utf8>>/binary, (erlang:integer_to_binary(I@2 + 1))/binary>> end ), gleam@string:join(_pipe@11, <<", "/utf8>>) end, Update_id_param = <<"$"/utf8, (erlang:integer_to_binary(erlang:length(Fields) + 1))/binary>>, Q = <<"\""/utf8>>, Table = <>, List_query = <<<<<<<<<<<<<<<<" pog.query("/utf8, Q/binary>>/binary, "SELECT "/utf8>>/binary, Select_fields/binary>>/binary, " FROM "/utf8>>/binary, Table/binary>>/binary, " ORDER BY id DESC"/utf8>>/binary, Q/binary>>/binary, ")"/utf8>>, Get_query = <<<<<<<<<<<<<<<<" pog.query("/utf8, Q/binary>>/binary, "SELECT "/utf8>>/binary, Select_fields/binary>>/binary, " FROM "/utf8>>/binary, Table/binary>>/binary, " WHERE id = $1"/utf8>>/binary, Q/binary>>/binary, ")"/utf8>>, Create_query = <<<<<<<<<<<<<<<<<<<<<<" pog.query("/utf8, Q/binary>>/binary, "INSERT INTO "/utf8>>/binary, Table/binary>>/binary, " ("/utf8>>/binary, Field_names/binary>>/binary, ") VALUES ("/utf8>>/binary, Insert_placeholders/binary>>/binary, ") RETURNING "/utf8>>/binary, Select_fields/binary>>/binary, Q/binary>>/binary, ")"/utf8>>, Update_query = <<<<<<<<<<<<<<<<<<<<<<" pog.query("/utf8, Q/binary>>/binary, "UPDATE "/utf8>>/binary, Table/binary>>/binary, " SET "/utf8>>/binary, Update_sets/binary>>/binary, " WHERE id = "/utf8>>/binary, Update_id_param/binary>>/binary, " RETURNING "/utf8>>/binary, Select_fields/binary>>/binary, Q/binary>>/binary, ")"/utf8>>, Delete_query = <<<<<<<<<<<<" pog.query("/utf8, Q/binary>>/binary, "DELETE FROM "/utf8>>/binary, Table/binary>>/binary, " WHERE id = $1"/utf8>>/binary, Q/binary>>/binary, ")"/utf8>>, Single_row_extract = <<" |> pog.execute(db) |> result.replace_error(Nil) |> result.try(fn(r) { case r.rows { [item] -> Ok(item) _ -> Error(Nil) } })"/utf8>>, gleam@string:join( [<<"import gleam/dynamic/decode"/utf8>>, <<"import gleam/result"/utf8>>, <<<<<<<<<<<<<<<<"import "/utf8, App_name/binary>>/binary, "/domain/"/utf8>>/binary, Resource_singular/binary>>/binary, ".{type "/utf8>>/binary, Type_name/binary>>/binary, ", "/utf8>>/binary, Type_name/binary>>/binary, "}"/utf8>>, <<<<<<<<<<<<"import "/utf8, App_name/binary>>/binary, "/web/forms/"/utf8>>/binary, Resource_singular/binary>>/binary, "_form.{type "/utf8>>/binary, Type_name/binary>>/binary, "Params}"/utf8>>, <<"import pog"/utf8>>, <<""/utf8>>, <<<<<<<<"fn "/utf8, Resource_singular/binary>>/binary, "_decoder() -> decode.Decoder("/utf8>>/binary, Type_name/binary>>/binary, ") {"/utf8>>, <<" use id <- decode.field(0, decode.int)"/utf8>>, Decoder_fields, <<<<<<<<" decode.success("/utf8, Type_name/binary>>/binary, "(id: id, "/utf8>>/binary, Constructor_args/binary>>/binary, "))"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<<<"pub fn list(db: pog.Connection) -> List("/utf8, Type_name/binary>>/binary, ") {"/utf8>>, List_query, <<<<" |> pog.returning("/utf8, Resource_singular/binary>>/binary, "_decoder())"/utf8>>, <<" |> pog.execute(db)"/utf8>>, <<" |> result.map(fn(r) { r.rows })"/utf8>>, <<" |> result.unwrap([])"/utf8>>, <<"}"/utf8>>, <<""/utf8>>, <<<<"pub fn get(db: pog.Connection, id: Int) -> Result("/utf8, Type_name/binary>>/binary, ", Nil) {"/utf8>>, Get_query, <<" |> pog.parameter(pog.int(id))"/utf8>>, <<<<" |> pog.returning("/utf8, Resource_singular/binary>>/binary, "_decoder())"/utf8>>, Single_row_extract, <<"}"/utf8>>, <<""/utf8>>, <<<<<<<<"pub fn create(db: pog.Connection, params: "/utf8, Type_name/binary>>/binary, "Params) -> Result("/utf8>>/binary, Type_name/binary>>/binary, ", Nil) {"/utf8>>, Create_query, Insert_params, <<<<" |> pog.returning("/utf8, Resource_singular/binary>>/binary, "_decoder())"/utf8>>, Single_row_extract, <<"}"/utf8>>, <<""/utf8>>, <<"pub fn update("/utf8>>, <<" db: pog.Connection,"/utf8>>, <<" id: Int,"/utf8>>, <<<<" params: "/utf8, Type_name/binary>>/binary, "Params,"/utf8>>, <<<<") -> Result("/utf8, Type_name/binary>>/binary, ", Nil) {"/utf8>>, Update_query, Insert_params, <<" |> pog.parameter(pog.int(id))"/utf8>>, <<<<" |> pog.returning("/utf8, Resource_singular/binary>>/binary, "_decoder())"/utf8>>, Single_row_extract, <<"}"/utf8>>, <<""/utf8>>, <<"pub fn delete(db: pog.Connection, id: Int) -> Result(Nil, Nil) {"/utf8>>, Delete_query, <<" |> pog.parameter(pog.int(id))"/utf8>>, <<" |> pog.execute(db)"/utf8>>, <<" |> result.replace(Nil)"/utf8>>, <<" |> result.replace_error(Nil)"/utf8>>, <<"}"/utf8>>, <<""/utf8>>], <<"\n"/utf8>> ). -file("src/refrakt/cli/gen.gleam", 1093). -spec resource_repo( binary(), binary(), binary(), list({binary(), binary()}), refrakt@cli@types:db_choice() ) -> binary(). resource_repo(App_name, Resource_singular, Type_name, Fields, Db) -> case Db of sqlite -> resource_repo_sqlite(App_name, Resource_singular, Type_name, Fields); no_db -> resource_repo_sqlite(App_name, Resource_singular, Type_name, Fields); postgres -> resource_repo_pog(App_name, Resource_singular, Type_name, Fields) end. -file("src/refrakt/cli/gen.gleam", 1593). -spec api_resource_test(binary(), binary()) -> binary(). api_resource_test(_, _) -> <<"import gleeunit/should pub fn placeholder_test() { // API handler tests require a running database. // Test your domain logic and JSON encoding instead. 1 + 1 |> should.equal(2) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1605). -spec resource_test(binary(), binary(), binary(), list({binary(), binary()})) -> binary(). resource_test(App_name, Resource_singular, _, Fields) -> Valid_values = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Name, Ftype} = F, Val = case Ftype of <<"bool"/utf8>> -> <<"on"/utf8>>; <<"int"/utf8>> -> <<"42"/utf8>>; <<"float"/utf8>> -> <<"3.14"/utf8>>; _ -> <<"test value"/utf8>> end, <<<<<<<<" #(\""/utf8, Name/binary>>/binary, "\", \""/utf8>>/binary, Val/binary>>/binary, "\"),"/utf8>> end ), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, Required_fields = begin _pipe@2 = Fields, gleam@list:filter( _pipe@2, fun(F@1) -> (erlang:element(2, F@1) =:= <<"string"/utf8>>) orelse (erlang:element( 2, F@1 ) =:= <<"text"/utf8>>) end ) end, Missing_field_test = case Required_fields of [{Name@1, _} | _] -> <<<<<<<<" pub fn decode_missing_"/utf8, Name@1/binary>>/binary, "_returns_error_test() { let data = wisp.FormData(values: [], files: []) "/utf8>>/binary, Resource_singular/binary>>/binary, "_form.decode(data) |> should.be_error } "/utf8>>; [] -> <<""/utf8>> end, <<<<<<<<<<<<<<<<<<<<<<"import gleeunit/should import "/utf8, App_name/binary>>/binary, "/web/forms/"/utf8>>/binary, Resource_singular/binary>>/binary, "_form import wisp pub fn empty_form_has_no_id_test() { let form = "/utf8>>/binary, Resource_singular/binary>>/binary, "_form.empty() form.id |> should.be_none } pub fn decode_valid_form_test() { let data = wisp.FormData( values: [ "/utf8>>/binary, Valid_values/binary>>/binary, " ], files: [], ) "/utf8>>/binary, Resource_singular/binary>>/binary, "_form.decode(data) |> should.be_ok } "/utf8>>/binary, Missing_field_test/binary>>. -file("src/refrakt/cli/gen.gleam", 1798). -spec split_after_imports(list(binary()), list(binary())) -> {list(binary()), list(binary())}. split_after_imports(Lines, Acc) -> case Lines of [] -> {lists:reverse(Acc), []}; [Line | Rest] -> case gleam_stdlib:string_starts_with(Line, <<"import "/utf8>>) of true -> split_after_imports(Rest, [Line | Acc]); false -> case Acc of [] -> split_after_imports(Rest, [Line | Acc]); _ -> {lists:reverse(Acc), [Line | Rest]} end end end. -file("src/refrakt/cli/gen.gleam", 1785). -spec add_import(binary(), binary()) -> binary(). add_import(Content, Import_line) -> case gleam_stdlib:contains_string(Content, Import_line) of true -> Content; false -> Lines = gleam@string:split(Content, <<"\n"/utf8>>), {Before, After} = split_after_imports(Lines, []), gleam@string:join( lists:append(Before, [Import_line | After]), <<"\n"/utf8>> ) end. -file("src/refrakt/cli/gen.gleam", 1816). -spec add_route(binary(), binary()) -> binary(). add_route(Content, Route_line) -> case gleam@string:split_once(Content, <<" _, _ ->"/utf8>>) of {ok, {Before, After}} -> <<<<<>/binary, "\n _, _ ->"/utf8>>/binary, After/binary>>; {error, _} -> case gleam@string:split_once(Content, <<" _ ->"/utf8>>) of {ok, {Before@1, After@1}} -> <<<<<>/binary, "\n _ ->"/utf8>>/binary, After@1/binary>>; {error, _} -> Content end end. -file("src/refrakt/cli/gen.gleam", 515). -spec patch_router_live(binary(), binary()) -> {ok, nil} | {error, simplifile:file_error()}. patch_router_live(App, Name) -> Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Content@1 = case simplifile:read(Router_path) of {ok, Content} -> Content; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_live"/utf8>>, line => 517, value => _assert_fail, start => 15224, 'end' => 15277, pattern_start => 15235, pattern_end => 15246}) end, Handler_import = <<<<<<<<"import "/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Name/binary>>/binary, "_live_handler"/utf8>>, Content@2 = add_import(Content@1, Handler_import), Socket_import = <<<<<<<<"import "/utf8, App/binary>>/binary, "/web/live/"/utf8>>/binary, Name/binary>>/binary, "_socket"/utf8>>, Content@3 = add_import(Content@2, Socket_import), Routes = <<<<<<<<"\n [\""/utf8, Name/binary>>/binary, "\"], http.Get -> "/utf8>>/binary, Name/binary>>/binary, "_live_handler.index(req, ctx)"/utf8>>, Content@4 = add_route(Content@3, Routes), _assert_subject = simplifile:write(Router_path, Content@4), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_live"/utf8>>, line => 533, value => _assert_fail@1, start => 15705, 'end' => 15762, pattern_start => 15716, pattern_end => 15721}) end. -file("src/refrakt/cli/gen.gleam", 1674). -spec patch_router_page(binary(), binary()) -> {ok, nil} | {error, simplifile:file_error()}. patch_router_page(App, Name) -> Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Content@1 = case simplifile:read(Router_path) of {ok, Content} -> Content; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_page"/utf8>>, line => 1676, value => _assert_fail, start => 44464, 'end' => 44517, pattern_start => 44475, pattern_end => 44486}) end, Import_line = <<<<<<<<"import "/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Name/binary>>/binary, "_handler"/utf8>>, Content@2 = add_import(Content@1, Import_line), Route_line = <<<<<<<<" [\""/utf8, Name/binary>>/binary, "\"], http.Get -> "/utf8>>/binary, Name/binary>>/binary, "_handler.index(req, ctx)"/utf8>>, Content@3 = add_route(Content@2, Route_line), _assert_subject = simplifile:write(Router_path, Content@3), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_page"/utf8>>, line => 1692, value => _assert_fail@1, start => 44856, 'end' => 44913, pattern_start => 44867, pattern_end => 44872}) end. -file("src/refrakt/cli/gen.gleam", 1695). -spec patch_router_resource(binary(), binary(), binary()) -> {ok, nil} | {error, simplifile:file_error()}. patch_router_resource(App, Plural, Singular) -> Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Content@1 = case simplifile:read(Router_path) of {ok, Content} -> Content; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_resource"/utf8>>, line => 1697, value => _assert_fail, start => 45046, 'end' => 45099, pattern_start => 45057, pattern_end => 45068}) end, Import_line = <<<<<<<<"import "/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Singular/binary>>/binary, "_handler"/utf8>>, Content@2 = add_import(Content@1, Import_line), Routes = <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"\n [\""/utf8, Plural/binary>>/binary, "\"], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.index(req, ctx) [\""/utf8>>/binary, Plural/binary>>/binary, "\", \"new\"], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.new(req, ctx) [\""/utf8>>/binary, Plural/binary>>/binary, "\"], http.Post -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.create(req, ctx) [\""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.show(req, ctx, id) [\""/utf8>>/binary, Plural/binary>>/binary, "\", id, \"edit\"], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.edit(req, ctx, id) [\""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Put -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.update(req, ctx, id) [\""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Delete -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.delete(req, ctx, id)"/utf8>>, Content@3 = add_route(Content@2, Routes), _assert_subject = simplifile:write(Router_path, Content@3), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_resource"/utf8>>, line => 1743, value => _assert_fail@1, start => 46091, 'end' => 46148, pattern_start => 46102, pattern_end => 46107}) end. -file("src/refrakt/cli/gen.gleam", 1746). -spec patch_router_api_resource(binary(), binary(), binary()) -> {ok, nil} | {error, simplifile:file_error()}. patch_router_api_resource(App, Plural, Singular) -> Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Content@1 = case simplifile:read(Router_path) of {ok, Content} -> Content; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_api_resource"/utf8>>, line => 1748, value => _assert_fail, start => 46285, 'end' => 46338, pattern_start => 46296, pattern_end => 46307}) end, Import_line = <<<<<<<<"import "/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Singular/binary>>/binary, "_handler"/utf8>>, Content@2 = add_import(Content@1, Import_line), Routes = <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"\n [\"api\", \""/utf8, Plural/binary>>/binary, "\"], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.index(req, ctx) [\"api\", \""/utf8>>/binary, Plural/binary>>/binary, "\"], http.Post -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.create(req, ctx) [\"api\", \""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Get -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.show(req, ctx, id) [\"api\", \""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Put -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.update(req, ctx, id) [\"api\", \""/utf8>>/binary, Plural/binary>>/binary, "\", id], http.Delete -> "/utf8>>/binary, Singular/binary>>/binary, "_handler.delete(req, ctx, id)"/utf8>>, Content@3 = add_route(Content@2, Routes), _assert_subject = simplifile:write(Router_path, Content@3), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_api_resource"/utf8>>, line => 1782, value => _assert_fail@1, start => 47159, 'end' => 47216, pattern_start => 47170, pattern_end => 47175}) end. -file("src/refrakt/cli/gen.gleam", 1833). -spec parse_fields(list(binary())) -> list({binary(), binary()}). parse_fields(Raw) -> _pipe = Raw, gleam@list:filter_map( _pipe, fun(Field) -> case gleam@string:split(Field, <<":"/utf8>>) of [Name, Field_type] -> {ok, {Name, Field_type}}; _ -> {error, nil} end end ). -file("src/refrakt/cli/gen.gleam", 1843). -spec to_gleam_type(binary()) -> binary(). to_gleam_type(Field_type) -> case Field_type of <<"string"/utf8>> -> <<"String"/utf8>>; <<"text"/utf8>> -> <<"String"/utf8>>; <<"int"/utf8>> -> <<"Int"/utf8>>; <<"float"/utf8>> -> <<"Float"/utf8>>; <<"bool"/utf8>> -> <<"Bool"/utf8>>; <<"date"/utf8>> -> <<"String"/utf8>>; <<"datetime"/utf8>> -> <<"String"/utf8>>; _ -> <<"String"/utf8>> end. -file("src/refrakt/cli/gen.gleam", 637). -spec api_params_module( binary(), binary(), binary(), list({binary(), binary()}) ) -> binary(). api_params_module(_, _, Type_name, Fields) -> Params_field_defs = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Name, Ft} = F, <<<<<<<<" "/utf8, Name/binary>>/binary, ": "/utf8>>/binary, (to_gleam_type(Ft))/binary>>/binary, ","/utf8>> end ), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, <<<<<<<<<<<<<<<<"/// Params type for "/utf8, Type_name/binary>>/binary, " (API mode). /// pub type "/utf8>>/binary, Type_name/binary>>/binary, "Params { "/utf8>>/binary, Type_name/binary>>/binary, "Params( "/utf8>>/binary, Params_field_defs/binary>>/binary, " ) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1856). -spec to_sql_type(binary()) -> binary(). to_sql_type(Field_type) -> case Field_type of <<"string"/utf8>> -> <<"TEXT"/utf8>>; <<"text"/utf8>> -> <<"TEXT"/utf8>>; <<"int"/utf8>> -> <<"INTEGER"/utf8>>; <<"float"/utf8>> -> <<"DOUBLE PRECISION"/utf8>>; <<"bool"/utf8>> -> <<"BOOLEAN"/utf8>>; <<"date"/utf8>> -> <<"DATE"/utf8>>; <<"datetime"/utf8>> -> <<"TIMESTAMPTZ"/utf8>>; _ -> <<"TEXT"/utf8>> end. -file("src/refrakt/cli/gen.gleam", 1869). -spec to_sql_type_sqlite(binary()) -> binary(). to_sql_type_sqlite(Field_type) -> case Field_type of <<"string"/utf8>> -> <<"TEXT"/utf8>>; <<"text"/utf8>> -> <<"TEXT"/utf8>>; <<"int"/utf8>> -> <<"INTEGER"/utf8>>; <<"float"/utf8>> -> <<"REAL"/utf8>>; <<"bool"/utf8>> -> <<"INTEGER"/utf8>>; <<"date"/utf8>> -> <<"TEXT"/utf8>>; <<"datetime"/utf8>> -> <<"TEXT"/utf8>>; _ -> <<"TEXT"/utf8>> end. -file("src/refrakt/cli/gen.gleam", 1882). -spec form_default_value(binary()) -> binary(). form_default_value(Field_type) -> case Field_type of <<"bool"/utf8>> -> <<"False"/utf8>>; <<"int"/utf8>> -> <<"0"/utf8>>; <<"float"/utf8>> -> <<"0.0"/utf8>>; _ -> <<"\"\""/utf8>> end. -file("src/refrakt/cli/gen.gleam", 1895). -spec auth_user_type() -> binary(). auth_user_type() -> <<"pub type User { User(id: Int, email: String, hashed_password: String) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1902). -spec auth_domain(binary()) -> binary(). auth_domain(_) -> <<"import gleam/crypto import gleam/bit_array import gleam/string /// Hash a password using a simple HMAC-based approach. /// Replace with a proper bcrypt/argon2 library for production. pub fn hash_password(password: String) -> String { crypto.hash(crypto.Sha256, bit_array.from_string(password)) |> bit_array.base16_encode |> string.lowercase } /// Verify a password against a hash. pub fn verify_password(password: String, hash: String) -> Bool { hash_password(password) == hash } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1922). -spec auth_user_repo(binary()) -> binary(). auth_user_repo(App) -> Q = <<"\""/utf8>>, <<<<<<<<<<<<<<<<<<<<<<<<<<<<"import gleam/dynamic/decode import gleam/result import "/utf8, App/binary>>/binary, "/domain/user.{type User, User} import pog fn user_decoder() -> decode.Decoder(User) { use id <- decode.field(0, decode.int) use email <- decode.field(1, decode.string) use hashed_password <- decode.field(2, decode.string) decode.success(User(id: id, email: email, hashed_password: hashed_password)) } pub fn get_by_email(db: pog.Connection, email: String) -> Result(User, Nil) { pog.query("/utf8>>/binary, Q/binary>>/binary, "SELECT id, email, hashed_password FROM users WHERE email = $1"/utf8>>/binary, Q/binary>>/binary, ") |> pog.parameter(pog.text(email)) |> pog.returning(user_decoder()) |> pog.execute(db) |> result.replace_error(Nil) |> result.try(fn(r) { case r.rows { [user] -> Ok(user) _ -> Error(Nil) } }) } pub fn get_by_id(db: pog.Connection, id: Int) -> Result(User, Nil) { pog.query("/utf8>>/binary, Q/binary>>/binary, "SELECT id, email, hashed_password FROM users WHERE id = $1"/utf8>>/binary, Q/binary>>/binary, ") |> pog.parameter(pog.int(id)) |> pog.returning(user_decoder()) |> pog.execute(db) |> result.replace_error(Nil) |> result.try(fn(r) { case r.rows { [user] -> Ok(user) _ -> Error(Nil) } }) } pub fn create( db: pog.Connection, email: String, hashed_password: String, ) -> Result(User, Nil) { pog.query( "/utf8>>/binary, Q/binary>>/binary, "INSERT INTO users (email, hashed_password) VALUES ($1, $2) RETURNING id, email, hashed_password"/utf8>>/binary, Q/binary>>/binary, ", ) |> pog.parameter(pog.text(email)) |> pog.parameter(pog.text(hashed_password)) |> pog.returning(user_decoder()) |> pog.execute(db) |> result.replace_error(Nil) |> result.try(fn(r) { case r.rows { [user] -> Ok(user) _ -> Error(Nil) } }) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 1987). -spec auth_migration() -> binary(). auth_migration() -> <<"CREATE TABLE users ( id SERIAL PRIMARY KEY, email TEXT NOT NULL UNIQUE, hashed_password TEXT NOT NULL, inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE UNIQUE INDEX users_email_index ON users (email); "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2000). -spec auth_form(binary()) -> binary(). auth_form(_) -> <<"import gleam/list import gleam/result import refrakt/validate import wisp pub type LoginParams { LoginParams(email: String, password: String) } pub type RegisterParams { RegisterParams(email: String, password: String, password_confirmation: String) } pub fn decode_login( data: wisp.FormData, ) -> Result(LoginParams, List(#(String, String))) { let email = get_value(data, \"email\") let password = get_value(data, \"password\") let errors = [] |> validate.required(email, \"email\", \"Email is required\") |> validate.required(password, \"password\", \"Password is required\") case errors { [] -> Ok(LoginParams(email: email, password: password)) _ -> Error(errors) } } pub fn decode_register( data: wisp.FormData, ) -> Result(RegisterParams, List(#(String, String))) { let email = get_value(data, \"email\") let password = get_value(data, \"password\") let password_confirmation = get_value(data, \"password_confirmation\") let errors = [] |> validate.required(email, \"email\", \"Email is required\") |> validate.required(password, \"password\", \"Password is required\") |> validate.min_length(password, \"password\", 8, \"Password must be at least 8 characters\") |> check_confirmation(password, password_confirmation) case errors { [] -> Ok(RegisterParams( email: email, password: password, password_confirmation: password_confirmation, )) _ -> Error(errors) } } fn check_confirmation( errors: List(#(String, String)), password: String, confirmation: String, ) -> List(#(String, String)) { case password == confirmation { True -> errors False -> [#(\"password_confirmation\", \"Passwords do not match\"), ..errors] } } fn get_value(data: wisp.FormData, key: String) -> String { list.find(data.values, fn(v) { v.0 == key }) |> result.map(fn(v) { v.1 }) |> result.unwrap(\"\") } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2075). -spec auth_handler(binary()) -> binary(). auth_handler(App) -> <<<<<<<<<<<<<<<<<<<<<<<<<<<<"import gleam/int import "/utf8, App/binary>>/binary, "/context.{type Context} import "/utf8>>/binary, App/binary>>/binary, "/data/user_repo import "/utf8>>/binary, App/binary>>/binary, "/domain/auth import "/utf8>>/binary, App/binary>>/binary, "/web/auth_views import "/utf8>>/binary, App/binary>>/binary, "/web/error_handler import "/utf8>>/binary, App/binary>>/binary, "/web/forms/auth_form import "/utf8>>/binary, App/binary>>/binary, "/web/layouts/root_layout import refrakt/flash import wisp.{type Request, type Response} pub fn login_page(_req: Request, _ctx: Context) -> Response { auth_views.login_view(\"\", []) |> root_layout.wrap(\"Log In\") |> wisp.html_response(200) } pub fn login(req: Request, ctx: Context) -> Response { use form_data <- wisp.require_form(req) case auth_form.decode_login(form_data) { Error(errors) -> auth_views.login_view(\"\", errors) |> root_layout.wrap(\"Log In\") |> wisp.html_response(422) Ok(params) -> case user_repo.get_by_email(ctx.db, params.email) { Error(_) -> auth_views.login_view(params.email, [#(\"email\", \"Invalid email or password\")]) |> root_layout.wrap(\"Log In\") |> wisp.html_response(422) Ok(user) -> case auth.verify_password(params.password, user.hashed_password) { False -> auth_views.login_view(params.email, [#(\"email\", \"Invalid email or password\")]) |> root_layout.wrap(\"Log In\") |> wisp.html_response(422) True -> wisp.redirect(\"/\") |> wisp.set_cookie( req, \"_user_id\", int.to_string(user.id), wisp.Signed, 60 * 60 * 24 * 7, ) |> flash.set_flash(req, \"info\", \"Logged in\") } } } } pub fn register_page(_req: Request, _ctx: Context) -> Response { auth_views.register_view(\"\", []) |> root_layout.wrap(\"Register\") |> wisp.html_response(200) } pub fn register(req: Request, ctx: Context) -> Response { use form_data <- wisp.require_form(req) case auth_form.decode_register(form_data) { Error(errors) -> auth_views.register_view(\"\", errors) |> root_layout.wrap(\"Register\") |> wisp.html_response(422) Ok(params) -> { let hashed = auth.hash_password(params.password) case user_repo.create(ctx.db, params.email, hashed) { Ok(user) -> wisp.redirect(\"/\") |> wisp.set_cookie( req, \"_user_id\", int.to_string(user.id), wisp.Signed, 60 * 60 * 24 * 7, ) |> flash.set_flash(req, \"info\", \"Account created\") Error(_) -> auth_views.register_view(params.email, [#(\"email\", \"Could not create account\")]) |> root_layout.wrap(\"Register\") |> wisp.html_response(422) } } } } pub fn logout(req: Request, _ctx: Context) -> Response { wisp.redirect(\"/\") |> wisp.set_cookie(req, \"_user_id\", \"\", wisp.Signed, 0) |> flash.set_flash(req, \"info\", \"Logged out\") } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2177). -spec auth_views(binary()) -> binary(). auth_views(_) -> <<"import gleam/list import lustre/attribute.{class, href, name, type_, value} import lustre/element.{type Element, text} import lustre/element/html.{ a, button, div, form, h1, input, label, p, section, } pub fn login_view(email: String, errors: List(#(String, String))) -> Element(Nil) { section([class(\"auth-form\")], [ h1([], [text(\"Log In\")]), form([attribute.action(\"/login\"), attribute.method(\"post\")], [ div([class(\"field\")], [ label([], [text(\"Email\")]), input([type_(\"email\"), name(\"email\"), value(email)]), field_error(errors, \"email\"), ]), div([class(\"field\")], [ label([], [text(\"Password\")]), input([type_(\"password\"), name(\"password\")]), field_error(errors, \"password\"), ]), button([type_(\"submit\"), class(\"btn\")], [text(\"Log In\")]), ]), p([], [ text(\"Don't have an account? \"), a([href(\"/register\")], [text(\"Register\")]), ]), ]) } pub fn register_view( email: String, errors: List(#(String, String)), ) -> Element(Nil) { section([class(\"auth-form\")], [ h1([], [text(\"Register\")]), form([attribute.action(\"/register\"), attribute.method(\"post\")], [ div([class(\"field\")], [ label([], [text(\"Email\")]), input([type_(\"email\"), name(\"email\"), value(email)]), field_error(errors, \"email\"), ]), div([class(\"field\")], [ label([], [text(\"Password\")]), input([type_(\"password\"), name(\"password\")]), field_error(errors, \"password\"), ]), div([class(\"field\")], [ label([], [text(\"Confirm Password\")]), input([type_(\"password\"), name(\"password_confirmation\")]), field_error(errors, \"password_confirmation\"), ]), button([type_(\"submit\"), class(\"btn\")], [text(\"Register\")]), ]), p([], [ text(\"Already have an account? \"), a([href(\"/login\")], [text(\"Log In\")]), ]), ]) } fn field_error(errors: List(#(String, String)), field: String) -> Element(Nil) { case list.find(errors, fn(e) { e.0 == field }) { Ok(#(_, message)) -> p([class(\"error\")], [text(message)]) Error(_) -> text(\"\") } } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2248). -spec auth_middleware(binary()) -> binary(). auth_middleware(App) -> <<<<<<<<<<<<"import gleam/int import gleam/result import "/utf8, App/binary>>/binary, "/context.{type Context} import "/utf8>>/binary, App/binary>>/binary, "/data/user_repo import "/utf8>>/binary, App/binary>>/binary, "/domain/user.{type User} import wisp.{type Request, type Response} /// Extract the current user from the session cookie. pub fn get_current_user(req: Request, ctx: Context) -> Result(User, Nil) { use user_id_str <- result.try(wisp.get_cookie(req, \"_user_id\", wisp.Signed)) use user_id <- result.try( int.parse(user_id_str) |> result.replace_error(Nil), ) user_repo.get_by_id(ctx.db, user_id) } /// Middleware that requires authentication. /// Redirects to /login if no valid session. pub fn require_auth( req: Request, ctx: Context, next: fn(User) -> Response, ) -> Response { case get_current_user(req, ctx) { Ok(user) -> next(user) Error(_) -> wisp.redirect(\"/login\") } } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2281). -spec auth_test(binary()) -> binary(). auth_test(App) -> <<<<"import gleeunit/should import "/utf8, App/binary>>/binary, "/domain/auth pub fn hash_password_test() { let hash = auth.hash_password(\"secret123\") auth.verify_password(\"secret123\", hash) |> should.be_true } pub fn wrong_password_test() { let hash = auth.hash_password(\"secret123\") auth.verify_password(\"wrong\", hash) |> should.be_false } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2299). -spec patch_router_auth(binary()) -> {ok, nil} | {error, simplifile:file_error()}. patch_router_auth(App) -> Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Content@1 = case simplifile:read(Router_path) of {ok, Content} -> Content; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_auth"/utf8>>, line => 2301, value => _assert_fail, start => 61566, 'end' => 61619, pattern_start => 61577, pattern_end => 61588}) end, Import_line = <<<<"import "/utf8, App/binary>>/binary, "/web/auth_handler"/utf8>>, Content@2 = add_import(Content@1, Import_line), Routes = <<"\n [\"login\"], http.Get -> auth_handler.login_page(req, ctx) [\"login\"], http.Post -> auth_handler.login(req, ctx) [\"register\"], http.Get -> auth_handler.register_page(req, ctx) [\"register\"], http.Post -> auth_handler.register(req, ctx) [\"logout\"], http.Post -> auth_handler.logout(req, ctx)"/utf8>>, Content@3 = add_route(Content@2, Routes), _assert_subject = simplifile:write(Router_path, Content@3), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"patch_router_auth"/utf8>>, line => 2315, value => _assert_fail@1, start => 62118, 'end' => 62175, pattern_start => 62129, pattern_end => 62134}) end. -file("src/refrakt/cli/gen.gleam", 2322). -spec capitalize(binary()) -> binary(). capitalize(S) -> case gleam_stdlib:string_pop_grapheme(S) of {ok, {First, Rest}} -> <<(string:uppercase(First))/binary, Rest/binary>>; {error, _} -> S end. -file("src/refrakt/cli/gen.gleam", 344). -spec live_component(binary(), binary()) -> binary(). live_component(_, Name) -> Type_name = capitalize(Name), <<<<<<<<"/// "/utf8, Type_name/binary>>/binary, " — a Lustre server component. /// /// This component runs on the server. UI updates are sent to the /// browser over WebSocket. The client runtime (~10kb) patches the DOM. /// import gleam/int import lustre import lustre/effect import lustre/element.{text} import lustre/element/html.{button, div, h1, p} import lustre/event pub type Model { Model(count: Int) } pub type Msg { Increment Decrement } pub fn init(_flags: Nil) -> #(Model, effect.Effect(Msg)) { #(Model(count: 0), effect.none()) } pub fn update(model: Model, msg: Msg) -> #(Model, effect.Effect(Msg)) { case msg { Increment -> #(Model(count: model.count + 1), effect.none()) Decrement -> #(Model(count: model.count - 1), effect.none()) } } pub fn view(model: Model) -> element.Element(Msg) { div([], [ h1([], [text(\""/utf8>>/binary, Type_name/binary>>/binary, "\")]), div([], [ button([event.on_click(Decrement)], [text(\"-\")]), p([], [text(int.to_string(model.count))]), button([event.on_click(Increment)], [text(\"+\")]), ]), ]) } /// Create a Lustre application for server-side rendering. pub fn app() { lustre.application(init, update, view) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 480). -spec live_handler(binary(), binary()) -> binary(). live_handler(App, Name) -> Type_name = capitalize(Name), <<<<<<<<<<<<<<<<<<<<<<<<"/// Handler for the "/utf8, Name/binary>>/binary, " live page. /// /// Serves the HTML shell that mounts the Lustre server component /// via the custom element over WebSocket. /// import "/utf8>>/binary, App/binary>>/binary, "/context.{type Context} import "/utf8>>/binary, App/binary>>/binary, "/web/layouts/root_layout import lustre/attribute import lustre/element.{text} import lustre/element/html.{div, section} import lustre/server_component import wisp.{type Request, type Response} pub fn index(_req: Request, _ctx: Context) -> Response { section([], [ // Inline the Lustre server component client runtime server_component.script(), // Mount the server component, connecting via WebSocket server_component.element( [ server_component.route(\"/"/utf8>>/binary, Name/binary>>/binary, "/ws\"), server_component.method(server_component.WebSocket), ], [text(\"Loading "/utf8>>/binary, Type_name/binary>>/binary, "...\")], ), ]) |> root_layout.wrap(\""/utf8>>/binary, Type_name/binary>>/binary, "\") |> wisp.html_response(200) } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 312). -spec live(binary()) -> nil. live(Name) -> App = refrakt@cli@project:app_name(), Live_dir = <<<<"src/"/utf8, App/binary>>/binary, "/web/live"/utf8>>, _ = simplifile:create_directory_all(Live_dir), Component_path = <<<<<>/binary, Name/binary>>/binary, ".gleam"/utf8>>, Socket_path = <<<<<>/binary, Name/binary>>/binary, "_socket.gleam"/utf8>>, Handler_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Name/binary>>/binary, "_live_handler.gleam"/utf8>>, case simplifile:write(Component_path, live_component(App, Name)) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"live"/utf8>>, line => 322, value => _assert_fail, start => 9345, 'end' => 9423, pattern_start => 9356, pattern_end => 9361}) end, case simplifile:write(Socket_path, live_socket(App, Name)) of {ok, _} -> nil; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"live"/utf8>>, line => 323, value => _assert_fail@1, start => 9426, 'end' => 9498, pattern_start => 9437, pattern_end => 9442}) end, case simplifile:write(Handler_path, live_handler(App, Name)) of {ok, _} -> nil; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"live"/utf8>>, line => 324, value => _assert_fail@2, start => 9501, 'end' => 9575, pattern_start => 9512, pattern_end => 9517}) end, _ = patch_router_live(App, Name), Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, refrakt_format_ffi:format_files( [Component_path, Socket_path, Handler_path, Router_path] ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Component_path/binary>>), gleam_stdlib:println(<<" "/utf8, Socket_path/binary>>), gleam_stdlib:println(<<" "/utf8, Handler_path/binary>>), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Updated:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Router_path/binary>>), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<"The live component runs on the server and patches the DOM"/utf8>> ), gleam_stdlib:println( <<<<"over WebSocket. Visit /"/utf8, Name/binary>>/binary, " to see it in action."/utf8>> ). -file("src/refrakt/cli/gen.gleam", 763). -spec resource_views( binary(), binary(), binary(), binary(), list({binary(), binary()}) ) -> binary(). resource_views(App_name, Resource_plural, Resource_singular, Type_name, Fields) -> First_field = case Fields of [{Name, _} | _] -> Name; [] -> <<"id"/utf8>> end, Form_field_elements = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Fname, Ftype} = F, Label_text = capitalize(Fname), case Ftype of <<"bool"/utf8>> -> <<<<<<<<<<<<" div([class(\"field\")], [ label([], [ input([type_(\"checkbox\"), name(\""/utf8, Fname/binary>>/binary, "\"), attribute.checked(values."/utf8>>/binary, Fname/binary>>/binary, ")]), text(\" "/utf8>>/binary, Label_text/binary>>/binary, "\"), ]), ]),"/utf8>>; <<"text"/utf8>> -> <<<<<<<<<<<<<<<<" div([class(\"field\")], [ label([], [text(\""/utf8, Label_text/binary>>/binary, "\")]), textarea([name(\""/utf8>>/binary, Fname/binary>>/binary, "\")], values."/utf8>>/binary, Fname/binary>>/binary, "), field_error(errors, \""/utf8>>/binary, Fname/binary>>/binary, "\"), ]),"/utf8>>; <<"int"/utf8>> -> <<<<<<<<<<<<<<<<" div([class(\"field\")], [ label([], [text(\""/utf8, Label_text/binary>>/binary, "\")]), input([type_(\"number\"), name(\""/utf8>>/binary, Fname/binary>>/binary, "\"), value(int.to_string(values."/utf8>>/binary, Fname/binary>>/binary, "))]), field_error(errors, \""/utf8>>/binary, Fname/binary>>/binary, "\"), ]),"/utf8>>; <<"float"/utf8>> -> <<<<<<<<<<<<<<<<" div([class(\"field\")], [ label([], [text(\""/utf8, Label_text/binary>>/binary, "\")]), input([type_(\"number\"), name(\""/utf8>>/binary, Fname/binary>>/binary, "\"), value(float.to_string(values."/utf8>>/binary, Fname/binary>>/binary, "))]), field_error(errors, \""/utf8>>/binary, Fname/binary>>/binary, "\"), ]),"/utf8>>; _ -> <<<<<<<<<<<<<<<<" div([class(\"field\")], [ label([], [text(\""/utf8, Label_text/binary>>/binary, "\")]), input([type_(\"text\"), name(\""/utf8>>/binary, Fname/binary>>/binary, "\"), value(values."/utf8>>/binary, Fname/binary>>/binary, ")]), field_error(errors, \""/utf8>>/binary, Fname/binary>>/binary, "\"), ]),"/utf8>> end end ), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, Float_import = case gleam@list:any( Fields, fun(F@1) -> erlang:element(2, F@1) =:= <<"float"/utf8>> end ) of true -> <<"\nimport gleam/float"/utf8>>; false -> <<""/utf8>> end, <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"import gleam/int"/utf8, Float_import/binary>>/binary, " import gleam/list import gleam/option import lustre/attribute.{class, href, name, type_, value} import lustre/element.{type Element, text} import lustre/element/html.{ a, button, div, form, h1, input, label, li, p, section, textarea, ul, } import "/utf8>>/binary, App_name/binary>>/binary, "/domain/"/utf8>>/binary, Resource_singular/binary>>/binary, ".{type "/utf8>>/binary, Type_name/binary>>/binary, "} import "/utf8>>/binary, App_name/binary>>/binary, "/web/forms/"/utf8>>/binary, Resource_singular/binary>>/binary, "_form pub fn index_view(items: List("/utf8>>/binary, Type_name/binary>>/binary, ")) -> Element(Nil) { section([class(\""/utf8>>/binary, Resource_plural/binary>>/binary, "\")], [ div([class(\"header\")], [ h1([], [text(\""/utf8>>/binary, Type_name/binary>>/binary, "s\")]), a([href(\"/"/utf8>>/binary, Resource_plural/binary>>/binary, "/new\"), class(\"btn\")], [text(\"New "/utf8>>/binary, Type_name/binary>>/binary, "\")]), ]), ul( [class(\"post-list\")], list.map(items, fn(item) { li([], [ a([href(\"/"/utf8>>/binary, Resource_plural/binary>>/binary, "/\" <> int.to_string(item.id))], [ text(item."/utf8>>/binary, First_field/binary>>/binary, "), ]), ]) }), ), ]) } pub fn show_view(item: "/utf8>>/binary, Type_name/binary>>/binary, ") -> Element(Nil) { section([class(\""/utf8>>/binary, Resource_singular/binary>>/binary, "\")], [ h1([], [text(item."/utf8>>/binary, First_field/binary>>/binary, ")]), div([class(\"actions\")], [ a( [ href(\"/"/utf8>>/binary, Resource_plural/binary>>/binary, "/\" <> int.to_string(item.id) <> \"/edit\"), class(\"btn\"), ], [text(\"Edit\")], ), ]), ]) } pub fn form_view( values: "/utf8>>/binary, Resource_singular/binary>>/binary, "_form."/utf8>>/binary, Type_name/binary>>/binary, "Form, errors: List(#(String, String)), ) -> Element(Nil) { let post_action = case values.id { option.Some(id) -> \"/"/utf8>>/binary, Resource_plural/binary>>/binary, "/\" <> int.to_string(id) option.None -> \"/"/utf8>>/binary, Resource_plural/binary>>/binary, "\" } section([class(\""/utf8>>/binary, Resource_singular/binary>>/binary, "-form\")], [ h1([], [text(case values.id { option.Some(_) -> \"Edit "/utf8>>/binary, Type_name/binary>>/binary, "\" option.None -> \"New "/utf8>>/binary, Type_name/binary>>/binary, "\" })]), form([attribute.action(post_action), attribute.method(\"post\")], [ case values.id { option.Some(_) -> input([type_(\"hidden\"), name(\"_method\"), value(\"put\")]) option.None -> text(\"\") }, "/utf8>>/binary, Form_field_elements/binary>>/binary, " button([type_(\"submit\"), class(\"btn\")], [text(\"Save\")]), ]), ]) } fn field_error( errors: List(#(String, String)), field: String, ) -> Element(Nil) { case list.find(errors, fn(e) { e.0 == field }) { Ok(#(_, message)) -> p([class(\"error\")], [text(message)]) Error(_) -> text(\"\") } } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 898). -spec resource_form(binary(), binary(), binary(), list({binary(), binary()})) -> binary(). resource_form(App_name, Resource_singular, Type_name, Fields) -> Form_fields = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Field_name, Field_type} = F, <<<<<<<<" "/utf8, Field_name/binary>>/binary, ": "/utf8>>/binary, (form_default_value(Field_type))/binary>>/binary, ","/utf8>> end ), gleam@string:join(_pipe@1, <<"\n"/utf8>>) end, Form_field_defs = begin _pipe@2 = Fields, _pipe@3 = gleam@list:map( _pipe@2, fun(F@1) -> {Name, Ft} = F@1, <<<<<<<<" "/utf8, Name/binary>>/binary, ": "/utf8>>/binary, (to_gleam_type(Ft))/binary>>/binary, ","/utf8>> end ), gleam@string:join(_pipe@3, <<"\n"/utf8>>) end, Params_field_defs = begin _pipe@4 = Fields, _pipe@5 = gleam@list:map( _pipe@4, fun(F@2) -> {Name@1, Ft@1} = F@2, <<<<<<<<" "/utf8, Name@1/binary>>/binary, ": "/utf8>>/binary, (to_gleam_type(Ft@1))/binary>>/binary, ","/utf8>> end ), gleam@string:join(_pipe@5, <<"\n"/utf8>>) end, From_form_fields = begin _pipe@6 = Fields, _pipe@7 = gleam@list:map( _pipe@6, fun(F@3) -> {Field_name@1, Field_type@1} = F@3, case Field_type@1 of <<"bool"/utf8>> -> <<<<<<<<" "/utf8, Field_name@1/binary>>/binary, ": list.any(data.values, fn(v) { v.0 == \""/utf8>>/binary, Field_name@1/binary>>/binary, "\" }),"/utf8>>; <<"int"/utf8>> -> <<<<<<<<" "/utf8, Field_name@1/binary>>/binary, ": result.unwrap(int.parse(get_value(data, \""/utf8>>/binary, Field_name@1/binary>>/binary, "\")), 0),"/utf8>>; <<"float"/utf8>> -> <<<<<<<<" "/utf8, Field_name@1/binary>>/binary, ": result.unwrap(float.parse(get_value(data, \""/utf8>>/binary, Field_name@1/binary>>/binary, "\")), 0.0),"/utf8>>; _ -> <<<<<<<<" "/utf8, Field_name@1/binary>>/binary, ": get_value(data, \""/utf8>>/binary, Field_name@1/binary>>/binary, "\"),"/utf8>> end end ), gleam@string:join(_pipe@7, <<"\n"/utf8>>) end, From_record_fields = begin _pipe@8 = Fields, _pipe@9 = gleam@list:map( _pipe@8, fun(F@4) -> {Name@2, _} = F@4, <<<<<<<<" "/utf8, Name@2/binary>>/binary, ": item."/utf8>>/binary, Name@2/binary>>/binary, ","/utf8>> end ), gleam@string:join(_pipe@9, <<"\n"/utf8>>) end, Decode_lets = begin _pipe@10 = Fields, _pipe@11 = gleam@list:filter( _pipe@10, fun(F@5) -> erlang:element(2, F@5) /= <<"bool"/utf8>> end ), _pipe@12 = gleam@list:map( _pipe@11, fun(F@6) -> {Name@3, _} = F@6, <<<<<<<<" let "/utf8, Name@3/binary>>/binary, " = get_value(data, \""/utf8>>/binary, Name@3/binary>>/binary, "\")"/utf8>> end ), gleam@string:join(_pipe@12, <<"\n"/utf8>>) end, Validation_lines = begin _pipe@13 = Fields, _pipe@14 = gleam@list:filter( _pipe@13, fun(F@7) -> {_, T} = F@7, (T =:= <<"string"/utf8>>) orelse (T =:= <<"text"/utf8>>) end ), _pipe@15 = gleam@list:map( _pipe@14, fun(F@8) -> {Name@4, _} = F@8, <<<<<<<<<<<<" |> validate.required("/utf8, Name@4/binary>>/binary, ", \""/utf8>>/binary, Name@4/binary>>/binary, "\", \""/utf8>>/binary, (capitalize(Name@4))/binary>>/binary, " is required\")"/utf8>> end ), gleam@string:join(_pipe@15, <<"\n"/utf8>>) end, Params_construction = begin _pipe@16 = Fields, _pipe@17 = gleam@list:map( _pipe@16, fun(F@9) -> {Name@5, T@1} = F@9, case T@1 of <<"bool"/utf8>> -> <<<<<<<<" "/utf8, Name@5/binary>>/binary, ": list.any(data.values, fn(v) { v.0 == \""/utf8>>/binary, Name@5/binary>>/binary, "\" }),"/utf8>>; <<"int"/utf8>> -> <<<<<<<<" "/utf8, Name@5/binary>>/binary, ": result.unwrap(int.parse("/utf8>>/binary, Name@5/binary>>/binary, "), 0),"/utf8>>; <<"float"/utf8>> -> <<<<<<<<" "/utf8, Name@5/binary>>/binary, ": result.unwrap(float.parse("/utf8>>/binary, Name@5/binary>>/binary, "), 0.0),"/utf8>>; _ -> <<<<<<<<" "/utf8, Name@5/binary>>/binary, ": "/utf8>>/binary, Name@5/binary>>/binary, ","/utf8>> end end ), gleam@string:join(_pipe@17, <<"\n"/utf8>>) end, Extra_imports = case {gleam@list:any( Fields, fun(F@10) -> erlang:element(2, F@10) =:= <<"int"/utf8>> end ), gleam@list:any( Fields, fun(F@11) -> erlang:element(2, F@11) =:= <<"float"/utf8>> end )} of {true, true} -> <<"\nimport gleam/int\nimport gleam/float"/utf8>>; {true, false} -> <<"\nimport gleam/int"/utf8>>; {false, true} -> <<"\nimport gleam/float"/utf8>>; {false, false} -> <<""/utf8>> end, <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"import gleam/list import gleam/option.{type Option, None, Some} import gleam/result"/utf8, Extra_imports/binary>>/binary, " import "/utf8>>/binary, App_name/binary>>/binary, "/domain/"/utf8>>/binary, Resource_singular/binary>>/binary, ".{type "/utf8>>/binary, Type_name/binary>>/binary, "} import refrakt/validate import wisp pub type "/utf8>>/binary, Type_name/binary>>/binary, "Form { "/utf8>>/binary, Type_name/binary>>/binary, "Form( id: Option(Int), "/utf8>>/binary, Form_field_defs/binary>>/binary, " ) } pub type "/utf8>>/binary, Type_name/binary>>/binary, "Params { "/utf8>>/binary, Type_name/binary>>/binary, "Params( "/utf8>>/binary, Params_field_defs/binary>>/binary, " ) } pub fn empty() -> "/utf8>>/binary, Type_name/binary>>/binary, "Form { "/utf8>>/binary, Type_name/binary>>/binary, "Form( id: None, "/utf8>>/binary, Form_fields/binary>>/binary, " ) } pub fn from_"/utf8>>/binary, Resource_singular/binary>>/binary, "(item: "/utf8>>/binary, Type_name/binary>>/binary, ") -> "/utf8>>/binary, Type_name/binary>>/binary, "Form { "/utf8>>/binary, Type_name/binary>>/binary, "Form( id: Some(item.id), "/utf8>>/binary, From_record_fields/binary>>/binary, " ) } pub fn from_form_data(data: wisp.FormData) -> "/utf8>>/binary, Type_name/binary>>/binary, "Form { "/utf8>>/binary, Type_name/binary>>/binary, "Form( id: None, "/utf8>>/binary, From_form_fields/binary>>/binary, " ) } pub fn decode( data: wisp.FormData, ) -> Result("/utf8>>/binary, Type_name/binary>>/binary, "Params, List(#(String, String))) { "/utf8>>/binary, Decode_lets/binary>>/binary, " let errors = [] "/utf8>>/binary, Validation_lines/binary>>/binary, " case errors { [] -> Ok("/utf8>>/binary, Type_name/binary>>/binary, "Params( "/utf8>>/binary, Params_construction/binary>>/binary, " )) _ -> Error(errors) } } fn get_value(data: wisp.FormData, key: String) -> String { list.find(data.values, fn(v) { v.0 == key }) |> result.map(fn(v) { v.1 }) |> result.unwrap(\"\") } "/utf8>>. -file("src/refrakt/cli/gen.gleam", 2329). -spec singularize(binary()) -> binary(). singularize(S) -> case gleam_stdlib:string_ends_with(S, <<"ies"/utf8>>) of true -> <<(gleam@string:drop_end(S, 3))/binary, "y"/utf8>>; false -> case gleam_stdlib:string_ends_with(S, <<"ses"/utf8>>) of true -> gleam@string:drop_end(S, 2); false -> case gleam_stdlib:string_ends_with(S, <<"s"/utf8>>) of true -> gleam@string:drop_end(S, 1); false -> S end end end. -file("src/refrakt/cli/gen.gleam", 1556). -spec resource_migration( binary(), list({binary(), binary()}), refrakt@cli@types:db_choice() ) -> binary(). resource_migration(Name, Fields, Db) -> Column_defs = begin _pipe = Fields, _pipe@1 = gleam@list:map( _pipe, fun(F) -> {Field_name, Field_type} = F, Sql_type = case Db of sqlite -> to_sql_type_sqlite(Field_type); _ -> to_sql_type(Field_type) end, <<<<<<<<" "/utf8, Field_name/binary>>/binary, " "/utf8>>/binary, Sql_type/binary>>/binary, " NOT NULL"/utf8>> end ), gleam@string:join(_pipe@1, <<",\n"/utf8>>) end, Table = <<(singularize(Name))/binary, "s"/utf8>>, case Db of sqlite -> <<<<<<<<"CREATE TABLE "/utf8, Table/binary>>/binary, " ( id INTEGER PRIMARY KEY AUTOINCREMENT, "/utf8>>/binary, Column_defs/binary>>/binary, ", inserted_at TEXT NOT NULL DEFAULT (datetime('now')), updated_at TEXT NOT NULL DEFAULT (datetime('now')) ); "/utf8>>; _ -> <<<<<<<<"CREATE TABLE "/utf8, Table/binary>>/binary, " ( id SERIAL PRIMARY KEY, "/utf8>>/binary, Column_defs/binary>>/binary, ", inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); "/utf8>> end. -file("src/refrakt/cli/gen.gleam", 2357). -spec pad_number(integer(), integer()) -> binary(). pad_number(N, Width) -> S = erlang:integer_to_binary(N), Padding = Width - string:length(S), case Padding > 0 of true -> <<(gleam@string:repeat(<<"0"/utf8>>, Padding))/binary, S/binary>>; false -> S end. -file("src/refrakt/cli/gen.gleam", 2346). -spec next_migration_number(binary()) -> binary(). next_migration_number(App) -> Dir = <<<<"src/"/utf8, App/binary>>/binary, "/data/migrations"/utf8>>, case simplifile_erl:read_directory(Dir) of {ok, Files} -> Count = erlang:length(Files) + 1, pad_number(Count, 3); {error, _} -> <<"001"/utf8>> end. -file("src/refrakt/cli/gen.gleam", 71). -spec resource(binary(), list(binary())) -> nil. resource(Name, Raw_args) -> App = refrakt@cli@project:app_name(), Db = refrakt@cli@project:detect_db(), Api_mode = gleam@list:contains(Raw_args, <<"--api"/utf8>>), Raw_fields = gleam@list:filter( Raw_args, fun(A) -> not gleam_stdlib:string_starts_with(A, <<"--"/utf8>>) end ), Singular = singularize(Name), Type_name = capitalize(Singular), Fields = parse_fields(Raw_fields), Handler_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Singular/binary>>/binary, "_handler.gleam"/utf8>>, Views_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Singular/binary>>/binary, "_views.gleam"/utf8>>, Form_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/web/forms/"/utf8>>/binary, Singular/binary>>/binary, "_form.gleam"/utf8>>, Domain_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/domain/"/utf8>>/binary, Singular/binary>>/binary, ".gleam"/utf8>>, Repo_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/data/"/utf8>>/binary, Singular/binary>>/binary, "_repo.gleam"/utf8>>, Migration_path = <<<<<<<<<<<<"src/"/utf8, App/binary>>/binary, "/data/migrations/"/utf8>>/binary, (next_migration_number(App))/binary>>/binary, "_create_"/utf8>>/binary, Name/binary>>/binary, ".sql"/utf8>>, Test_path = <<<<<<<<"test/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Singular/binary>>/binary, "_handler_test.gleam"/utf8>>, gleam@list:each( [<<<<"src/"/utf8, App/binary>>/binary, "/web/forms"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/domain"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/data"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/data/migrations"/utf8>>, <<<<"test/"/utf8, App/binary>>/binary, "/web"/utf8>>], fun(Dir) -> _ = simplifile:create_directory_all(Dir) end ), First_field = case Fields of [{Name@1, _} | _] -> Name@1; [] -> <<"id"/utf8>> end, Gleam_fields = gleam@list:map( Fields, fun(F) -> {Field_name, Field_type} = F, {Field_name, to_gleam_type(Field_type)} end ), case case Api_mode of true -> simplifile:write( Handler_path, api_resource_handler(App, Name, Singular, Type_name, Db, Fields) ); false -> simplifile:write( Handler_path, refrakt@cli@templates:resource_handler( App, Name, Singular, Type_name, First_field, Db ) ) end of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 123, value => _assert_fail, start => 3602, 'end' => 4003, pattern_start => 3613, pattern_end => 3618}) end, Created_paths = case Api_mode of false -> case simplifile:write( Views_path, resource_views(App, Name, Singular, Type_name, Fields) ) of {ok, _} -> nil; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 146, value => _assert_fail@1, start => 4121, 'end' => 4263, pattern_start => 4132, pattern_end => 4137}) end, case simplifile:write( Form_path, resource_form(App, Singular, Type_name, Fields) ) of {ok, _} -> nil; _assert_fail@2 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 151, value => _assert_fail@2, start => 4270, 'end' => 4404, pattern_start => 4281, pattern_end => 4286}) end, [Handler_path, Views_path, Form_path, Domain_path, Repo_path, Test_path]; true -> case simplifile:write( Form_path, api_params_module(App, Singular, Type_name, Fields) ) of {ok, _} -> nil; _assert_fail@3 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 160, value => _assert_fail@3, start => 4566, 'end' => 4704, pattern_start => 4577, pattern_end => 4582}) end, [Handler_path, Form_path, Domain_path, Repo_path, Test_path] end, case simplifile:write( Domain_path, refrakt@cli@templates:resource_domain_type(Type_name, Gleam_fields) ) of {ok, _} -> nil; _assert_fail@4 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 169, value => _assert_fail@4, start => 4785, 'end' => 4913, pattern_start => 4796, pattern_end => 4801}) end, case simplifile:write( Repo_path, resource_repo(App, Singular, Type_name, Fields, Db) ) of {ok, _} -> nil; _assert_fail@5 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 175, value => _assert_fail@5, start => 4917, 'end' => 5039, pattern_start => 4928, pattern_end => 4933}) end, case simplifile:write(Migration_path, resource_migration(Name, Fields, Db)) of {ok, _} -> nil; _assert_fail@6 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 181, value => _assert_fail@6, start => 5043, 'end' => 5136, pattern_start => 5054, pattern_end => 5059}) end, case simplifile:write(Test_path, case Api_mode of true -> api_resource_test(App, Singular); false -> resource_test(App, Singular, Type_name, Fields) end) of {ok, _} -> nil; _assert_fail@7 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"resource"/utf8>>, line => 184, value => _assert_fail@7, start => 5140, 'end' => 5323, pattern_start => 5151, pattern_end => 5156}) end, _ = case Api_mode of true -> patch_router_api_resource(App, Name, Singular); false -> patch_router_resource(App, Name, Singular) end, Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, refrakt_format_ffi:format_files([Router_path | Created_paths]), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Handler_path/binary>>), case Api_mode of false -> gleam_stdlib:println(<<" "/utf8, Views_path/binary>>), gleam_stdlib:println(<<" "/utf8, Form_path/binary>>); true -> nil end, gleam_stdlib:println(<<" "/utf8, Domain_path/binary>>), gleam_stdlib:println(<<" "/utf8, Repo_path/binary>>), gleam_stdlib:println(<<" "/utf8, Migration_path/binary>>), gleam_stdlib:println(<<" "/utf8, Test_path/binary>>), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Updated:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Router_path/binary>>). -file("src/refrakt/cli/gen.gleam", 221). -spec migration(binary()) -> nil. migration(Name) -> App = refrakt@cli@project:app_name(), Dir = <<<<"src/"/utf8, App/binary>>/binary, "/data/migrations"/utf8>>, _ = simplifile:create_directory_all(Dir), Number = next_migration_number(App), Filename = <<<<<>/binary, Name/binary>>/binary, ".sql"/utf8>>, Path = <<<>/binary, Filename/binary>>, Content = <<<<<<<<"-- Migration: "/utf8, Name/binary>>/binary, "\n-- Created: "/utf8>>/binary, Number/binary>>/binary, "\n\n"/utf8>>, case simplifile:write(Path, Content) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"migration"/utf8>>, line => 232, value => _assert_fail, start => 6582, 'end' => 6632, pattern_start => 6593, pattern_end => 6598}) end, gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Path/binary>>). -file("src/refrakt/cli/gen.gleam", 243). -spec auth() -> nil. auth() -> App = refrakt@cli@project:app_name(), gleam@list:each( [<<<<"src/"/utf8, App/binary>>/binary, "/web/forms"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/web/middleware"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/domain"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/data"/utf8>>, <<<<"src/"/utf8, App/binary>>/binary, "/data/migrations"/utf8>>, <<<<"test/"/utf8, App/binary>>/binary, "/web"/utf8>>], fun(Dir) -> _ = simplifile:create_directory_all(Dir) end ), Files = [{<<<<"src/"/utf8, App/binary>>/binary, "/domain/user.gleam"/utf8>>, auth_user_type()}, {<<<<"src/"/utf8, App/binary>>/binary, "/domain/auth.gleam"/utf8>>, auth_domain(App)}, {<<<<"src/"/utf8, App/binary>>/binary, "/data/user_repo.gleam"/utf8>>, auth_user_repo(App)}, {<<<<<<<<"src/"/utf8, App/binary>>/binary, "/data/migrations/"/utf8>>/binary, (next_migration_number(App))/binary>>/binary, "_create_users.sql"/utf8>>, auth_migration()}, {<<<<"src/"/utf8, App/binary>>/binary, "/web/forms/auth_form.gleam"/utf8>>, auth_form(App)}, {<<<<"src/"/utf8, App/binary>>/binary, "/web/auth_handler.gleam"/utf8>>, auth_handler(App)}, {<<<<"src/"/utf8, App/binary>>/binary, "/web/auth_views.gleam"/utf8>>, auth_views(App)}, {<<<<"src/"/utf8, App/binary>>/binary, "/web/middleware/auth.gleam"/utf8>>, auth_middleware(App)}, {<<<<"test/"/utf8, App/binary>>/binary, "/web/auth_handler_test.gleam"/utf8>>, auth_test(App)}], gleam@list:each( Files, fun(File) -> {Path, Content} = File, _assert_subject = simplifile:write(Path, Content), case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"auth"/utf8>>, line => 282, value => _assert_fail, start => 8083, 'end' => 8133, pattern_start => 8094, pattern_end => 8099}) end end ), _ = patch_router_auth(App), Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, Gleam_paths = gleam@list:filter_map( Files, fun(File@1) -> case gleam_stdlib:string_ends_with( erlang:element(1, File@1), <<".gleam"/utf8>> ) of true -> {ok, erlang:element(1, File@1)}; false -> {error, nil} end end ), refrakt_format_ffi:format_files([Router_path | Gleam_paths]), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam@list:each( Files, fun(File@2) -> gleam_stdlib:println( <<" "/utf8, (erlang:element(1, File@2))/binary>> ) end ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Updated:"/utf8>>), gleam_stdlib:println( <<<<" src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>> ), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println( <<"Note: You need a password hashing library. Add one with:"/utf8>> ), gleam_stdlib:println(<<" gleam add beecrypt"/utf8>>). -file("src/refrakt/cli/gen.gleam", 2366). -spec ensure_dir_for(binary()) -> nil. ensure_dir_for(Path) -> case gleam@string:split(Path, <<"/"/utf8>>) of [] -> nil; Parts -> Dir = begin _pipe = Parts, _pipe@1 = gleam@list:take(_pipe, erlang:length(Parts) - 1), gleam@string:join(_pipe@1, <<"/"/utf8>>) end, _ = simplifile:create_directory_all(Dir), nil end. -file("src/refrakt/cli/gen.gleam", 17). -spec page(binary()) -> nil. page(Name) -> App = refrakt@cli@project:app_name(), Handler_path = <<<<<<<<"src/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Name/binary>>/binary, "_handler.gleam"/utf8>>, Test_path = <<<<<<<<"test/"/utf8, App/binary>>/binary, "/web/"/utf8>>/binary, Name/binary>>/binary, "_handler_test.gleam"/utf8>>, Handler_content = <<<<<<<<<<<<<<<<<<<<"import "/utf8, App/binary>>/binary, "/context.{type Context} import "/utf8>>/binary, App/binary>>/binary, "/web/layouts/root_layout import lustre/attribute.{class} import lustre/element.{text} import lustre/element/html.{h1, section} import wisp.{type Request, type Response} pub fn index(_req: Request, _ctx: Context) -> Response { section([class(\""/utf8>>/binary, Name/binary>>/binary, "\")], [ h1([], [text(\""/utf8>>/binary, (capitalize(Name))/binary>>/binary, "\")]), ]) |> root_layout.wrap(\""/utf8>>/binary, (capitalize(Name))/binary>>/binary, "\") |> wisp.html_response(200) } "/utf8>>, Test_content = <<"import gleeunit/should pub fn placeholder_test() { 1 + 1 |> should.equal(2) } "/utf8>>, case simplifile:write(Handler_path, Handler_content) of {ok, _} -> nil; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"page"/utf8>>, line => 49, value => _assert_fail, start => 1318, 'end' => 1384, pattern_start => 1329, pattern_end => 1334}) end, ensure_dir_for(Test_path), case simplifile:write(Test_path, Test_content) of {ok, _} -> nil; _assert_fail@1 -> erlang:error(#{gleam_error => let_assert, message => <<"Pattern match failed, no pattern matched the value."/utf8>>, file => <>, module => <<"refrakt/cli/gen"/utf8>>, function => <<"page"/utf8>>, line => 51, value => _assert_fail@1, start => 1415, 'end' => 1475, pattern_start => 1426, pattern_end => 1431}) end, _ = patch_router_page(App, Name), Router_path = <<<<"src/"/utf8, App/binary>>/binary, "/router.gleam"/utf8>>, refrakt_format_ffi:format_files([Handler_path, Test_path, Router_path]), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Created:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Handler_path/binary>>), gleam_stdlib:println(<<" "/utf8, Test_path/binary>>), gleam_stdlib:println(<<""/utf8>>), gleam_stdlib:println(<<"Updated:"/utf8>>), gleam_stdlib:println(<<" "/utf8, Router_path/binary>>).