Skip to content

Commit

Permalink
Merge pull request #95 from inaka/jfacorro.21.order.asc.desc
Browse files Browse the repository at this point in the history
[#21] Support for sorting asc/desc
  • Loading branch information
Brujo Benavides committed Nov 4, 2014
2 parents 25248af + 0fb5b1e commit 3c11470
Show file tree
Hide file tree
Showing 11 changed files with 351 additions and 155 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PROJECT = sumo_db

DEPS = lager emysql emongo tirerl worker_pool

dep_lager = git https://github.com/basho/lager.git 2.0.3
dep_lager = git https://github.com/basho/lager.git 2.1.0
dep_emysql = git https://github.com/Eonblast/Emysql.git v0.4.1
dep_emongo = git https://github.com/inaka/emongo.git v0.2.1
dep_tirerl = git https://github.com/inaka/tirerl 0.1.0
Expand All @@ -18,7 +18,7 @@ ERLC_OPTS += +warn_export_vars +warn_exported_vars +warn_missing_spec +warn_unty
# Commont Test Config

TEST_ERLC_OPTS += +'{parse_transform, lager_transform}'
CT_SUITES = sumo_config conditional_logic
CT_SUITES = sumo_find sumo_config conditional_logic
CT_OPTS = -s emysql -s sumo_db -erl_args -config test/test.config

test-shell: app
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ And you can check all of our open-source projects at [inaka.github.io](http://in
* Some native domain events are supported, that are dispatched through a `gen_event:notify/2` automatically when an entity is created, updated, deleted. Also when a schema is created and when all entities of a given type are deleted. Events are described in [this article](http://marcelog.github.com/articles/erlang_epers_persist_entities_domain_events.html).
* Full conditional logic support when using `find_by/2` and `delete_by/2` function. You can find more information about
the syntax of this conditional logic operators [here](./wiki/Conditional-Logic-Syntax).
* Support for sorting (`asc` or `desc`) based on multiple fields unsing `find_by/5` and `find_all/4` functions.
For example this `[{age, desc}, {name, asc}]]` will sort descendently by `age` and ascendently by `name`.

## Example
See: [**examples/blog**](https://github.com/inaka/sumo_db/tree/master/examples/blog)
Expand Down
10 changes: 8 additions & 2 deletions elvis.config
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
{elvis_style, nesting_level, [3]},
{elvis_style, god_modules, [25]},
{elvis_style, no_if_expression, []},
{elvis_style, invalid_dynamic_call, [conditional_logic_SUITE]},
{elvis_style,
invalid_dynamic_call,
[conditional_logic_SUITE,
sumo_find_SUITE,
sumo,
sumo_internal]
},
{elvis_style, used_ignored_variable, []},
{elvis_style, no_behavior_info, []},
{
Expand Down Expand Up @@ -43,4 +49,4 @@
}
]
}
].
].
98 changes: 64 additions & 34 deletions src/sumo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,23 @@

%%% API for standard CRUD functions.
-export([persist/2, delete/2, delete_by/2, delete_all/1]).
-export([find/2, find_all/1, find_all/4, find_by/2, find_by/4, find_one/2]).
-export([find/2, find_all/1, find_all/4]).
-export([find_by/2, find_by/4, find_by/5, find_one/2]).
-export([call/2, call/3]).

-type schema_name() :: atom().

-type field_attr() :: id|unique|index|not_null|auto_increment|{length, integer()}.
-type field_attr() ::
id | unique | index | not_null | auto_increment | {length, integer()}.
-type field_attrs() :: [field_attr()].

-type field_type() :: integer|string|binary|text|float|date|datetime.
-type field_name() :: atom().
-type field_value() :: term().
-type doc() :: [{field_name(), field_value()}].
-type conditions() :: [{field_name(), field_value()}].
-type sort_order() :: asc | desc.
-type sort() :: field_name() | [{field_name(), sort_order()}].

-export_type([schema_name/0, field_attr/0, field_attrs/0, field_type/0,
field_name/0, field_value/0, doc/0, conditions/0]).
Expand Down Expand Up @@ -96,23 +100,30 @@ find(DocName, Id) ->
find_one(DocName, [{IdFieldName, Id}]).

%% @doc Returns all docs from the given repo.
-spec find_all(schema_name()) -> [user_doc()].
find_all(DocName) ->
case sumo_repo:find_all(sumo_internal:get_repo(DocName), DocName) of
{ok, Docs} ->
lists:reverse(lists:map(
fun(Doc) -> sumo_internal:wakeup(DocName, Doc) end, Docs
));
{ok, Docs} -> docs_wakeup(DocName, Docs);
Error -> throw(Error)
end.

%% @doc Returns Limit docs from the given repo, starting at offset.
find_all(DocName, OrderField, Limit, Offset) ->
-spec find_all(schema_name(), sort(), non_neg_integer(), non_neg_integer()) ->
[user_doc()].
find_all(DocName, SortFields0, Limit, Offset) ->
SortFields = normalize_sort_fields(SortFields0),
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:find_all(Repo, DocName, SortFields, Limit, Offset) of
{ok, Docs} -> docs_wakeup(DocName, Docs);
Error -> throw(Error)
end.

%% @doc Returns *all* docs that match Conditions.
-spec find_by(schema_name(), conditions()) -> [user_doc()].
find_by(DocName, Conditions) ->
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:find_all(Repo, DocName, OrderField, Limit, Offset) of
{ok, Docs} ->
lists:reverse(lists:map(
fun(Doc) -> sumo_internal:wakeup(DocName, Doc) end, Docs
));
case sumo_repo:find_by(Repo, DocName, Conditions) of
{ok, Docs} -> docs_wakeup(DocName, Docs);
Error -> throw(Error)
end.

Expand All @@ -124,18 +135,21 @@ find_all(DocName, OrderField, Limit, Offset) ->
find_by(DocName, Conditions, Limit, Offset) ->
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:find_by(Repo, DocName, Conditions, Limit, Offset) of
{ok, Docs} ->
lists:reverse(lists:map(
fun(Doc) -> sumo_internal:wakeup(DocName, Doc) end, Docs
));
{ok, Docs} -> docs_wakeup(DocName, Docs);
Error -> throw(Error)
end.

%% @doc Returns *all* docs that match Conditions.
-spec find_by(schema_name(), conditions()) -> [user_doc()].
find_by(DocName, Conditions) ->
%% @doc Returns Limit number of docs that match Conditions, starting at
%% offset Offset.
-spec find_by(
schema_name(), conditions(), sort(), non_neg_integer(), non_neg_integer()
) -> [user_doc()].
find_by(DocName, Conditions, SortFields0, Limit, Offset) ->
SortFields = normalize_sort_fields(SortFields0),
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:find_by(Repo, DocName, Conditions) of
case sumo_repo:find_by(
Repo, DocName, Conditions, SortFields, Limit, Offset
) of
{ok, Docs} -> docs_wakeup(DocName, Docs);
Error -> throw(Error)
end.
Expand Down Expand Up @@ -164,9 +178,9 @@ delete_all(DocName) ->
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:delete_all(Repo, DocName) of
{ok, NumRows} ->
if
NumRows > 0 -> sumo_event:dispatch(DocName, deleted_all);
true -> ok
case NumRows > 0 of
true -> sumo_event:dispatch(DocName, deleted_all);
_ -> ok
end,
NumRows;
Error -> throw(Error)
Expand All @@ -186,9 +200,13 @@ delete(DocName, Id) ->
delete_by(DocName, Conditions) ->
Repo = sumo_internal:get_repo(DocName),
case sumo_repo:delete_by(Repo, DocName, Conditions) of
{ok, 0} -> 0;
{ok, NumRows} -> sumo_event:dispatch(DocName, deleted_total, [NumRows]), NumRows;
Error -> throw(Error)
{ok, 0} ->
0;
{ok, NumRows} ->
sumo_event:dispatch(DocName, deleted_total, [NumRows]),
NumRows;
Error ->
throw(Error)
end.

%% @doc Creates the schema for the docs of type DocName.
Expand Down Expand Up @@ -221,14 +239,6 @@ call(DocName, Function, Args) ->
{ok, {raw, Value}} -> Value
end.

docs_wakeup(DocName, Docs) ->
lists:reverse(lists:map(
fun(Doc) ->
sumo_internal:wakeup(DocName, Doc)
end,
Docs
)).

%% @doc Returns a new schema.
-spec new_schema(schema_name(), [field()]) -> schema().
new_schema(Name, Fields) ->
Expand All @@ -243,3 +253,23 @@ new_field(Name, Type, Attributes) ->
-spec new_field(field_name(), field_type()) -> field().
new_field(Name, Type) ->
new_field(Name, Type, []).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Interal functions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

docs_wakeup(DocName, Docs) ->
lists:map(
fun(Doc) ->
sumo_internal:wakeup(DocName, Doc)
end,
Docs
).

normalize_sort_fields(FieldName) when is_atom(FieldName) ->
[{FieldName, asc}];
normalize_sort_fields({Name, Order}) ->
[{Name, Order}];
normalize_sort_fields(SortFields) when is_list(SortFields) ->
lists:flatmap(fun normalize_sort_fields/1, SortFields).
37 changes: 28 additions & 9 deletions src/sumo_repo.erl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
-export([create_schema/2]).
-export([persist/2]).
-export([delete/3, delete_by/3, delete_all/2]).
-export([find_all/2, find_all/5, find_by/3, find_by/5]).
-export([find_all/2, find_all/5, find_by/3, find_by/5, find_by/6]).
-export([call/4]).

%%% Exports for gen_server
Expand Down Expand Up @@ -141,8 +141,16 @@ find_all(Name, DocName) ->
atom(), sumo:schema_name(), sumo:field_name(),
non_neg_integer(), non_neg_integer()
) -> {ok, [sumo_internal:doc()]} | {error, term()}.
find_all(Name, DocName, OrderField, Limit, Offset) ->
wpool:call(Name, {find_all, DocName, OrderField, Limit, Offset}).
find_all(Name, DocName, SortFields, Limit, Offset) ->
wpool:call(Name, {find_all, DocName, SortFields, Limit, Offset}).

%% @doc Finds documents that match the given conditions in the given
%% repository name.
-spec find_by(
atom(), sumo:schema_name(), sumo:conditions()
) -> {ok, [sumo_internal:doc()]} | {error, term()}.
find_by(Name, DocName, Conditions) ->
wpool:call(Name, {find_by, DocName, Conditions}).

%% @doc Finds documents that match the given conditions in the given
%% repository name.
Expand All @@ -156,10 +164,12 @@ find_by(Name, DocName, Conditions, Limit, Offset) ->
%% @doc Finds documents that match the given conditions in the given
%% repository name.
-spec find_by(
atom(), sumo:schema_name(), sumo:conditions()
atom(), sumo:schema_name(), sumo:conditions(),
sumo:sort(), non_neg_integer(), non_neg_integer()
) -> {ok, [sumo_internal:doc()]} | {error, term()}.
find_by(Name, DocName, Conditions) ->
wpool:call(Name, {find_by, DocName, Conditions}).
find_by(Name, DocName, Conditions, SortFields, Limit, Offset) ->
wpool:call(Name, {find_by, DocName, Conditions, SortFields, Limit, Offset}).


%% @doc Calls a custom function in the given repository name.
-spec call(
Expand Down Expand Up @@ -223,11 +233,11 @@ handle_call(
{reply, {OkOrError, Reply}, State#state{handler_state = NewState}};

handle_call(
{find_all, DocName, OrderField, Limit, Offset}, _From,
{find_all, DocName, SortFields, Limit, Offset}, _From,
#state{handler=Handler, handler_state=HState}=State
) ->
{OkOrError, Reply, NewState} = Handler:find_all(
DocName, OrderField, Limit, Offset, HState
DocName, SortFields, Limit, Offset, HState
),
{reply, {OkOrError, Reply}, State#state{handler_state = NewState}};

Expand All @@ -247,9 +257,18 @@ handle_call(
),
{reply, {OkOrError, Reply}, State#state{handler_state=NewState}};

handle_call(
{find_by, DocName, Conditions, SortFields, Limit, Offset}, _From,
#state{handler = Handler, handler_state = HState} = State
) ->
{OkOrError, Reply, NewState} = Handler:find_by(
DocName, Conditions, SortFields, Limit, Offset, HState
),
{reply, {OkOrError, Reply}, State#state{handler_state=NewState}};

handle_call(
{call, DocName, Function, Args}, _From,
#state{handler=Handler,handler_state=HState}=State
#state{handler = Handler, handler_state = HState} = State
) ->
RealArgs = lists:append(Args, [DocName, HState]),
{OkOrError, Reply, NewState} = erlang:apply(Handler, Function, RealArgs),
Expand Down
Loading

0 comments on commit 3c11470

Please sign in to comment.