Просмотр исходного кода

Merge pull request #93 from yjh0502/devel

epgsqla: add prepared_query/3
David N. Welton 9 лет назад
Родитель
Сommit
49fdb4e257
7 измененных файлов с 69 добавлено и 14 удалено
  1. 21 2
      README.md
  2. 4 1
      src/epgsql.erl
  3. 8 3
      src/epgsqla.erl
  4. 8 3
      src/epgsqli.erl
  5. 11 0
      test/epgsql_cast.erl
  6. 12 0
      test/epgsql_incremental.erl
  7. 5 5
      test/epgsql_tests.erl

+ 21 - 2
README.md

@@ -261,7 +261,9 @@ Data Representation section below.
 Asynchronous API `epgsqla:equery/3` requires you to parse statement beforehand
 
 ```erlang
-Ref = epgsqla:equery(C, Statement, [Parameters]),
+#statement{types = Types} = Statement,
+TypedParameters = lists:zip(Types, Parameters),
+Ref = epgsqla:equery(C, Statement, [TypedParameters]),
 receive
   {C, Ref, Res} -> Res
 end.
@@ -270,7 +272,7 @@ end.
 - `Statement` - parsed statement (see parse below)
 - `Res` has same format as return value of `epgsql:equery/3`.
 
-`epgsqli:equery(C, Statement, [Parameters])` sends same set of messages as
+`epgsqli:equery(C, Statement, [TypedParameters])` sends same set of messages as
 squery including final `{C, Ref, done}`.
 
 ## Prepared Query
@@ -291,6 +293,23 @@ epgsql:prepared_query(C, "inc", [4]).
 epgsql:prepared_query(C, "inc", [1]).
 ```
 
+Asynchronous API `epgsqla:prepared_query/3` requires you to parse statement beforehand
+
+```erlang
+#statement{types = Types} = Statement,
+TypedParameters = lists:zip(Types, Parameters),
+Ref = epgsqla:prepared_query(C, Statement, [TypedParameters]),
+receive
+  {C, Ref, Res} -> Res
+end.
+```
+
+- `Statement` - parsed statement (see parse below)
+- `Res` has same format as return value of `epgsql:prepared_query/3`.
+
+`epgsqli:prepared_query(C, Statement, [TypedParameters])` sends same set of messages as
+squery including final `{C, Ref, done}`.
+
 ## Parse/Bind/Execute
 
 ```erlang

+ 4 - 1
src/epgsql.erl

@@ -24,7 +24,7 @@
 
 -export_type([connection/0, connect_option/0,
               connect_error/0, query_error/0,
-              sql_query/0, bind_param/0,
+              sql_query/0, bind_param/0, typed_param/0,
               squery_row/0, equery_row/0, reply/1]).
 
 -include("epgsql.hrl").
@@ -56,6 +56,9 @@
         | {list({binary(), binary() | null})}   % hstore
         | [bind_param()].                       %array (maybe nested)
 
+-type typed_param() ::
+    {epgsql_type(), bind_param()}.
+
 -type squery_row() :: {binary()}.
 -type equery_row() :: {bind_param()}.
 -type ok_reply(RowType) ::

+ 8 - 3
src/epgsqla.erl

@@ -8,6 +8,7 @@
          get_parameter/2,
          squery/2,
          equery/2, equery/3,
+         prepared_query/3,
          parse/2, parse/3, parse/4,
          describe/2, describe/3,
          bind/3, bind/4,
@@ -55,9 +56,13 @@ squery(C, Sql) ->
 equery(C, Sql) ->
     equery(C, Sql, []).
 
--spec equery(epgsql:connection(), #statement{}, [epgsql:bind_param()]) -> reference().
-equery(C, Statement, Parameters) ->
-    cast(C, {equery, Statement, Parameters}).
+-spec equery(epgsql:connection(), #statement{}, [epgsql:typed_param()]) -> reference().
+equery(C, Statement, TypedParameters) ->
+    cast(C, {equery, Statement, TypedParameters}).
+
+-spec prepared_query(epgsql:connection(), #statement{}, [epgsql:typed_param()]) -> reference().
+prepared_query(C, Statement, TypedParameters) ->
+    cast(C, {prepared_query, Statement, TypedParameters}).
 
 parse(C, Sql) ->
     parse(C, "", Sql, []).

+ 8 - 3
src/epgsqli.erl

@@ -8,6 +8,7 @@
          get_parameter/2,
          squery/2,
          equery/2, equery/3,
+         prepared_query/3,
          parse/2, parse/3, parse/4,
          describe/2, describe/3,
          bind/3, bind/4,
@@ -54,9 +55,13 @@ squery(C, Sql) ->
 equery(C, Sql) ->
     equery(C, Sql, []).
 
--spec equery(epgsql:connection(), #statement{}, [epgsql:bind_param()]) -> reference().
-equery(C, Statement, Parameters) ->
-    incremental(C, {equery, Statement, Parameters}).
+-spec equery(epgsql:connection(), #statement{}, [epgsql:typed_param()]) -> reference().
+equery(C, Statement, TypedParameters) ->
+    incremental(C, {equery, Statement, TypedParameters}).
+
+-spec prepared_query(epgsql:connection(), #statement{}, [epgsql:typed_param()]) -> reference().
+prepared_query(C, Statement, TypedParameters) ->
+    incremental(C, {prepared_query, Statement, TypedParameters}).
 
 parse(C, Sql) ->
     parse(C, "", Sql, []).

+ 11 - 0
test/epgsql_cast.erl

@@ -7,6 +7,7 @@
 
 -export([connect/2, connect/3, connect/4, close/1]).
 -export([get_parameter/2, squery/2, equery/2, equery/3]).
+-export([prepared_query/3]).
 -export([parse/2, parse/3, parse/4, describe/2, describe/3]).
 -export([bind/3, bind/4, execute/2, execute/3, execute/4, execute_batch/2]).
 -export([close/2, close/3, sync/1]).
@@ -60,6 +61,16 @@ equery(C, Sql, Parameters) ->
             Error
     end.
 
+prepared_query(C, Name, Parameters) ->
+    case describe(C, statement, Name) of
+        {ok, #statement{types = Types} = S} ->
+            Typed_Parameters = lists:zip(Types, Parameters),
+            Ref = epgsqla:prepared_query(C, S, Typed_Parameters),
+            receive_result(C, Ref);
+        Error ->
+            Error
+    end.
+
 %% parse
 
 parse(C, Sql) ->

+ 12 - 0
test/epgsql_incremental.erl

@@ -7,6 +7,7 @@
 
 -export([connect/2, connect/3, connect/4, close/1]).
 -export([get_parameter/2, squery/2, equery/2, equery/3]).
+-export([prepared_query/3]).
 -export([parse/2, parse/3, parse/4, describe/2, describe/3]).
 -export([bind/3, bind/4, execute/2, execute/3, execute/4, execute_batch/2]).
 -export([close/2, close/3, sync/1]).
@@ -60,6 +61,17 @@ equery(C, Sql, Parameters) ->
             Error
     end.
 
+prepared_query(C, Name, Parameters) ->
+    case describe(C, statement, Name) of
+        {ok, #statement{types = Types} = S} ->
+            Typed_Parameters = lists:zip(Types, Parameters),
+            Ref = epgsqli:prepared_query(C, S, Typed_Parameters),
+            receive_result(C, Ref, undefined);
+        Error ->
+            Error
+    end.
+
+
 %% parse
 
 parse(C, Sql) ->

+ 5 - 5
test/epgsql_tests.erl

@@ -110,11 +110,11 @@ prepared_query_test(Module) ->
   with_connection(
     Module,
     fun(C) ->
-      {ok, _} = epgsql:parse(C, "inc", "select $1+1", []),
-      {ok, Cols, [{5}]} = epgsql:prepared_query(C, "inc", [4]),
-      {ok, Cols, [{2}]} = epgsql:prepared_query(C, "inc", [1]),
-      {ok, Cols, [{23}]} = epgsql:prepared_query(C, "inc", [22]),
-      {error, _} = epgsql:prepared_query(C, "non_existent_query", [4])
+      {ok, _} = Module:parse(C, "inc", "select $1+1", []),
+      {ok, Cols, [{5}]} = Module:prepared_query(C, "inc", [4]),
+      {ok, Cols, [{2}]} = Module:prepared_query(C, "inc", [1]),
+      {ok, Cols, [{23}]} = Module:prepared_query(C, "inc", [22]),
+      {error, _} = Module:prepared_query(C, "non_existent_query", [4])
     end).