mongo-parser-rb 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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