mongo-parser-rb 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a3a58b44007f8b742abfe589c9182b839a70eaa9
4
- data.tar.gz: f2e40e2eb6870f62b0daf5ac4ff7311ddd0484e9
3
+ metadata.gz: 377864fec17861222eb64d45223d527e95e1fc53
4
+ data.tar.gz: 96bbf223ea627086c2107a43e720b877986b5587
5
5
  SHA512:
6
- metadata.gz: 7d21bbdf37312f90431e1cd9c7843ceca3a512173e77a2fe6f01c39683198f9a62d691c5c65e8e4ac8b5d9403a81f45e505c99bfb164cfa5087e9e632bf6cf18
7
- data.tar.gz: d5b1516dba68c439e41f764577558a3c2fd438091ded9e40d819ce12d65a8733484c37bd83c4b7a03d6214414c91b853d4037249a59b5839e0812a7f594cc03b
6
+ metadata.gz: 4625ff07d26acb1a8e632b5e02ccbe8c3965a03dd3dd5ecdcd6d008e29be1f361dcd23b00f65237322e791e82d6895e58db9454a944ee2bc36166f57869eb7ed
7
+ data.tar.gz: 2b35a891d28081c32956e64a5efef2bd9692b7bb5a2d68ba1b05823f91ce4609e353fccb4e429f1a8aa8932d3f2b2230a97825819efad38aa7eb7ee6b0827def
data/Rakefile CHANGED
@@ -9,3 +9,9 @@ Rake::TestTask.new("test") do |test|
9
9
  test.warning = false
10
10
  test.verbose = true
11
11
  end
12
+
13
+
14
+ desc "Run some performance tests"
15
+ task :perf do
16
+ require_relative 'performance/perf.rb'
17
+ end
@@ -1,8 +1,8 @@
1
- require "mongo-parser-rb/version"
2
- require "mongo-parser-rb/exceptions"
3
- require "mongo-parser-rb/field"
4
- require "mongo-parser-rb/query/expression"
5
- require "mongo-parser-rb/query"
1
+ require_relative "mongo-parser-rb/version"
2
+ require_relative "mongo-parser-rb/exceptions"
3
+ require_relative "mongo-parser-rb/field"
4
+ require_relative "mongo-parser-rb/query/expression"
5
+ require_relative "mongo-parser-rb/query"
6
6
 
7
7
  module MongoParserRB
8
8
  end
@@ -7,7 +7,6 @@ module MongoParserRB
7
7
  end
8
8
 
9
9
  def value_in_document(document)
10
- document = stringify_keys(document)
11
10
  @field_parts.reduce(document) do |value, field|
12
11
  case value
13
12
  when Array
@@ -22,8 +21,6 @@ module MongoParserRB
22
21
  end
23
22
 
24
23
  def in_document?(document)
25
- document = stringify_keys(document)
26
-
27
24
  @field_parts.reduce(document) do |value, field|
28
25
  return false unless value.has_key?(field)
29
26
  value[field]
@@ -32,22 +29,5 @@ module MongoParserRB
32
29
  true
33
30
  end
34
31
 
35
- private
36
-
37
- def stringify_keys(document)
38
- document.reduce({}) do |new_document, (k,v)|
39
- new_document[k.to_s] = case v
40
- when Hash
41
- stringify_keys(v)
42
- when Array
43
- v.map { |e| e.kind_of?(Hash) ? stringify_keys(e) : e }
44
- else
45
- v
46
- end
47
-
48
- new_document
49
- end
50
- end
51
-
52
32
  end
53
33
  end
@@ -31,9 +31,11 @@ module MongoParserRB
31
31
  # @return [Boolean]
32
32
  def matches_document?(document)
33
33
  raise NotParsedError, "Query not parsed (run parse!)" if @expression_tree.nil?
34
+
35
+ document = stringify_keys(document)
34
36
  @expression_tree.evaluate(document)
35
37
  end
36
-
38
+
37
39
  private
38
40
 
39
41
  def parse_root_expression(query, field = nil)
@@ -43,17 +45,17 @@ module MongoParserRB
43
45
  end
44
46
 
45
47
  def parse_sub_expression(key, value, field = nil)
46
- if Expression.operator?(key)
47
- case key
48
- when *Expression.conjunction_operators
48
+ if Expression::ALL_OPERATORS.include?(key)
49
+ case key
50
+ when *Expression::CONJUNCTION_OPERATORS
49
51
  Expression.new(key, value.map { |v| parse_root_expression(v) })
50
- when *Expression.inversion_operators
52
+ when *Expression::INVERSION_OPERATORS
51
53
  if value.kind_of?(Hash)
52
54
  Expression.new(:$not, field, parse_root_expression(value, field))
53
55
  else
54
56
  Expression.new(:$not, field, Expression.new(:$eq, field, value))
55
57
  end
56
- when *Expression.elemMatch_operators
58
+ when *Expression::ELEM_MATCH_OPERATORS
57
59
  Expression.new(:$elemMatch, field, value.to_a.map do |(key, value)|
58
60
  parse_sub_expression(key, value)
59
61
  end)
@@ -67,5 +69,20 @@ module MongoParserRB
67
69
  end
68
70
  end
69
71
 
72
+ def stringify_keys(document)
73
+ document.reduce({}) do |new_document, (k,v)|
74
+ new_document[k.to_s] = case v
75
+ when Hash
76
+ stringify_keys(v)
77
+ when Array
78
+ v.map { |e| e.kind_of?(Hash) ? stringify_keys(e) : e }
79
+ else
80
+ v
81
+ end
82
+
83
+ new_document
84
+ end
85
+ end
86
+
70
87
  end
71
88
  end
@@ -2,71 +2,17 @@ module MongoParserRB
2
2
  class Query
3
3
  class Expression
4
4
 
5
- class << self
6
-
7
- def inversion_operators
8
- @inversion_operators ||= [
9
- :$not
10
- ]
11
- end
12
-
13
- def inversion_operator?(operator)
14
- inversion_operators.include?(operator)
15
- end
16
-
17
- def conjunction_operators
18
- @conjunction_operators ||= [
19
- :$and,
20
- :$or
21
- ]
22
- end
23
-
24
- def conjunction_operator?(operator)
25
- conjunction_operators.include?(operator)
26
- end
27
-
28
- def negative_equality_operators
29
- @negative_equality_operators ||= [
30
- :$nin,
31
- :$ne
32
- ]
33
- end
34
-
35
- def equality_operators
36
- @equality_operators ||= [
37
- :$eq,
38
- :$gt,
39
- :$lt,
40
- :$gte,
41
- :$lte,
42
- :$in
43
- ] | negative_equality_operators
44
- end
45
-
46
- def equality_operator?(operator)
47
- equality_operators.include?(operator)
48
- end
49
-
50
- def elemMatch_operators
51
- @elemMatch_operators ||= [
52
- :$elemMatch
53
- ]
54
- end
55
-
56
- def elemMatch_operator?(operator)
57
- elemMatch_operators.include?(operator)
58
- end
59
-
60
- def operator?(operator)
61
- equality_operator?(operator) || conjunction_operator?(operator) || inversion_operator?(operator) || elemMatch_operator?(operator)
62
- end
63
-
64
- end
5
+ INVERSION_OPERATORS = [:$not].freeze
6
+ CONJUNCTION_OPERATORS = [:$and, :$or].freeze
7
+ NEGATIVE_EQUALITY_OPERATORS = [:$nin, :$ne].freeze
8
+ EQUALITY_OPERATORS = [:$eq, :$gt, :$lt, :$gte, :$lte, :$in, :$nin, :$ne].freeze
9
+ ELEM_MATCH_OPERATORS = [:$elemMatch].freeze
10
+ ALL_OPERATORS = [:$eq, :$gt, :$lt, :$gte, :$lte, :$in, :$nin, :$ne, :$and, :$or, :$not, :$elemMatch].freeze
65
11
 
66
12
  def initialize(operator, *args)
67
13
  @operator = operator
68
14
 
69
- if Expression.conjunction_operator?(@operator)
15
+ if CONJUNCTION_OPERATORS.include?(@operator)
70
16
  @arguments = args[0]
71
17
  else
72
18
  @field = Field.new(args[0])
@@ -76,15 +22,15 @@ module MongoParserRB
76
22
 
77
23
  def evaluate(document)
78
24
  case @operator
79
- when *Expression.conjunction_operators
25
+ when *Expression::CONJUNCTION_OPERATORS
80
26
  evaluate_conjunction(document)
81
- when *Expression.negative_equality_operators
27
+ when *Expression::NEGATIVE_EQUALITY_OPERATORS
82
28
  evaluate_negative_equality(document)
83
- when *Expression.equality_operators
29
+ when *Expression::EQUALITY_OPERATORS
84
30
  evaluate_equality(document)
85
- when *Expression.inversion_operators
31
+ when *Expression::INVERSION_OPERATORS
86
32
  evaluate_inversion(document)
87
- when *Expression.elemMatch_operators
33
+ when *Expression::ELEM_MATCH_OPERATORS
88
34
  evaluate_elemMatch(document)
89
35
  end
90
36
  rescue NoMethodError, TypeError
@@ -100,7 +46,7 @@ module MongoParserRB
100
46
  end
101
47
  end
102
48
  end
103
-
49
+
104
50
  def evaluate_inversion(document)
105
51
  # Mongo negative equality operators return true when
106
52
  # the specified field does not exist on a document.
@@ -130,8 +76,7 @@ module MongoParserRB
130
76
  # the specified field does not exist on a document.
131
77
  return true if !value_for_field && !@field.in_document?(document)
132
78
 
133
- if value_for_field.kind_of?(Array) &&
134
- !@arguments.kind_of?(Array)
79
+ if value_for_field.kind_of?(Array) && !@arguments.kind_of?(Array)
135
80
  !value_for_field.include?(@arguments)
136
81
  else
137
82
  value_for_field != @arguments
@@ -152,8 +97,7 @@ module MongoParserRB
152
97
  when :$eq
153
98
  if @arguments.kind_of?(Regexp)
154
99
  !!(value_for_field =~ @arguments)
155
- elsif value_for_field.kind_of?(Array) &&
156
- !@arguments.kind_of?(Array)
100
+ elsif value_for_field.kind_of?(Array) && !@arguments.kind_of?(Array)
157
101
  value_for_field.include?(@arguments)
158
102
  else
159
103
  value_for_field == @arguments
@@ -1,3 +1,3 @@
1
1
  module MongoParserRB
2
- VERSION = "0.0.11"
2
+ VERSION = "0.0.12"
3
3
  end
@@ -0,0 +1,49 @@
1
+ require 'benchmark'
2
+ require_relative '../lib/mongo-parser-rb'
3
+
4
+ iterations = 500_000
5
+
6
+ Benchmark.bm(22) do |bm|
7
+ bm.report('simple query parsing') do
8
+ query_hash = {
9
+ :$or => [
10
+ { aaa: { :$gt => 20 } },
11
+ { bbb: {:$not => {:$gt => 10 }} },
12
+ { ccc: 11 },
13
+ { ddd: 12 },
14
+ { eee: 13 },
15
+ { :fff => { :$in => [1] } }
16
+ ]
17
+ }
18
+
19
+ iterations.times do
20
+ MongoParserRB::Query.parse(query_hash)
21
+ end
22
+ end
23
+
24
+ bm.report('simple query matching') do
25
+ query = MongoParserRB::Query.parse({
26
+ :$or => [
27
+ { aaa: { :$gt => 20 } },
28
+ { bbb: 10 },
29
+ { ccc: 11 },
30
+ { ddd: 12 },
31
+ { eee: 13 }
32
+ ]
33
+ })
34
+
35
+ document = {
36
+ aaa: 1, bbb: 2, ccc: 3, ddd: 4, eee: 5,
37
+ nested1: {
38
+ aaa: 1, bbb: 2, ccc: 3, ddd: 4, eee: 5,
39
+ nested: {
40
+ aaa: 1, bbb: 2, ccc: 3, ddd: 4, eee: 5
41
+ }
42
+ }
43
+ }
44
+
45
+ iterations.times do
46
+ query.matches_document?(document)
47
+ end
48
+ end
49
+ end
@@ -1,41 +1,41 @@
1
1
  require 'test_helper'
2
2
 
3
- class FieldTest < MiniTest::Unit::TestCase
3
+ class FieldTest < Minitest::Test
4
4
 
5
5
  def test_returns_value_when_key_present
6
6
  field = MongoParserRB::Field.new(:"custom_data.tracked_users")
7
- assert_equal 10, field.value_in_document(:custom_data => {:tracked_users => 10})
7
+ assert_equal 10, field.value_in_document('custom_data' => {'tracked_users' => 10})
8
8
  end
9
9
 
10
10
  def test_returns_nil_when_key_not_present
11
11
  field = MongoParserRB::Field.new(:"custom_data.tracked_users")
12
- assert_nil field.value_in_document(:custom_data => {:something_else => 10})
13
- assert_nil field.value_in_document(:name => "Ben")
12
+ assert_nil field.value_in_document('custom_data' => {'something_else' => 10})
13
+ assert_nil field.value_in_document('name' => "Ben")
14
14
  end
15
15
 
16
16
  def test_document_has_a_field
17
17
  field = MongoParserRB::Field.new(:"custom_data.tracked_users")
18
- assert field.in_document?(:custom_data => {:tracked_users => 10})
19
- refute field.in_document?(:not_custom_data => {:tracked_users => 10})
18
+ assert field.in_document?('custom_data' => {'tracked_users' => 10})
19
+ refute field.in_document?('not_custom_data' => {'tracked_users' => 10})
20
20
 
21
21
  field = MongoParserRB::Field.new(:"session_count")
22
- assert field.in_document?(:custom_data => {:tracked_users => 10}, :session_count => 5)
23
- refute field.in_document?(:custom_data => {:tracked_users => 10})
22
+ assert field.in_document?('custom_data' => {'tracked_users' => 10}, 'session_count' => 5)
23
+ refute field.in_document?('custom_data' => {'tracked_users' => 10})
24
24
  end
25
25
 
26
26
  def test_returning_array_element
27
27
  field = MongoParserRB::Field.new(:"something.array.0")
28
- assert_equal 1, field.value_in_document(:something => {:array => [1,2]})
28
+ assert_equal 1, field.value_in_document('something' => {'array' => [1,2]})
29
29
  end
30
-
30
+
31
31
  def test_returning_empty_array
32
32
  field = MongoParserRB::Field.new(:"something.array.name")
33
- assert_equal [], field.value_in_document(:something => {:array => []})
33
+ assert_equal [], field.value_in_document('something' => {'array' => []})
34
34
  end
35
35
 
36
36
  def test_returning_hash_in_array
37
37
  field = MongoParserRB::Field.new(:"something.array.0.key")
38
- document = {:something => {:array => [{:key => 'hello world'}, {:key => 'bye world'}]}}
38
+ document = {'something' => {'array' => [{'key' => 'hello world'}, {'key' => 'bye world'}]}}
39
39
  assert_equal 'hello world', field.value_in_document(document)
40
40
 
41
41
  field = MongoParserRB::Field.new(:"something.array.1.key")
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class QueryTest < MiniTest::Unit::TestCase
3
+ class QueryTest < Minitest::Test
4
4
  def test_raises_if_not_parsed
5
5
  assert_raises(MongoParserRB::NotParsedError) do
6
6
  query = MongoParserRB::Query.new(:integer_key => 10)
@@ -113,6 +113,18 @@ class QueryTest < MiniTest::Unit::TestCase
113
113
  refute query.matches_document?(:integer_key => 5)
114
114
  end
115
115
 
116
+ def test_nested_or
117
+ query = MongoParserRB::Query.parse({
118
+ :$or=>[{ :name => 'cormac' }, { :name => 'john' }],
119
+ :anonymous => { :$in => [false, nil] },
120
+ :app_id => 6
121
+ })
122
+ assert query.matches_document?(:name => 'cormac', :app_id => 6)
123
+ assert query.matches_document?(:name => 'john', :app_id => 6)
124
+ refute query.matches_document?(:name => 'john', :app_id => 7)
125
+ refute query.matches_document?(:name => 'john', :app_id => 6, :anonymous => true)
126
+ end
127
+
116
128
  def test_boolean_eq
117
129
  query = MongoParserRB::Query.parse(:boolean_key => false)
118
130
  assert query.matches_document?(:boolean_key => false)
@@ -137,12 +149,12 @@ class QueryTest < MiniTest::Unit::TestCase
137
149
  refute query.matches_document?(:array_key => [1,4,5])
138
150
  end
139
151
 
140
- def test_nil_by_absence_nin
152
+ def test_nil_by_absence_nin
141
153
  query = MongoParserRB::Query.parse(:"custom_data.value" => {:$nin => [nil]})
142
154
  assert query.matches_document?(:custom_data => {:value => 5})
143
155
  refute query.matches_document?({})
144
156
  end
145
-
157
+
146
158
  def test_nil_by_empty
147
159
  query = MongoParserRB::Query.parse({:"user_event_summaries.name" => {:$ne => "second-support"}})
148
160
  assert query.matches_document?({"user_event_summaries" => []})
@@ -224,19 +236,19 @@ class QueryTest < MiniTest::Unit::TestCase
224
236
  query = MongoParserRB::Query.parse(:array_key => {:$ne => [1]})
225
237
  assert query.matches_document?(:array_key => [1,2])
226
238
  end
227
-
239
+
228
240
  def test_elemMatch
229
241
  query = MongoParserRB::Query.parse({:user_event_summaries => {:$elemMatch=> {:name => "second-support", :count => 3}}})
230
242
  refute query.matches_document?(:user_event_summaries => [{:name => "first-support", :count => 3}, {:name => "second-support", :count => 4}])
231
243
  assert query.matches_document?(:user_event_summaries => [{:name => "first-support", :count => 4}, {:name => "second-support", :count => 3}])
232
244
  end
233
-
245
+
234
246
  def test_elemMatch_inequality
235
247
  query = MongoParserRB::Query.parse(:user_event_summaries => {:$elemMatch=> {:count => {:$ne => 2}, :name => "second-support"}})
236
248
  refute query.matches_document?(:user_event_summaries => [{:name => "first-support", :count => 3}, {:name => "second-support", :count => 2}])
237
249
  assert query.matches_document?(:user_event_summaries => [{:name => "first-support", :count => 3}, {:name => "second-support", :count => 3}])
238
250
  end
239
-
251
+
240
252
  def test_datatype_mismatch
241
253
  query = MongoParserRB::Query.parse(:integer_key => {:$gt => 5})
242
254
  refute query.matches_document?(:integer_key => "hello")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongo-parser-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.11
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben McRedmond
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-14 00:00:00.000000000 Z
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parse and evaluate mongo queries in Ruby
14
14
  email:
@@ -17,8 +17,8 @@ executables: []
17
17
  extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
- - .gitignore
21
- - .yardopts
20
+ - ".gitignore"
21
+ - ".yardopts"
22
22
  - Gemfile
23
23
  - LICENSE.txt
24
24
  - README.md
@@ -30,6 +30,7 @@ files:
30
30
  - lib/mongo-parser-rb/query/expression.rb
31
31
  - lib/mongo-parser-rb/version.rb
32
32
  - mongo-parser-rb.gemspec
33
+ - performance/perf.rb
33
34
  - test/mongo-parser-rb/field_test.rb
34
35
  - test/mongo-parser-rb/query_test.rb
35
36
  - test/test_helper.rb
@@ -42,17 +43,17 @@ require_paths:
42
43
  - lib
43
44
  required_ruby_version: !ruby/object:Gem::Requirement
44
45
  requirements:
45
- - - '>='
46
+ - - ">="
46
47
  - !ruby/object:Gem::Version
47
48
  version: '0'
48
49
  required_rubygems_version: !ruby/object:Gem::Requirement
49
50
  requirements:
50
- - - '>='
51
+ - - ">="
51
52
  - !ruby/object:Gem::Version
52
53
  version: '0'
53
54
  requirements: []
54
55
  rubyforge_project:
55
- rubygems_version: 2.0.3
56
+ rubygems_version: 2.2.2
56
57
  signing_key:
57
58
  specification_version: 4
58
59
  summary: Parse and evaluate mongo queries in Ruby