Skip to content

Commit

Permalink
feat: Size operator (#35)
Browse files Browse the repository at this point in the history
* feat: Size operator

* emric

* fix: size operator

* feat: remove raise

* style: Refactor to reduce complexity

* fix: Require logger

* refactor: Update lib/exec.ex

Co-authored-by: Emric Pichonnier <emric.pichonnier@lenra.io>

* refactor: SImpler management

---------

Co-authored-by: shiipou <shiishii@nocturlab.fr>
Co-authored-by: Emric Pichonnier <emric.pichonnier@lenra.io>
Co-authored-by: Thomas DA ROCHA <thomas.darocha@lenra.io>
Co-authored-by: Emric Pichonnier <emric.pichonnier@gmail.com>
  • Loading branch information
5 people authored May 30, 2023
1 parent 55fddc1 commit 402d48b
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 43 deletions.
108 changes: 69 additions & 39 deletions lib/exec.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule QueryParser.Exec do
It takes care of executing the AST query into the data passed.
"""

require Logger

alias LenraCommon.JsonHelper

@all_operator ["$nin", "$not", "$nor"]
Expand Down Expand Up @@ -86,18 +88,22 @@ defmodule QueryParser.Exec do
)
when is_list(elem_value) do
Enum.all?(operators, fn operator ->
case Map.get(operator, "operator") do
# $all need specific action
all_operator when all_operator == "$all" ->
exec?(operator, elem, ctx)

# not operator need cond match all the list add value in @all_operator
op when op in @all_operator ->
exec_all(elem, elem_value, ctx, operator)

# other operator need cond matchh any of the list
_common ->
exec_any(elem, elem_value, ctx, operator)
if Map.get(operator, "operator") == "$size" do
exec?(operator, elem, ctx)
else
case Map.get(operator, "operator") do
# $all need specific action
all_operator when all_operator == "$all" ->
exec?(operator, elem, ctx)

# not operator need cond match all the list add value in @all_operator
op when op in @all_operator ->
exec_all(elem, elem_value, ctx, operator)

# other operator need cond matchh any of the list
_common ->
exec_any(elem, elem_value, ctx, operator)
end
end
end)
end
Expand Down Expand Up @@ -128,33 +134,7 @@ defmodule QueryParser.Exec do
ctx
) do
{elem_value, ctx} = Map.pop(ctx, "elem_value")

case operator do
"$eq" ->
elem_value == exec_value(value, elem, ctx)

"$ne" ->
elem_value != exec_value(value, elem, ctx)

"$lt" ->
elem_value < exec_value(value, elem, ctx)

"$lte" ->
elem_value <= exec_value(value, elem, ctx)

"$gt" ->
elem_value > exec_value(value, elem, ctx)

"$gte" ->
elem_value >= exec_value(value, elem, ctx)

"$exists" ->
nil? = nil == elem_value
exec_value(value, elem, ctx) != nil?

"$type" ->
is_bson_type(elem_value, exec_value(value, elem, ctx))
end
exec_value_operator?(operator, elem_value, exec_value(value, elem, ctx))
end

defp exec?(%{"pos" => "leaf-clause", "key" => key, "value" => value}, elem, ctx) do
Expand Down Expand Up @@ -204,4 +184,54 @@ defmodule QueryParser.Exec do
end
)
end

defp exec_value_operator?("$eq", elem_value, value) do
elem_value == value
end

defp exec_value_operator?("$ne", elem_value, value) do
elem_value != value
end

defp exec_value_operator?("$lt", elem_value, value) do
elem_value < value
end

defp exec_value_operator?("$lte", elem_value, value) do
elem_value <= value
end

defp exec_value_operator?("$gt", elem_value, value) do
elem_value > value
end

defp exec_value_operator?("$gte", elem_value, value) do
elem_value >= value
end

defp exec_value_operator?("$exists", elem_value, value) when is_nil(elem_value) do
# Since elem_value is nil, we want to return the opposite of $exists value
!value
end

defp exec_value_operator?("$exists", _elem_value, value) do
value
end

defp exec_value_operator?("$size", elem_value, value) when is_list(elem_value) do
elem_value |> length() == value
end

defp exec_value_operator?("$size", _elem_value, _value) do
false
end

defp exec_value_operator?("$type", elem_value, value) do
is_bson_type(elem_value, value)
end

defp exec_value_operator?(operator, _elem_value, _value) do
Logger.error("operator does not exist #{operator}")
false
end
end
2 changes: 1 addition & 1 deletion lib/parser/grammar.ex
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ defmodule QueryParser.Parser.Grammar do
'$lt' /
'$eq' /
'$ne' /
'$size' /
'$type' /
'$exists'"
# '$size'

# '$bitsAllClear' /
# '$bitsAllSet' /
Expand Down
5 changes: 5 additions & 0 deletions test/exec_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -382,5 +382,10 @@ defmodule QueryParser.ExecTest do
%{"_id" => 10}
] = parse_and_exec(data(), %{"_id" => %{"$not" => %{"$lt" => 5}}})
end

test "size operator can only take array" do
assert [] = parse_and_exec(data(), %{"_id" => %{"$size" => 5}})
assert [] = parse_and_exec(data(), %{"ids" => %{"$size" => 10}})
end
end
end
6 changes: 3 additions & 3 deletions test/parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ defmodule QueryParser.ParserTest do
end

test "should accept $size operator" do
not_supported(%{"foo" => %{"$size" => 10}})
supported(%{"foo" => %{"$size" => 10}})
end

test "should accept $regex operator without options (via leaf value)" do
Expand Down Expand Up @@ -314,11 +314,11 @@ defmodule QueryParser.ParserTest do
end

test "should accept $not with an operator object as its value" do
not_supported(%{"names" => %{"$exists" => true, "$not" => %{"$size" => 0}}})
supported(%{"names" => %{"$exists" => true, "$not" => %{"$size" => 0}}})
end

test "should accept $not with a complex operator object as its value" do
not_supported(%{"names" => %{"$not" => %{"$exists" => true, "$size" => 0}}})
supported(%{"names" => %{"$not" => %{"$exists" => true, "$size" => 0}}})
end

test "should accept $not in combination with a $regex operator without options" do
Expand Down

0 comments on commit 402d48b

Please sign in to comment.