Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/my_first_nova/config/dev_sys.config.src
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@
read_urlencoded_body => true}}
]}
]}
%% Please change your app.src-file instead if you intend to add app-specific configurations
},
{my_first_nova, [
{database, <<"my_first_nova_dev">>}
]}
].
16 changes: 16 additions & 0 deletions examples/my_first_nova/config/test_sys.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[
{nova, [
{environment, test},
{cowboy_configuration, #{
port => 8099
}},
{bootstrap_application, my_first_nova},
{plugins, [
{pre_request, nova_request_plugin, #{decode_json_body => true,
read_urlencoded_body => true}}
]}
]},
{my_first_nova, [
{database, <<"my_first_nova_dev">>}
]}
].
14 changes: 14 additions & 0 deletions examples/my_first_nova/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
services:
postgres:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: my_first_nova_dev
volumes:
- pgdata:/var/lib/postgresql/data

volumes:
pgdata:
11 changes: 0 additions & 11 deletions examples/my_first_nova/priv/schemas/product.json

This file was deleted.

10 changes: 0 additions & 10 deletions examples/my_first_nova/priv/schemas/user.json

This file was deleted.

83 changes: 51 additions & 32 deletions examples/my_first_nova/rebar.config
Original file line number Diff line number Diff line change
@@ -1,48 +1,67 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-

{erl_opts, [debug_info]}.
{src_dirs, ["src", "src/controllers"]}.
{src_dirs, [{"src", [{recursive, true}]}]}.
{shell, [{config, "./config/dev_sys.config.src"}]}.

{erlydtl_opts, [{doc_root, "src/views"},
{recursive, true},
{libraries, [
{nova_erlydtl_inventory, nova_erlydtl_inventory}
]},
{default_libraries, [nova_erlydtl_inventory]}
]}.
{erlydtl_opts, [
{doc_root, "src/views"},
{recursive, true},
{libraries, [
{nova_erlydtl_inventory, nova_erlydtl_inventory}
]},
{default_libraries, [nova_erlydtl_inventory]}
]}.

{deps, [
nova,
{flatlog, "0.1.2"} %% Used for logging - Change if needed
]}.

nova,
%% Used for logging - Change if needed
{flatlog, "0.1.2"},
{kura, "~> 0.3"}
]}.

%% Release profiles
%% To create a release just run
%% rebar3 as prod release
{relx, [{release, {my_first_nova, git},
[my_first_nova,
sasl]},
{mode, dev},
{sys_config_src, "./config/dev_sys.config.src"},
{vm_args_src, "./config/vm.args.src"}
]}.

{profiles, [{prod, [{relx,
[{mode, prod},
{sys_config_src, "./config/prod_sys.config.src"}]}]}]}.
{relx, [
{release, {my_first_nova, git}, [
my_first_nova,
sasl
]},
{mode, dev},
{sys_config_src, "./config/dev_sys.config.src"},
{vm_args_src, "./config/vm.args.src"}
]}.

{profiles, [
{prod, [
{relx, [
{mode, prod},
{sys_config_src, "./config/prod_sys.config.src"}
]}
]},
{test, [
{deps, [meck, nova_test]},
{ct_opts, [{sys_config, ["config/test_sys.config"]}]}
]}
]}.

%% Plugins for rebar3
{plugins, [
{rebar3_erlydtl_plugin, ".*",
{git, "https://github.com/tsloughter/rebar3_erlydtl_plugin.git", {branch, "master"}}},
{rebar3_erldb_plugin, ".*",
{git, "https://github.com/erldb/rebar3_erldb_plugin.git", {branch, "master"}}},
{rebar3_nova, ".*",
{git, "https://github.com/novaframework/rebar3_nova.git", {branch, "master"}}}
]}.
{rebar3_erlydtl_plugin, ".*",
{git, "https://github.com/tsloughter/rebar3_erlydtl_plugin.git", {branch, "master"}}},
{rebar3_nova, ".*",
{git, "https://github.com/novaframework/rebar3_nova.git", {branch, "master"}}}
]}.

{project_plugins, [
{rebar3_kura, "~> 0.3"},
erlfmt
]}.

{provider_hooks, [
{pre, [{compile, {erlydtl, compile}}]}
]}.
{pre, [
{compile, {erlydtl, compile}},
{compile, {kura, compile}}
]}
]}.
47 changes: 47 additions & 0 deletions examples/my_first_nova/rebar.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{"1.2.0",
[{<<"backoff">>,{pkg,<<"backoff">>,<<"1.1.6">>},2},
{<<"cowboy">>,{pkg,<<"cowboy">>,<<"2.13.0">>},1},
{<<"cowlib">>,{pkg,<<"cowlib">>,<<"2.16.0">>},2},
{<<"erlydtl">>,{pkg,<<"erlydtl">>,<<"0.14.0">>},1},
{<<"flatlog">>,{pkg,<<"flatlog">>,<<"0.1.2">>},0},
{<<"jhn_stdlib">>,{pkg,<<"jhn_stdlib">>,<<"5.4.0">>},1},
{<<"kura">>,{pkg,<<"kura">>,<<"0.3.0">>},0},
{<<"nova">>,{pkg,<<"nova">>,<<"0.13.1">>},0},
{<<"opentelemetry_api">>,{pkg,<<"opentelemetry_api">>,<<"1.5.0">>},2},
{<<"pg_types">>,{pkg,<<"pg_types">>,<<"0.6.0">>},2},
{<<"pgo">>,{pkg,<<"pgo">>,<<"0.20.0">>},1},
{<<"ranch">>,{pkg,<<"ranch">>,<<"2.2.0">>},2},
{<<"routing_tree">>,{pkg,<<"routing_tree">>,<<"1.0.11">>},1},
{<<"thoas">>,{pkg,<<"thoas">>,<<"1.2.1">>},1}]}.
[
{pkg_hash,[
{<<"backoff">>, <<"83B72ED2108BA1EE8F7D1C22E0B4A00CFE3593A67DBC792799E8CCE9F42F796B">>},
{<<"cowboy">>, <<"09D770DD5F6A22CC60C071F432CD7CB87776164527F205C5A6B0F24FF6B38990">>},
{<<"cowlib">>, <<"54592074EBBBB92EE4746C8A8846E5605052F29309D3A873468D76CDF932076F">>},
{<<"erlydtl">>, <<"964B2DC84F8C17ACFAA69C59BA129EF26AC45D2BA898C3C6AD9B5BDC8BA13CED">>},
{<<"flatlog">>, <<"8C4B81A4931A1396254DBD975B841F4A6350D6F128FF94FFE86799A4451E32B1">>},
{<<"jhn_stdlib">>, <<"FAC6F19B35351278F1CB156E23A5B2A6047A9DD5AB1FD9E1189A7918006DF7ED">>},
{<<"kura">>, <<"4B0391AF6B6CB8E010B6A88BF88BB6E420379C6FE453B5E627E9C320916F9717">>},
{<<"nova">>, <<"6A2F3E9D69FB12AA10CA530F53049A4A25005F8E816587B150CB86BEDDAF85DB">>},
{<<"opentelemetry_api">>, <<"1A676F3E3340CAB81C763E939A42E11A70C22863F645AA06AAFEFC689B5550CF">>},
{<<"pg_types">>, <<"B530C56330A59288BE49CDD27739EC025B6E877A475AE70BF95B04F1E3A817C4">>},
{<<"pgo">>, <<"4F4A1FCB0A4894311BE238195BDAD4DF80312AB091DB87FE5348FAFA4DA75F87">>},
{<<"ranch">>, <<"25528F82BC8D7C6152C57666CA99EC716510FE0925CB188172F41CE93117B1B0">>},
{<<"routing_tree">>, <<"72ACEF2095F0EC804F7AFD07EF781DDE5009425A1CA0A28F0706B1DB334A4812">>},
{<<"thoas">>, <<"19A25F31177A17E74004D4840F66D791D4298C5738790FA2CC73731EB911F195">>}]},
{pkg_hash_ext,[
{<<"backoff">>, <<"CF0CFFF8995FB20562F822E5CC47D8CCF664C5ECDC26A684CBE85C225F9D7C39">>},
{<<"cowboy">>, <<"E724D3A70995025D654C1992C7B11DBFEA95205C047D86FF9BF1CDA92DDC5614">>},
{<<"cowlib">>, <<"7F478D80D66B747344F0EA7708C187645CFCC08B11AA424632F78E25BF05DB51">>},
{<<"erlydtl">>, <<"D80EC044CD8F58809C19D29AC5605BE09E955040911B644505E31E9DD8143431">>},
{<<"flatlog">>, <<"FDD2A311A67F63F9D0BC194FAD6BEAF9CCCDE8FFFEE2919DF1C4D86098E49984">>},
{<<"jhn_stdlib">>, <<"7EABD1B01D2DEFF495BF7C5CA1DBA4D3FA0B84DC3AF03CA85F31D52EBB03C6FC">>},
{<<"kura">>, <<"63BF8E6A0C7430DE6BBB8FA97F5E918FCA5DEE936D080EE52CB753A908131344">>},
{<<"nova">>, <<"B6B0B66DFEBD427944C9AFB2E1F9046F707E4F647AB7F1884CBDE3FEA84396DC">>},
{<<"opentelemetry_api">>, <<"F53EC8A1337AE4A487D43AC89DA4BD3A3C99DDF576655D071DEED8B56A2D5DDA">>},
{<<"pg_types">>, <<"9949A4849DD13408FA249AB7B745E0D2DFDB9532AEE2B9722326E33CD082A778">>},
{<<"pgo">>, <<"2F11E6649CEB38E569EF56B16BE1D04874AE5B11A02867080A2817CE423C683B">>},
{<<"ranch">>, <<"FA0B99A1780C80218A4197A59EA8D3BDAE32FBFF7E88527D7D8A4787EFF4F8E7">>},
{<<"routing_tree">>, <<"85982C7AC502892C5179CD2A591331003BACD2D2A71723640BA7D23F45408E6E">>},
{<<"thoas">>, <<"E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A">>}]}
].
Original file line number Diff line number Diff line change
@@ -1,23 +1,33 @@
-module(my_first_nova_api_controller).
-include_lib("kura/include/kura.hrl").
-export([
index/1,
show/1,
create/1
]).
index/1,
show/1,
create/1
]).

index(_Req) ->
Users = [
#{id => 1, name => <<"Alice">>, email => <<"alice@example.com">>},
#{id => 2, name => <<"Bob">>, email => <<"bob@example.com">>}
],
{ok, Users} = my_first_nova_repo:all(kura_query:from(user)),
{json, #{users => Users}}.

show(#{bindings := #{<<"id">> := Id}}) ->
{json, #{id => binary_to_integer(Id), name => <<"Alice">>, email => <<"alice@example.com">>}};
case my_first_nova_repo:get(user, binary_to_integer(Id)) of
{ok, User} ->
{json, User};
{error, not_found} ->
{status, 404, #{}, #{error => <<"not found">>}}
end;
show(_Req) ->
{status, 400, #{}, #{error => <<"missing id">>}}.

create(#{json := #{<<"name">> := Name, <<"email">> := Email}}) ->
{json, 201, #{}, #{id => 3, name => Name, email => Email}};
create(#{json := Params}) ->
CS = kura_changeset:cast(user, #{}, Params, [name, email]),
CS1 = kura_changeset:validate_required(CS, [name, email]),
case my_first_nova_repo:insert(CS1) of
{ok, User} ->
{json, 201, #{}, User};
{error, Changeset} ->
{status, 422, #{}, #{errors => Changeset#kura_changeset.errors}}
end;
create(_Req) ->
{status, 422, #{}, #{error => <<"name and email required">>}}.
Original file line number Diff line number Diff line change
@@ -1,41 +1,63 @@
-module(my_first_nova_products_controller).
-include_lib("kura/include/kura.hrl").
-export([
list/1,
show/1,
create/1,
update/1,
delete/1
]).
list/1,
show/1,
create/1,
update/1,
delete/1
]).

list(_Req) ->
Products = [
#{id => 1, name => <<"Widget">>, price => 999, description => <<"A fine widget">>},
#{id => 2, name => <<"Gadget">>, price => 1999, description => <<"A fancy gadget">>}
],
{ok, Products} = my_first_nova_repo:all(kura_query:from(product)),
{json, #{products => Products}}.

show(#{bindings := #{<<"id">> := Id}}) ->
{json, #{id => binary_to_integer(Id),
name => <<"Widget">>,
price => 999,
description => <<"A fine widget">>}};
case my_first_nova_repo:get(product, binary_to_integer(Id)) of
{ok, Product} ->
{json, Product};
{error, not_found} ->
{status, 404, #{}, #{error => <<"not found">>}}
end;
show(_Req) ->
{status, 400, #{}, #{error => <<"missing id">>}}.

create(#{params := #{<<"name">> := Name, <<"price">> := Price}} = Req) ->
Desc = maps:get(<<"description">>, maps:get(params, Req, #{}), <<>>),
{json, 201, #{}, #{id => 3, name => Name, price => Price, description => Desc}};
create(#{json := Params}) ->
CS = kura_changeset:cast(product, #{}, Params, [name, price, description]),
CS1 = kura_changeset:validate_required(CS, [name, price]),
case my_first_nova_repo:insert(CS1) of
{ok, Product} ->
{json, 201, #{}, Product};
{error, Changeset} ->
{status, 422, #{}, #{errors => Changeset#kura_changeset.errors}}
end;
create(_Req) ->
{status, 422, #{}, #{error => <<"name and price required">>}}.

update(#{bindings := #{<<"id">> := Id},
params := #{<<"name">> := Name, <<"price">> := Price}} = Req) ->
Desc = maps:get(<<"description">>, maps:get(params, Req, #{}), <<>>),
{json, #{id => binary_to_integer(Id), name => Name, price => Price, description => Desc}};
update(#{bindings := #{<<"id">> := Id}, json := Params}) ->
case my_first_nova_repo:get(product, binary_to_integer(Id)) of
{ok, Existing} ->
CS = kura_changeset:cast(product, Existing, Params, [name, price, description]),
case my_first_nova_repo:update(CS) of
{ok, Updated} ->
{json, Updated};
{error, Changeset} ->
{status, 422, #{}, #{errors => Changeset#kura_changeset.errors}}
end;
{error, not_found} ->
{status, 404, #{}, #{error => <<"not found">>}}
end;
update(_Req) ->
{status, 422, #{}, #{error => <<"name and price required">>}}.
{status, 422, #{}, #{error => <<"invalid request">>}}.

delete(#{bindings := #{<<"id">> := _Id}}) ->
{status, 204};
delete(#{bindings := #{<<"id">> := Id}}) ->
case my_first_nova_repo:get(product, binary_to_integer(Id)) of
{ok, Record} ->
CS = kura_changeset:cast(product, Record, #{}, []),
{ok, _} = my_first_nova_repo:delete(CS),
{status, 204};
{error, not_found} ->
{status, 404, #{}, #{error => <<"not found">>}}
end;
delete(_Req) ->
{status, 400, #{}, #{error => <<"missing id">>}}.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-module(m20260214180502_update_schema).
-behaviour(kura_migration).
-include_lib("kura/include/kura.hrl").
-export([up/0, down/0]).

up() ->
[{create_table, <<"products">>, [
#kura_column{name = id, type = id, primary_key = true, nullable = false},
#kura_column{name = name, type = string, nullable = false},
#kura_column{name = price, type = integer, nullable = false},
#kura_column{name = description, type = text},
#kura_column{name = inserted_at, type = utc_datetime},
#kura_column{name = updated_at, type = utc_datetime}
]},
{create_table, <<"users">>, [
#kura_column{name = id, type = id, primary_key = true, nullable = false},
#kura_column{name = name, type = string, nullable = false},
#kura_column{name = email, type = string, nullable = false},
#kura_column{name = inserted_at, type = utc_datetime},
#kura_column{name = updated_at, type = utc_datetime}
]}].

down() ->
[{drop_table, <<"products">>},
{drop_table, <<"users">>}].
Loading