Commits

Anonymous committed bda74f1

adding conditional operators, a test file and documentation

Comments (0)

Files changed (4)

 	
 	emongo:find(PoolName, CollectionName) -> Result
 	emongo:find(PoolName, CollectionName, Selector) -> Result
-	emongo:find(PoolName, CollectionName, Selector, Options) -> Result
+	emongo:find(PoolName, CollectionName, Selector, Options) -> Result
+	
+#### Examples
+
+limit, offset, timeout, orderby, fields
+
+	%% find documents from 'collection' where field1 equals 1 and abort the query if it takes more than 5 seconds
+	%% limit the number of results to 100 and offset the first document 10 documents from the beginning
+	%% return documents in ascending order, sorted by the value of field1
+	%% limit the fields in the return documents to field1 (the _id field is always included in the results)
+	emongo:find(test, "collection", [{"field1", 1}], [{limit, 100}, {offset, 10}, {timeout, 5000}, {orderby, [{"field1", asc}]}, {fields, ["field1"]}]).
+	
+great than, less than, great than or equal, less than or equal
+
+	%% find documents where field1 is greater than 5 and less than 10
+	emongo:find(test, "collection", [{"field1", [{gt, 5}, {lt, 10}]}]).
+	  
+	%% find documents where field1 is greater than or equal to 5 and less than or equal to 10
+	emongo:find(test, "collection", [{"field1", [{gte, 5}, {lte, 10}]}]).
+	  
+	%% find documents where field1 is greater than 5 and less than 10
+	emongo:find(test, "collection", [{"field1", [{'>', 5}, {'<', 10}]}]).
+	  
+	%% find documents where field1 is greater than or equal to 5 and less than or equal to 10
+	emongo:find(test, "collection", [{"field1", [{'>=', 5}, {'=<', 10}]}]).
+	
+not equal
+
+	%% find documents where field1 is not equal to 5 or 10
+	emongo:find(test, "collection", [{"field1", [{ne, 5}, {ne, 10}]}]).
+	
+in
+
+	%% find documents where the value of field1 is one of the values in the list [1,2,3,4,5]
+	emongo:find(test, "collection", [{"field1", [{in, [1,2,3,4,5]}]}]).
+
+not in
+	
+	%% find documents where the value of field1 is NOT one of the values in the list [1,2,3,4,5]
+	emongo:find(test, "collection", [{"field1", [{nin, [1,2,3,4,5]}]}]).
+	
+all
+
+	%% find documents where the value of field1 is an array and contains all of the values in the list [1,2,3,4,5]
+	emongo:find(test, "collection", [{"field1", [{all, [1,2,3,4,5]}]}]).
+	
+size
+
+	%% find documents where the value of field1 is an array of size 10
+	emongo:find(test, "collection", [{"field1", [{size, 10}]}]).
+	
+exists
+
+	%% find documents where field1 exists
+	emongo:find(test, "collection", [{"field1", [{exists, true}]}]).
+	
+where
+
+	%% find documents where the value of field1 is greater than 10
+	emongo:find(test, "collection", [{where, "this.field1 > 10"}]).
 %%		 Offset = integer
 %%		 Orderby = [{Key, Direction}]
 %%		 Key = string() | binary() | atom() | integer()
-%%		 Direction = 1 (Asc) | -1 (Desc)
+%%		 Direction = asc | desc
 %%		 Fields = [Field]
 %%		 Field = string() | binary() | atom() | integer() = specifies a field to return in the result set
 %%		 response_options = return {response, header, response_flag, cursor_id, offset, limit, documents}
 %%		 Result = documents() | response()
 find(PoolId, Collection, Selector, Options) when ?IS_DOCUMENT(Selector), is_list(Options) ->
 	{Pid, Pool} = gen_server:call(?MODULE, {pid, PoolId}, infinity),
-	Query = create_query(Options, #emo_query{}, Selector, []),
+	Query = create_query(Options, Selector),
 	Packet = emongo_packet:do_query(Pool#pool.database, Collection, Pool#pool.req_id, Query),
 	Resp = emongo_conn:send_recv(Pid, Pool#pool.req_id, Packet, proplists:get_value(timeout, Options, ?TIMEOUT)),
 	case lists:member(response_options, Options) of
 hex2dec(N,<<>>) ->
 	N.
 
+create_query(Options, Selector) ->
+	Selector1 = transform_selector(Selector),
+	create_query(Options, #emo_query{}, Selector1, []).
+	
 create_query([], QueryRec, QueryDoc, []) ->
 	QueryRec#emo_query{q=QueryDoc};
 
 	create_query(Options, QueryRec1, QueryDoc, OptDoc);
 
 create_query([{orderby, Orderby}|Options], QueryRec, QueryDoc, OptDoc) ->
-	OptDoc1 = [{<<"orderby">>, Orderby}|OptDoc],
+	Orderby1 = [{Key, case Dir of desc -> -1; _ -> 1 end}|| {Key, Dir} <- Orderby],
+	OptDoc1 = [{<<"orderby">>, Orderby1}|OptDoc],
 	create_query(Options, QueryRec, QueryDoc, OptDoc1);
 	
 create_query([{fields, Fields}|Options], QueryRec, QueryDoc, OptDoc) ->
 create_query([_|Options], QueryRec, QueryDoc, OptDoc) ->
 	create_query(Options, QueryRec, QueryDoc, OptDoc).
 	
+transform_selector(Selector) ->
+	transform_selector(Selector, []).
+	
+transform_selector([], Acc) -> 
+	lists:reverse(Acc);
+	
+transform_selector([{where, Val}|Tail], Acc) when is_list(Val) ->
+	transform_selector(Tail, [{<<"$where">>, Val}|Acc]);
+	
+transform_selector([{Key, [{_,_}|_]=Vals}|Tail], Acc) ->
+	Vals1 =
+		[case Operator of
+			O when O == '>'; O == gt -> 
+				{<<"$gt">>, Val};
+			O when O == '<'; O == lt ->
+				{<<"$lt">>, Val};
+			O when O == '>='; O == gte ->
+				{<<"$gte">>, Val};
+			O when O == '=<'; O == lte ->
+				{<<"$lte">>, Val};
+			O when O == '=/='; O == '/='; O == ne ->
+				{<<"$ne">>, Val};
+			in when is_list(Val) -> 
+				{<<"$in">>, {array, Val}};
+			nin when is_list(Val) -> 
+				{<<"$nin">>, {array, Val}};
+			mod when is_list(Val), length(Val) == 2 -> 
+				{<<"$mod">>, {array, Val}};
+			all when is_list(Val) ->
+				{<<"$all">>, {array, Val}};
+			size when is_integer(Val) ->
+				{<<"$size">>, Val};
+			exists when is_boolean(Val) ->
+				{<<"$exists">>, Val};
+			_ -> 
+				{Operator, Val}
+		 end || {Operator, Val} <- Vals],
+	transform_selector(Tail, [{Key, Vals1}|Acc]);
+	
+transform_selector([Other|Tail], Acc) ->
+	transform_selector(Tail, [Other|Acc]).
+	
 dec0($a) ->	10;
 dec0($b) ->	11;
 dec0($c) ->	12;
 	
 	[emongo:insert(test1, "sushi", [{<<"rolls">>, I}, {<<"uni">>, <<"nigiri">>}]) || I <- lists:seq(1, 1000)],
 	
-	All = emongo:find_all(test1, "sushi", [], [{orderby, [{"rolls", 1}]}]),
+	All = emongo:find_all(test1, "sushi", [], [{orderby, [{"rolls", asc}]}]),
 	etap:is(length(All), 1000, "inserted documents into sushi collection"),
 	
 	(fun() ->
 	
 	%% LIMIT && ORDERBY
 	(fun() ->
-		Docs = emongo:find(test1, "sushi", [], [{limit, 1}, {orderby, [{"rolls", 1}]}, {fields, [<<"rolls">>]}]),
+		Docs = emongo:find(test1, "sushi", [], [{limit, 1}, {orderby, [{"rolls", asc}]}, {fields, [<<"rolls">>]}]),
 		etap:is(length(Docs), 1, "limit returns one document"),
 		etap:is(length(hd(Docs)), 2, "correct number of fields"),
 		etap:is(lists:nth(2, hd(Docs)), {<<"rolls">>, 1}, "returned correct document from limit query"),
 	
 	%% LIMIT && OFFSET && ORDERBY
 	(fun() ->
-		Docs = emongo:find(test1, "sushi", [], [{limit, 1}, {offset, 1}, {orderby, [{"rolls", -1}]}]),
+		Docs = emongo:find(test1, "sushi", [], [{limit, 1}, {offset, 1}, {orderby, [{"rolls", desc}]}]),
 		etap:is(length(Docs), 1, "limit returns one document"),
 		etap:is(lists:nth(2, hd(Docs)), {<<"rolls">>, 999}, "returned correct document from offset query"),
 		ok
 	end)(),
 	
 	(fun() ->
-		Docs = emongo:find(test1, "sushi", [{"rolls", 100}], [{orderby, [{"rolls", -1}]}]),
+		Docs = emongo:find(test1, "sushi", [{"rolls", 100}], [{orderby, [{"rolls", desc}]}]),
 		etap:is(proplists:get_value(<<"rolls">>, hd(Docs)), 100, "query returned correct value"),
 		ok
 	end)(),

t/004-cond-exprs.t

+#!/usr/local/bin/escript
+%% -*- erlang -*-
+%%! -pa ebin -sasl errlog_type error -boot start_sasl -noshell -config priv/example
+
+main(_) ->
+	etap:plan(unknown),
+    error_logger:tty(false),
+    etap_application:start_ok(emongo, "application 'emongo' started ok"),
+
+	emongo:delete(test1, "sushi"),
+	etap:is(emongo:find(test1, "sushi"), [], "sushi collection is empty"),
+	
+	[emongo:insert(test1, "sushi", [{<<"rolls">>, I}]) || I <- lists:seq(1, 50)],
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{gt, 45}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 5, "correct number of results from gt query"),
+		etap:is([I || [_, {_, I}] <- Docs], [46,47,48,49,50], "correct results from gt query"),
+		ok
+	end)(),
+
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{lt, 5}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 4, "correct number of results from lt query"),
+		etap:is([I || [_, {_, I}] <- Docs], [1, 2, 3, 4], "correct results from lt query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{gte, 45}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 6, "correct number of results from gte query"),
+		etap:is([I || [_, {_, I}] <- Docs], [45,46,47,48,49,50], "correct results from gte query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{lte, 5}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 5, "correct number of results from lte query"),
+		etap:is([I || [_, {_, I}] <- Docs], [1, 2, 3, 4, 5], "correct results from lte query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{ne, 1}, {ne, 50}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 48, "correct number of results from ne query"),
+		etap:is([I || [_, {_, I}] <- Docs], lists:seq(2, 49), "correct results from ne query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{in, [1,2,3,4,5]}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 5, "correct number of results from in query"),
+		etap:is([I || [_, {_, I}] <- Docs], [1,2,3,4,5], "correct results from in query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"rolls">>, [{nin, [1,2,3,4,5]}]}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 45, "correct number of results from nin query"),
+		etap:is([I || [_, {_, I}] <- Docs], lists:seq(6,50), "correct results from nin query"),
+		ok
+	end)(),
+	
+	[emongo:insert(test1, "sushi", [{<<"maki">>, {array, [I,I+1,I+2]}}]) || I <- lists:seq(1, 10)],
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"maki">>, [{all, [2,3]}]}], [orderby, [{"maki", asc}]]),
+		etap:is(length(Docs), 2, "correct number of results from all query"),
+		etap:is([I || [_, {_, I}] <- Docs], [{array, [1,2,3]}, {array, [2,3,4]}], "correct results from all query"),
+		ok
+	end)(),
+	
+	emongo:insert(test1, "sushi", [{<<"maki">>, {array, [1,2,3,4,5]}}]),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"maki">>, [{size, 5}]}], [orderby, [{"maki", asc}]]),
+		etap:is(length(Docs), 1, "correct number of results from size query"),
+		etap:is([I || [_, {_, I}] <- Docs], [{array, [1,2,3,4,5]}], "correct results from size query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"maki">>, [{exists, true}]}], [orderby, [{"maki", asc}]]),
+		etap:is(length(Docs), 11, "correct number of results from exists query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{<<"maki">>, [{exists, false}]}], [orderby, [{"maki", asc}]]),
+		etap:is(length(Docs), 50, "correct number of results from exists query"),
+		ok
+	end)(),
+	
+	(fun() ->
+		Docs = emongo:find(test1, "sushi", [{where, "this.rolls > 45"}], [orderby, [{"rolls", asc}]]),
+		etap:is(length(Docs), 5, "correct number of results from where query"),
+		etap:is([I || [_, {_, I}] <- Docs], [46,47,48,49,50], "correct results from where query"),
+		ok
+	end)(),
+	
+   	etap:end_tests().