Skip to content

Commit

Permalink
Integrate the pool interface into main API.
Browse files Browse the repository at this point in the history
This extends the main `sqerl` API by adding `_with` versions
of public entry points.  These functions each take an initial parameter
of context, which can be created with `sqerl:make_context(PoolName)`
where PoolName must be configured as a valid alternate pool.

The context form of this (instead of an atom for pool) keeps future
options to extend the API to include more features beyond alternate
pools

Signed-off-by: Marc A. Paradise <marc.paradise@gmail.com>
  • Loading branch information
marcparadise committed Nov 21, 2016
1 parent f4abff4 commit 12b7425
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 248 deletions.
6 changes: 3 additions & 3 deletions common_test/sqerl_integration_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ select_simple(Config) ->
?assertEqual(ExpectedRows, Rows).

select_simple_multipool_(_Config) ->
[ ?_assertMatch(ok, 0), sqerl_mp:execute(other, <<"SELECT COUNT(*) FROM only_in_itest_sqerl2_db">>),
?_assertMatch(ok, 0), sqerl_mp:execute(sqerl, <<"SELECT COUNT(*) FROM only_in_itest_sqerl2_db">>)].
[ ?_assertMatch(ok, 0), sqerl:execute_with(sqerl:make_context(other), <<"SELECT COUNT(*) FROM only_in_itest_sqerl2_db">>),
?_assertMatch(ok, 0), sqerl:execute_with(sqerl:make_context(sqerl), <<"SELECT COUNT(*) FROM only_in_itest_sqerl1_db">>)].

adhoc_select(Config) ->
insert_data(Config),
Expand Down Expand Up @@ -369,7 +369,7 @@ adhoc_select(Config) ->
end(),
%% adhoc_select_limit
fun() ->
{ok, Rows} = sqerl_mp:adhoc_select(sqerl, [<<"id">>], <<"users">>, all, [{order_by, [<<"id">>]}, {limit, 2}]),
{ok, Rows} = sqerl:adhoc_select_with(sqerl:make_context(sqerl), [<<"id">>], <<"users">>, all, [{order_by, [<<"id">>]}, {limit, 2}]),
ExpectedRows = [
[{<<"id">>, 1}],
[{<<"id">>, 2}]
Expand Down
3 changes: 3 additions & 0 deletions include/sqerl.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
{ok, integer(), sqerl_rows()} |
{error, atom() | tuple()}.

-record(sqerl_ctx, { pool :: atom() }).
-type sqerl_ctx() :: #sqerl_ctx{}.

-ifdef(namespaced_types).
-type sqerl_dict() :: dict:dict().
-else.
Expand Down
137 changes: 119 additions & 18 deletions src/sqerl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@

-module(sqerl).

-export([select/2,
%% Original API exports. These will execute
%% all queries against the default `sqerl` pool.
-export([
select/2,
select/3,
select/4,
statement/2,
Expand All @@ -36,11 +39,35 @@
adhoc_insert/2,
adhoc_insert/3,
adhoc_insert/4,
adhoc_delete/2]).
adhoc_delete/2
]).

%% Context-based API functions which currently
%% allows multipool support. These functions are identicial
%% to their counterparts above, but each accepts a context as the
%% first argument.
-export([make_context/1,
select_with/3,
select_with/4,
select_with/5,
statement_with/3,
statement_with/4,
statement_with/5,
execute_with/3,
execute_with/2,
adhoc_select_with/4,
adhoc_select_with/5,
adhoc_insert_with/3,
adhoc_insert_with/4,
adhoc_insert_with/5,
adhoc_delete_with/3]).

-include("sqerl.hrl").
-define(DEFAULT_POOL, sqerl).

make_context(Pool) ->
#sqerl_ctx{pool = Pool}.

select(StmtName, StmtArgs) ->
select(StmtName, StmtArgs, identity, []).

Expand All @@ -50,9 +77,22 @@ select(StmtName, StmtArgs, XformName) ->
select(StmtName, StmtArgs, XformName, []).

select(StmtName, StmtArgs, XformName, XformArgs) ->
Results = sqerl_core:execute_statement(?DEFAULT_POOL, StmtName, StmtArgs, XformName, XformArgs),
sqerl_core:parse_select_results(Results).
select_with(make_context(?DEFAULT_POOL), StmtName, StmtArgs, XformName, XformArgs).

%% @doc as select/2 with context added
select_with(#sqerl_ctx{} = Context, StmtName, StmtArgs) ->
select_with(Context, StmtName, StmtArgs, identity, []).

%% @doc as select/3 with context added
select_with(#sqerl_ctx{} = Context, StmtName, StmtArgs, {XformName, XformArgs}) ->
select_with(Context, StmtName, StmtArgs, XformName, XformArgs);
select_with(#sqerl_ctx{} = Context, StmtName, StmtArgs, XformName) ->
select_with(Context, StmtName, StmtArgs, XformName, []).

%% @doc as select/4 with context added
select_with(#sqerl_ctx{} = Context, StmtName, StmtArgs, XformName, XformArgs) ->
Results = sqerl_core:execute_statement(Context, StmtName, StmtArgs, XformName, XformArgs),
sqerl_core:parse_select_results(Results).

statement(StmtName, StmtArgs) ->
statement(StmtName, StmtArgs, identity, []).
Expand All @@ -61,15 +101,25 @@ statement(StmtName, StmtArgs, XformName) ->
statement(StmtName, StmtArgs, XformName, []).

statement(StmtName, StmtArgs, XformName, XformArgs) ->
Results = sqerl_core:execute_statement(?DEFAULT_POOL, StmtName, StmtArgs, XformName, XformArgs),
statement_with(make_context(?DEFAULT_POOL), StmtName, StmtArgs, XformName, XformArgs).

statement_with(#sqerl_ctx{} = Context, StmtName, StmtArgs) ->
statement_with(Context, StmtName, StmtArgs, identity, []).

statement_with(#sqerl_ctx{} = Context, StmtName, StmtArgs, XformName) ->
statement_with(Context, StmtName, StmtArgs, XformName, []).

statement_with(#sqerl_ctx{} = Context, StmtName, StmtArgs, XformName, XformArgs) ->
Results = sqerl_core:execute_statement(Context, StmtName, StmtArgs, XformName, XformArgs),
sqerl_core:parse_statement_results(Results).



%% @doc Execute query or statement with no parameters.
%% See execute/2 for return info.
-spec execute(sqerl_query()) -> sqerl_results().
execute(QueryOrStatement) ->
sqerl_core:execute(?DEFAULT_POOL, QueryOrStatement, []).
execute(QueryOrStatement, []).

%% @doc Execute query or statement with parameters.
%% ```
Expand All @@ -89,7 +139,19 @@ execute(QueryOrStatement) ->
%%
-spec execute(sqerl_query(), [] | [term()]) -> sqerl_results().
execute(QueryOrStatement, Parameters) ->
sqerl_core:execute(?DEFAULT_POOL, QueryOrStatement, Parameters).
execute_with(make_context(?DEFAULT_POOL), QueryOrStatement, Parameters).


%% @doc as execute/1, adds a sqerl_ctx() as its first argument.
%% See execute/1 for return info.
-spec execute_with(sqerl_ctx(), sqerl_query()) -> sqerl_results().
execute_with(#sqerl_ctx{} = Context, QueryOrStatement) ->
sqerl_core:execute(Context, QueryOrStatement, []).

%% @doc as execute/2, adds a sqerl_ctx() as its first argument
-spec execute_with(sqerl_ctx(), sqerl_query(), [] | [term()]) -> sqerl_results().
execute_with(#sqerl_ctx{} = Context, QueryOrStatement, Parameters) ->
sqerl_core:execute(Context, QueryOrStatement, Parameters).


%% @doc Execute an adhoc select query.
Expand Down Expand Up @@ -135,18 +197,32 @@ adhoc_select(Columns, Table, Where) ->
%% that uses several clauses.
-spec adhoc_select([binary() | string()], binary() | string(), atom() | tuple(), [] | [atom() | tuple()]) -> sqerl_results().
adhoc_select(Columns, Table, Where, Clauses) ->
adhoc_select_with(make_context(?DEFAULT_POOL), Columns, Table, Where, Clauses).


%% @doc as adhoc_select/3,
%% @see adhoc_select/3
-spec adhoc_select_with(sqerl_ctx(), [binary() | string()], binary() | string(), atom() | tuple()) -> sqerl_results().
adhoc_select_with(#sqerl_ctx{} = Context, Columns, Table, Where) ->
adhoc_select_with(Context, Columns, Table, Where, []).

%% @doc as adhoc_select/4, adds a #sqerl_ctx as the first argument.
%% @see adhoc_select/4
-spec adhoc_select_with(sqerl_ctx(), [binary() | string()], binary() | string(), atom() | tuple(), [] | [atom() | tuple()]) -> sqerl_results().
adhoc_select_with(#sqerl_ctx{} = Context, Columns, Table, Where, Clauses) ->
{SQL, Values} = sqerl_adhoc:select(Columns,
Table,
[{where, Where}|Clauses],
sqerl_client:sql_parameter_style()),
sqerl_core:execute(?DEFAULT_POOL, SQL, Values).
sqerl_core:execute(Context, SQL, Values).



%% @doc Utility for generating specific message tuples from database-specific error
%% messages. The 1-argument form determines which database is being used by querying
%% Sqerl's configuration at runtime, while the 2-argument form takes the database type as a
%% parameter directly.
%% @doc Insert Rows into Table with default batch size.
%% @doc Inser Rows into Table with default batch size.
%% @see adhoc_insert/3.
adhoc_insert(Table, Rows) ->
adhoc_insert(Table, Rows, ?SQERL_DEFAULT_BATCH_SIZE).
Expand Down Expand Up @@ -189,19 +265,35 @@ adhoc_insert(Table, Rows, BatchSize) ->
%% {ok, 2}
%% '''
%%
adhoc_insert(_Table, _Columns, [], _BatchSize) ->
%% empty list of rows means nothing to do
adhoc_insert(Table, Columns, RowsValues, BatchSize) ->
adhoc_insert_with(make_context(?DEFAULT_POOL), Table, Columns, RowsValues, BatchSize).

%% @doc As adhoc_insert/2, adds a #sqerl_ctx as the first argument.
%% @see adhoc_insert/2.
adhoc_insert_with(#sqerl_ctx{} = Context, Table, Rows) ->
adhoc_insert_with(Context, Table, Rows, ?SQERL_DEFAULT_BATCH_SIZE).

%% @doc As adhoc_insert/3,adds a #sqerl_ctx as the first argument.
%% @see adhoc_insert/3.
adhoc_insert_with(#sqerl_ctx{} = Context, Table, Rows, BatchSize) ->
%% reformat Rows to desired format
{Columns, RowsValues} = sqerl_core:extract_insert_data(Rows),
NumRows = length(RowsValues),
bulk_insert_with(Context, Table, Columns, RowsValues, NumRows, BatchSize).

%% @doc as adhoc_insert/4, adds a #sqerl_ctx as the first argument.
%% @see adhoc_insert/4
adhoc_insert_with(_Context, _Table, _Columns, [], _BatchSize) ->
{ok, 0};
adhoc_insert(Table, Columns, RowsValues, BatchSize) when BatchSize > 0 ->
adhoc_insert_with(#sqerl_ctx{} = Context, Table, Columns, RowsValues, BatchSize) when BatchSize > 0 ->
NumRows = length(RowsValues),
%% Avoid the case where NumRows < BatchSize
EffectiveBatchSize = erlang:min(NumRows, BatchSize),
bulk_insert(Table, Columns, RowsValues, NumRows, EffectiveBatchSize).

%% @doc Bulk insert rows. Returns {ok, InsertedCount}.
bulk_insert(Table, Columns, RowsValues, NumRows, BatchSize) when NumRows >= BatchSize ->
sqerl_core:bulk_insert(?DEFAULT_POOL, Table, Columns, RowsValues, NumRows, BatchSize) .
bulk_insert_with(Context, Table, Columns, RowsValues, NumRows, EffectiveBatchSize).

%% @doc Bulk insert rows using the provided context. Returns {ok, InsertedCount}.
bulk_insert_with(#sqerl_ctx{} = Context, Table, Columns, RowsValues, NumRows, BatchSize) when NumRows >= BatchSize ->
sqerl_core:bulk_insert(Context, Table, Columns, RowsValues, NumRows, BatchSize) .



Expand All @@ -213,5 +305,14 @@ bulk_insert(Table, Columns, RowsValues, NumRows, BatchSize) when NumRows >= Batc
-spec adhoc_delete(binary(), term()) -> {ok, integer()} | {error, any()}.
adhoc_delete(Table, Where) ->
{SQL, Values} = sqerl_adhoc:delete(Table, Where, sqerl_client:sql_parameter_style()),
sqerl_core:execute(?DEFAULT_POOL, SQL, Values).
sqerl_core:execute(make_context(?DEFAULT_POOL), SQL, Values).


%% @doc Adhoc delete.
%% Uses the same Where specifications as adhoc_select/3.
%% Returns {ok, Count} or {error, ErrorInfo}.
%%
-spec adhoc_delete_with(sqerl_ctx(), binary(), term()) -> {ok, integer()} | {error, any()}.
adhoc_delete_with(#sqerl_ctx{} = Context, Table, Where) ->
{SQL, Values} = sqerl_adhoc:delete(Table, Where, sqerl_client:sql_parameter_style()),
sqerl_core:execute(Context, SQL, Values).
36 changes: 18 additions & 18 deletions src/sqerl_core.erl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
%% -*- erlang-indent-level: 4;indent-tabs-mode: nil; fill-column: 92 -*-
%% ex: ts=4 sw=4 et
%% @author Mark Paradise <marc.paradise@chef.io>
%% @author Marc Paradise <marc.paradise@chef.io>
%% @author Seth Falcon <seth@chef.io>
%% @author Marc Anderson <mark@chef.io>
%% Copyright 2011-2015 Chef Software, Inc.
%% @author Mark Anderson <mark@chef.io>
%% Copyright 2011-2016 Chef Software, Inc.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
Expand Down Expand Up @@ -39,19 +39,19 @@
parse_select_results/1,
extract_insert_data/1]).

checkout(Pool) ->
checkout(#sqerl_ctx{pool = Pool}) ->
pooler:take_member(Pool, envy:get(sqerl, pooler_timeout, 0, integer)).

checkin(Pool, Connection) ->
checkin(#sqerl_ctx{pool = Pool}, Connection) ->
pooler:return_member(Pool, Connection).

with_db(Pool, Call) ->
with_db(Pool, Call, ?MAX_RETRIES).
with_db(Context, Call) ->
with_db(Context, Call, ?MAX_RETRIES).

with_db(_Pool, _Call, 0) ->
with_db(_Context, _Call, 0) ->
{error, no_connections};
with_db(Pool, Call, Retries) ->
case checkout(Pool) of
with_db(#sqerl_ctx{} = Context, Call, Retries) ->
case checkout(Context) of
error_no_members ->
{error, no_connections};
Cn when is_pid(Cn) ->
Expand All @@ -66,13 +66,13 @@ with_db(Pool, Call, Retries) ->
sqerl_client:close(Cn),
with_db(Call, Retries - 1);
Result ->
checkin(Pool, Cn),
checkin(Context, Cn),
Result
end
end.

execute_statement(Pool, StmtName, StmtArgs, XformName, XformArgs) ->
case execute(Pool, StmtName, StmtArgs) of
execute_statement(Context, StmtName, StmtArgs, XformName, XformArgs) ->
case execute(Context, StmtName, StmtArgs) of
{ok, Results} ->
Xformer = erlang:apply(sqerl_transformers, XformName, XformArgs),
Xformer(Results);
Expand Down Expand Up @@ -101,14 +101,14 @@ execute_statement(Pool, StmtName, StmtArgs, XformName, XformArgs) ->
%% parameters.
%% '''
%%
-spec execute(atom(), sqerl_query(), [] | [term()]) -> sqerl_results().
execute(Pool, QueryOrStatement, Parameters) ->
-spec execute(sqerl_ctx(), sqerl_query(), [] | [term()]) -> sqerl_results().
execute(Context, QueryOrStatement, Parameters) ->
F = fun(Cn) -> sqerl_client:execute(Cn, QueryOrStatement, Parameters) end,
with_db(Pool, F).
with_db(Context, F).

bulk_insert(Pool, Table, Columns, RowsValues, NumRows, BatchSize) when NumRows >= BatchSize ->
bulk_insert(Context, Table, Columns, RowsValues, NumRows, BatchSize) when NumRows >= BatchSize ->
Inserter = make_batch_inserter(Table, Columns, RowsValues, NumRows, BatchSize),
with_db(Pool, Inserter).
with_db(Context, Inserter).

%% @doc Returns a function to call via sqerl_core:with_db/1.
%%
Expand Down

0 comments on commit 12b7425

Please sign in to comment.