<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:#0563C1;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:#954F72;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"HTML Preformatted Char";
        margin:0in;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";}
span.HTMLPreformattedChar
        {mso-style-name:"HTML Preformatted Char";
        mso-style-priority:99;
        mso-style-link:"HTML Preformatted";
        font-family:"Courier New";}
span.EmailStyle19
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link="#0563C1" vlink="#954F72"><div class=WordSection1><p class=MsoNormal><span style='font-size:12.0pt'>Hi fellows,<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Here I show some examples of how to work with the little framework for cowboy that I am making, I will be glad of hear some opinions from the community in order to help improve it. I must say that I will release it to the community as soon as it is ready for shown (the first version).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>(This will be about database stuffs)<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>First you configure the backends in a config file </span><span style='font-size:10.0pt;font-family:Consolas'>app.config</span><span style='font-size:12.0pt'>. (you can configure as many backends as you want, even in runtime you can update and install database backends). I’ll show you how.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>%% Database backends configuration.<br>{database_manager, [<br>    {main_backend, [<br>        {backend, postgres_backend},<br>        {server, "localhost"},<br>        {username, "postgres"},<br>        {password, "server"},<br>        {database, "my_main_db"},<br>        %% max amount of database connections in the connection pool.<br>        {max_reusable_connections, 10}, % 10 connections.<br>        %% max time it will wait for an available connection.<br>        {wait_for_reusable_connection_timeout, 5000} % 5 seconds.<br>    ]},<br>    {test_backend, [<br>        {backend, postgres_backend},<br>        {server, "localhost"},<br>        {username, "postgres"},<br>        {password, "server"},<br>        {database, "test_db"},<br>        %% max amount of database connections in the connection pool.<br>        {max_reusable_connections, 50}, % 10 connections.<br>        %% max time it will wait for an available connection.<br>        {wait_for_reusable_connection_timeout, 3000} % 3 seconds.<br>    ]}<br>]}<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>To install a backend at runtime use </span><span style='font-size:10.0pt;font-family:Consolas'>database_manager:install_backend/2</span><span style='font-size:12.0pt'>, passing the backend name and config, also has </span><span style='font-size:10.0pt;font-family:Consolas'>update_backend/2</span><span style='font-size:12.0pt'>.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Later you will use this in a simple way:</span><span style='font-size:14.0pt'><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>database_manager:connection_session(fun(DBSession)-> … end, [{backend, test_backend}]).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>'connection_session/1'</span><span style='font-size:12.0pt'> give us an available connection from the connection pool. Each configured backend has its own connection pool, so we can use they as we like having the possibility of use multiple backend in runtime and at the same time.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Let’s see some examples of the current database functionalities the framework has:<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>database_manager:connection_session(fun(DBSession) -><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    database_manager:insert(DBSession, {users, #{username => "John", age => 31}})<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>end).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>If no backend option is defined in </span><span style='font-size:10.0pt;font-family:Consolas'>'connection_session'</span><span style='font-size:14.0pt'>, </span><span style='font-size:10.0pt;font-family:Consolas'>'main_backend'</span><span style='font-size:12.0pt'> will be used.</span><span style='font-size:14.0pt'><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>database_manager:connection_session_transaction(fun(DBSession) -><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, #{id := UserId}} = database_manager:insert(DBSession, {users, #{username => "John", age => 31}}, [{return_fields, [id]}]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, 1} = database_manager:insert(DBSession, {roles, #{user_id => UserId, role_level => 1}})<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>end).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>We also have</span><span style='font-size:14.0pt'> </span><span style='font-size:10.0pt;font-family:Consolas'>'database_manager:transaction/1'</span><span style='font-size:14.0pt'> for use with </span><span style='font-size:10.0pt;font-family:Consolas'>'connection_session'</span><span style='font-size:12.0pt'> as we like.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>It has more functions like update, delete, find. i.e.:</span><span style='font-size:14.0pt'><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>database_manager:connection_session(fun(DBSession) -><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, DataMap} = database_manager:find(DBSession, users, [{username, '==', "John"}])<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>end).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>We can use </span><span style='font-size:10.0pt;font-family:Consolas'>'return_fields'</span><span style='font-size:12.0pt'> option also to select just the fields we want.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>That was the low level API, it also have a high level API for model validation and of course you can mix between them as you wish.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Example:<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>To use the high level model API you need to create a module file that implement a behavior of </span><span style='font-size:10.0pt;font-family:Consolas'>'model'</span><span style='font-size:12.0pt'>. The nice thing here is that you can use validation functions by context, using tags.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:14.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>-module(users_model).<br>-behavior(model).<br><br>-export([<br>    validation_tests/1,<br>    after_validate/1]).<br><br>validation_tests(ModelDataMap) -><br>    {username := Username, online := Online,<br>    password := Password} = ModelDataMap,<br>    [<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>        %% tag for common validation tests.<br>        {common, [<br>            %% username is required<br>            {fun() -><br>                size(Username) =/= 0<br>             end, "username cannot be empty"}]},<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>        {new, [<br>            %% password cannot be empty<br>            {fun() -><br>                size(Password) =/= 0<br>             end, "password cannot be empty"}]},<br>        {update, [<br>            %% online must be true or false<br>            {fun() -><br>                (Online == true) or (Online == false)<br>             end, "online is not true or false"}]}<br>       ].<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>%% optional<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>after_validate(ModelDataMap) -><br>    ok.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>%% optional<o:p></o:p></span></p><p class=MsoNormal>id_field_name() -><o:p></o:p></p><p class=MsoNormal>    id.<o:p></o:p></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Then you can write<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>{ok, ModelInfo} = model_manager:new_model(users, #{<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                      username => "John",<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                      password => "server213*-+",<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                      password_old => password},<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                          [common, new]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>{ok, UserId} = model_manager:store(ModelInfo, [return_id]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>{ok, ModelInfo2} = model_manager:update_model(roles, UserId, #{role_level => 1}, [common, update]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>ok = model_manager:store_model(ModelInfo2).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Note three things here:<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'> - first you can use tags to separate validation tests by context, for example, here I use </span><span style='font-size:10.0pt;font-family:Consolas'>'common'</span><span style='font-size:12.0pt'> to use that validation function for both new and update, and one for each of them. You can choose the name you want. But </span><span style='font-size:10.0pt;font-family:Consolas'>'always'</span><span style='font-size:12.0pt'> is a special name that is used when you don’t specify any tag in </span><span style='font-size:10.0pt;font-family:Consolas'>'new_model'</span><span style='font-size:12.0pt'> or </span><span style='font-size:10.0pt;font-family:Consolas'>'update_model'</span><span style='font-size:12.0pt'> functions, them </span><span style='font-size:10.0pt;font-family:Consolas'>'always'</span><span style='font-size:12.0pt'> tag will be used.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'> - second you can use </span><span style='font-size:10.0pt;font-family:Consolas'>'return_id'</span><span style='font-size:12.0pt'> option to return just the id of the inserted record but you can also use </span><span style='font-size:10.0pt;font-family:Consolas'>'return_fields'</span><span style='font-size:12.0pt'> to return any other field. In other to make the framework knows which is the id for </span><span style='font-size:10.0pt;font-family:Consolas'>'return_id'</span><span style='font-size:12.0pt'> option we must use </span><span style='font-size:10.0pt;font-family:Consolas'>'id'</span><span style='font-size:12.0pt'> for the name in the database or specify which is the name of the id in the model module using 'id_field_name/0' function.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'> - third we can do stuffs like this #{</span><span style='font-size:10.0pt;font-family:Consolas'>username => "John", password => "server213*-+", <b><span style='color:red'>password_old => password</span></b>}</span><span style='font-size:12.0pt'>, meaning that </span><span style='font-size:10.0pt;font-family:Consolas'>'passworld_old'</span><span style='font-size:12.0pt'> will take the value of </span><span style='font-size:10.0pt;font-family:Consolas'>'password'</span><span style='font-size:12.0pt'>.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>There are many other options and functions in the API, for example you can mix between low level API and High level API using<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>model_manager:store_session(fun(DBSession) -> … end)</span><span style='font-size:12.0pt'>. You of course can use all functionalities form the low level API in the High one, like backend options and many other.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>Using '</span><span style='font-size:10.0pt;font-family:Consolas'>model_manager:store_session/1/2</span><span style='font-size:12.0pt'>' when using multiple '</span><span style='font-size:10.0pt;font-family:Consolas'>store_model</span><span style='font-size:12.0pt'>' in the same function is recommended because with it you hold the same connection for all '</span><span style='font-size:10.0pt;font-family:Consolas'>store_model</span><span style='font-size:12.0pt'>' and low level API operations.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>So this will be ok:<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>model_manager:store_session_transaction(fun(_) -><o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, ModelInfo} = model_manager:new_model(users, #{<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                          username => "John",<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                          password => "server213*-+",<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                          password_old => password},<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>                              [common, new]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, UserId} = model_manager:store(ModelInfo, [return_id]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    {ok, ModelInfo2} = model_manager:update_model(roles, UserId, #{role_level => 1}, [common, update]),<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>    ok = model_manager:store_model(ModelInfo2)<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>end, [{backend, test_backend}]).<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:12.0pt'>If any of the functions fail or the pattern matching fails the hold transaction will rollback.<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'> <o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>Cheers,<o:p></o:p></span></p><p class=MsoNormal><span style='font-size:10.0pt;font-family:Consolas'>Ivan (son of Gilberio).<o:p></o:p></span></p></div></body></html>