Browse Source

add postgresql queries with pool

221V 1 year ago
parent
commit
caa594ac60

+ 6 - 0
apps/n2o_sample/src/hm.erl

@@ -17,6 +17,9 @@
 
 %% todo mv this funcs to framework
 
+%% other
+% assert_int(X)
+
 %% get params
 
 
@@ -74,3 +77,6 @@ post_value2([Val|_]) -> Val;
 post_value2(_) -> undefined.
 
 
+assert_int(X) when erlang:is_integer(X) -> ok.
+
+

+ 2 - 2
apps/n2o_sample/src/n2o_sample_app.erl

@@ -12,8 +12,8 @@
 %main(A)    -> mad:main(A).
 %start()    -> start(normal,[]).
 start(_,_) ->
-  %%[application:start(A) || A <- [asn1,kernel,stdlib,fs,ranch,compiler,syntax_tools,mnesia,crypto,inets,kvs,cowlib,public_key,ssl,cowboy,n4u,n4u_sample,active,avz,epgsql,erlydtl,gproc,jsone,mad,nitro,oauth,rest,sh] ],
-  [application:start(A) || A <- [asn1,kernel,stdlib,fs,ranch,compiler,syntax_tools,mnesia,crypto,inets,kvs,cowlib,public_key,ssl,cowboy,n4u,active,avz,epgsql,erlydtl,gproc,jsone,mad,nitro,oauth,rest,sh] ],
+  %%[application:start(A) || A <- [asn1,kernel,stdlib,fs,ranch,compiler,syntax_tools,mnesia,crypto,inets,kvs,cowlib,public_key,ssl,cowboy,n4u,n4u_sample,active,avz,epgsql,pooler,epgsql_pool,erlydtl,gproc,jsone,mad,nitro,oauth,rest,sh] ],
+  [application:start(A) || A <- [asn1,kernel,stdlib,fs,ranch,compiler,syntax_tools,mnesia,crypto,inets,kvs,cowlib,public_key,ssl,cowboy,n4u,active,avz,epgsql,pooler,epgsql_pool,erlydtl,gproc,jsone,mad,nitro,oauth,rest,sh] ],
   
   {ok, _} = application:ensure_all_started(ranch),
   {ok, _} = application:ensure_all_started(cowboy),

+ 16 - 0
apps/n2o_sample/src/n2o_sample_sup.erl

@@ -24,6 +24,22 @@ init([]) ->
   users:init(),
   users:populate(?USERS),
   kvs:join(),
+  
+  Params = #{host => application:get_env(n4u, pgs_host, "localhost"), %% gets settings from sys.config
+    port => application:get_env(n4u, pgs_port, 6432),                 %% and start postgresql connections pool
+    username => application:get_env(n4u, pgs_user, "user"),
+    password => application:get_env(n4u, pgs_pass, "pass"),
+    database => application:get_env(n4u, pgs_db, "test")},
+  
+  case epgsql_pool:start(my_main_pool, 10, 50, Params) of
+    {ok, _} ->
+      io:format("~p~n", ["pg_pool start !!"]),
+      ok;
+    Err ->
+      io:format("Pool start err: ~p~n~p~n", ["err db connect", Err]),
+      err
+  end,
+  
   {ok, {{one_for_one, 10, 10}, [spec()]}}.
 
 

+ 62 - 11
apps/n2o_sample/src/pgm.erl

@@ -4,11 +4,17 @@
 
 
 -export([
-  mypg/0,
-  transaction/2,
-  select/3,
-  in_up_del/3,
-  returning/3
+  mypg/0,        %% without pool
+  transaction/2, %% without pool
+  select/3,      %% without pool
+  in_up_del/3,   %% without pool
+  returning/3,   %% without pool
+  
+  transaction/1,   %% with pool
+  transaction_q/3, %% with pool
+  select/2,        %% with pool
+  in_up_del/2,     %% with pool
+  returning/2      %% with pool
 ]).
 
 
@@ -52,9 +58,9 @@ select(Ppid, Q, A) ->
   case epgsql:equery(Ppid, Q, A) of
     {ok, _, R} ->
       R;
-    {error, E} ->
+    {error, E} = Err ->
       io:format("~p~n", [E]),
-      {error, E}
+      Err
   end.
 
 
@@ -62,9 +68,9 @@ in_up_del(Ppid, Q, A) ->
   case epgsql:equery(Ppid, Q, A) of
     {ok, R} ->
       R;
-    {error, E} ->
+    {error, E} = Err ->
       io:format("~p~n", [E]),
-      {error, E}
+      Err
   end.
 
 
@@ -72,8 +78,53 @@ returning(Ppid, Q, A) ->
   case epgsql:equery(Ppid, Q, A) of
     {ok, 1, _, R} ->
       R;
-    {error, E} ->
+    {error, E} = Err ->
       io:format("~p~n", [E]),
-      {error, E}
+      Err
+  end.
+
+
+
+transaction(Fun) ->
+  case epgsql_pool:transaction(my_main_pool, Fun) of
+    ok ->
+      ok;
+    Error ->
+      io:format("transaction error: ~p~n in tr fun: ~p~n", [Error, Fun]),
+      Error
+  end.
+
+
+transaction_q(Worker, Q, A) ->
+  epgsql_pool:query(Worker, Q, A).
+
+
+select(Q, A) ->
+  case epgsql_pool:query(my_main_pool, Q, A) of
+    {ok, _, R} ->
+      R;
+    {error, E} = Err ->
+      io:format("~p~n", [E]),
+      Err
+  end.
+
+
+in_up_del(Q, A) ->
+  case epgsql_pool:query(my_main_pool, Q, A) of
+    {ok, R} ->
+      R;
+    {error, E} = Err ->
+      io:format("~p~n", [E]),
+      Err
+  end.
+
+
+returning(Q, A) ->
+  case epgsql_pool:query(my_main_pool, Q, A) of
+    {ok, 1, _, R} ->
+      R;
+    {error, E} = Err ->
+      io:format("~p~n", [E]),
+      Err
   end.
 

+ 42 - 0
apps/n2o_sample/src/pq.erl

@@ -4,11 +4,23 @@
 
 %% postgresql queries module
 
+%% without pool
 % get_all_cities(Mpid)
 % update_city_by_id(Mpid, City_Id, City_Name, City_Pop)
 % add_city(Mpid, City_Name, City_Pop)
 % add_city_return_id(Mpid, City_Name, City_Pop)
 % delete_city_by_id(Mpid, City_Id)
+
+%% with pool
+% get_all_cities()
+% update_city_by_id(City_Id, City_Name, City_Pop)
+% add_city(City_Name, City_Pop)
+% add_city_return_id(City_Name, City_Pop)
+% delete_city_by_id(City_Id)
+
+%% with pool and in transaction
+% get_all_cities_t(Worker)
+% add_city_t(Worker, City_Name, City_Pop)
 % 
 
 
@@ -31,3 +43,33 @@ add_city_return_id(Ppid, City_Name, City_Pop) ->
 delete_city_by_id(Ppid, City_Id) ->
   pgm:in_up_del(Ppid, "DELETE FROM test WHERE id = $1", [City_Id]).
 
+
+
+get_all_cities() ->
+  pgm:select("SELECT id, name, population FROM test ORDER BY id", []).
+
+
+update_city_by_id(City_Id, City_Name, City_Pop) ->
+  pgm:in_up_del("UPDATE test SET name = $1, population = $2 WHERE id = $3", [City_Name, City_Pop, City_Id]).
+
+
+add_city(City_Name, City_Pop) ->
+  pgm:in_up_del("INSERT INTO test (name, population) VALUES ($1, $2)", [City_Name, City_Pop]).
+
+
+add_city_return_id(City_Name, City_Pop) ->
+  pgm:returning("INSERT INTO test (name, population) VALUES ($1, $2) RETURNING id", [City_Name, City_Pop]).
+
+
+delete_city_by_id(City_Id) ->
+  pgm:in_up_del("DELETE FROM test WHERE id = $1", [City_Id]).
+
+
+
+get_all_cities_t(Worker) ->
+  pgm:transaction_q(Worker, "SELECT id, name, population FROM test ORDER BY id", []).
+
+
+add_city_t(Worker, City_Name, City_Pop) ->
+  pgm:transaction_q(Worker, "INSERT INTO test (name, population) VALUES ($1, $2)", [City_Name, City_Pop]).
+

+ 1 - 0
apps/n2o_sample/src/routes.erl

@@ -24,6 +24,7 @@ route_prefix(P) -> route(P).
 
 route(<<>>)              -> login;
 route(<<"testcities/">>) -> testcities;
+route(<<"testcities2/">>) -> testcities2;
 route(<<"index",_/binary>>) -> index;
 route(<<"static/spa/index",_/binary>>) -> index;
 route(<<"static/spa/login",_/binary>>) -> login;

+ 7 - 6
apps/n2o_sample/src/testcities.erl

@@ -3,6 +3,7 @@
 -include_lib("nitro/include/nitro.hrl").
 -include_lib("n4u/include/wf.hrl").
 
+%% example work with postgresql (without pool)
 
 -export([
   main/0,
@@ -43,9 +44,9 @@ event({client, {sitiesshow}}) ->
   InnerHtml = hg:generate_cities_list(Data),
 
   wf:wire(wf:f("var parent = qi('cities');"
-          "parent.innerHTML='~s';"
-          "window.getting_data=false;"
-          "qi('citiesshow').disabled=false;", [unicode:characters_to_binary(InnerHtml, utf8)]));
+    "parent.innerHTML='~s';"
+    "window.getting_data=false;"
+    "qi('citiesshow').disabled=false;", [unicode:characters_to_binary(InnerHtml, utf8)]));
 
 
 event({client, {cityadd, Name, Pop}}) ->
@@ -55,9 +56,9 @@ event({client, {cityadd, Name, Pop}}) ->
   epgsql:close(Mpid),
 
   wf:wire(wf:f("qi('cityname').value='';"
-          "qi('citypop').value='1';"
-          "window.sending_data=false;"
-          "qi('cityadd').disabled=false;", [])),
+    "qi('citypop').value='1';"
+    "window.sending_data=false;"
+    "qi('cityadd').disabled=false;", [])),
   ?MODULE:event({client, {sitiesshow}});
 
 

+ 80 - 0
apps/n2o_sample/src/testcities2.erl

@@ -0,0 +1,80 @@
+-module(testcities2).
+
+-include_lib("nitro/include/nitro.hrl").
+-include_lib("n4u/include/wf.hrl").
+
+%% example work with postgresql (with pool)
+
+-export([
+  main/0,
+  event/1
+]).
+
+
+main() ->
+  Tr = hm:get_tr_mod(), % get i18n module by lang
+  
+  Body = #dtl{file = "testcities", app = n2o_sample, bindings=[
+    {cities, Tr:tr(testcities, cities) },
+    {cities_show, Tr:tr(testcities, cities_show) },
+    {cities_add, Tr:tr(testcities, cities_add) },
+    {city_name, Tr:tr(testcities, city_name) },
+    {city_pop, Tr:tr(testcities, city_pop) },
+    {city_add, Tr:tr(testcities, city_add) }
+  ]},
+
+  #dtl{file = "layout", app = n2o_sample, bindings=[
+    {page_title, Tr:tr(testcities, page_title) },
+    {page_css, <<"<link rel=\"stylesheet\" href=\"/css/test.css\">">>},
+    {page_body, wf:render(Body)},
+    {page_js, <<"<script src=\"/js/testcities.js\" defer></script>">>}
+  ]}.
+
+
+event(init) ->
+  ?MODULE:event({client, {sitiesshow}});
+  %[];
+
+
+event({client, {sitiesshow}}) ->
+  Data = pq:get_all_cities(),
+  InnerHtml = hg:generate_cities_list(Data),
+
+  wf:wire(wf:f("var parent = qi('cities');"
+    "parent.innerHTML='~s';"
+    "window.getting_data=false;"
+    "qi('citiesshow').disabled=false;", [unicode:characters_to_binary(InnerHtml, utf8)]));
+
+
+%% add one city and show all -- example with transaction
+event({client, {cityadd, Name, Pop}}) ->
+  pgm:transaction(fun(Worker) ->
+    %%epgsql:squery(Mpid, "BEGIN"), %% when transaction without pool
+    
+    {ok, R1} = pq:add_city_t(Worker, Name, Pop),
+    hm:assert_int(R1),
+    
+    {ok, _Columns, Data} = pq:get_all_cities_t(Worker),
+    %%hm:assert_int(R2)
+    
+    InnerHtml = hg:generate_cities_list(Data),
+    
+    wf:wire(wf:f("var parent = qi('cities');"
+      "parent.innerHTML='~s';"
+      "window.getting_data=false;"
+      "qi('citiesshow').disabled=false;", [unicode:characters_to_binary(InnerHtml, utf8)])),
+      ok
+    
+    %% commit pg-transaction - when transaction without pool
+    %%epgsql:squery(Mpid, "COMMIT"),
+    %% rollback pg-transaction - when transaction without pool
+    %%epgsql:squery(Mpid, "ROLLBACK"),
+    %%io:format("~p~n",[epgsql:get_cmd_status(Mpid)]),
+    %%{ok,commit} or {ok, rollback}
+  end);
+
+
+event(Event) ->
+  wf:info(?MODULE, "Event: ~p", [Event]),
+  ok.
+

+ 3 - 0
rebar.config

@@ -20,6 +20,9 @@
     {sh,      ".*", {git, "https://git.4dev.win/n4u/sh.git",           {tag, "1.9-erl19"}  }},
     
     {epgsql,  ".*", {git, "https://git.4dev.win/n4u/epgsql.git",       {tag, "3.3.0"} }},
+    {pooler,  ".*", {git, "https://git.4dev.win/n4u/pooler.git",       {tag, "erl19"} }},
+    {herd,    ".*", {git, "https://git.4dev.win/n4u/herd.git",         {tag, "erl19"} }},
+    {epgsql_pool, ".*", {git, "https://git.4dev.win/n4u/epgsql_pool.git", {tag, "erl19"} }},
     
     {cowlib,  ".*", {git, "https://git.4dev.win/n4u/cowlib.git",       {branch, "1.0.0-erl19"} }},
     {ranch,   ".*", {git, "https://git.4dev.win/n4u/ranch.git",        {tag, "1.0.0"} }},

+ 4 - 0
sys.config

@@ -25,6 +25,10 @@
         {pickler, n2o_pickle},
         {erroring, n2o_error},
         {event, pickle}]},
+ {epgsql_pool,
+        [{connection_timeout, 10000},
+        {query_timeout, 3000},
+        {transaction_timeout, 10000} ]},
  {fs,
    [{backwards_compatible, false}]},
  {active,