plucky 0.4.0 → 0.4.1
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.
- data/UPGRADES +2 -0
- data/lib/plucky.rb +17 -9
- data/lib/plucky/new_relic.rb +9 -0
- data/lib/plucky/query.rb +9 -3
- data/lib/plucky/version.rb +2 -2
- data/test/helper.rb +45 -0
- data/test/plucky/pagination/test_decorator.rb +34 -0
- data/test/plucky/pagination/test_paginator.rb +120 -0
- data/test/plucky/test_criteria_hash.rb +296 -0
- data/test/plucky/test_options_hash.rb +302 -0
- data/test/plucky/test_query.rb +819 -0
- data/test/test_plucky.rb +46 -0
- data/test/test_symbol.rb +11 -0
- data/test/test_symbol_operator.rb +49 -0
- metadata +18 -6
data/UPGRADES
ADDED
data/lib/plucky.rb
CHANGED
@@ -14,17 +14,25 @@ module Plucky
|
|
14
14
|
autoload :Paginator, 'plucky/pagination/paginator'
|
15
15
|
end
|
16
16
|
|
17
|
+
# Array of methods that actually perform queries
|
18
|
+
Methods = [
|
19
|
+
:where, :filter, :limit, :skip, :offset, :sort, :order,
|
20
|
+
:fields, :ignore, :only,
|
21
|
+
:each, :find_each,
|
22
|
+
:count, :size, :distinct,
|
23
|
+
:last, :first, :all, :paginate,
|
24
|
+
:exists?, :exist?, :empty?,
|
25
|
+
:to_a, :remove,
|
26
|
+
]
|
27
|
+
|
17
28
|
def self.to_object_id(value)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
29
|
+
return value if value.is_a?(BSON::ObjectId)
|
30
|
+
return nil if value.nil? || (value.respond_to?(:empty?) && value.empty?)
|
31
|
+
|
32
|
+
if BSON::ObjectId.legal?(value.to_s)
|
33
|
+
BSON::ObjectId.from_string(value.to_s)
|
22
34
|
else
|
23
|
-
|
24
|
-
BSON::ObjectId.from_string(value.to_s)
|
25
|
-
else
|
26
|
-
value
|
27
|
-
end
|
35
|
+
value
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
data/lib/plucky/query.rb
CHANGED
@@ -8,7 +8,8 @@ module Plucky
|
|
8
8
|
OptionKeys = [
|
9
9
|
:select, :offset, :order, # MM
|
10
10
|
:fields, :skip, :limit, :sort, :hint, :snapshot, # Ruby Driver
|
11
|
-
:batch_size, :timeout, :transformer
|
11
|
+
:batch_size, :timeout, :transformer, # Ruby Driver
|
12
|
+
:max_scan, :show_disk_loc, :return_key, # Ruby Driver
|
12
13
|
]
|
13
14
|
|
14
15
|
attr_reader :criteria, :options, :collection
|
@@ -85,9 +86,14 @@ module Plucky
|
|
85
86
|
find_each.each { |doc| yield(doc) }
|
86
87
|
end
|
87
88
|
|
88
|
-
def remove(opts={})
|
89
|
+
def remove(opts={}, driver_opts={})
|
89
90
|
query = clone.amend(opts)
|
90
|
-
query.collection.remove(query.criteria.to_hash)
|
91
|
+
query.collection.remove(query.criteria.to_hash, driver_opts)
|
92
|
+
end
|
93
|
+
|
94
|
+
def update(document, driver_opts={})
|
95
|
+
query = clone
|
96
|
+
query.collection.update(query.criteria.to_hash, document, driver_opts)
|
91
97
|
end
|
92
98
|
|
93
99
|
def count(opts={})
|
data/lib/plucky/version.rb
CHANGED
data/test/helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
gem 'jnunemaker-matchy', '~> 0.4.0'
|
3
|
+
gem 'log_buddy'
|
4
|
+
gem 'shoulda', '~> 2.11'
|
5
|
+
gem 'mocha', '~> 0.9.8'
|
6
|
+
|
7
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
|
+
require 'plucky'
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
require 'logger'
|
12
|
+
require 'pp'
|
13
|
+
|
14
|
+
require 'log_buddy'
|
15
|
+
require 'shoulda'
|
16
|
+
require 'matchy'
|
17
|
+
require 'mocha'
|
18
|
+
|
19
|
+
log_dir = File.expand_path('../../log', __FILE__)
|
20
|
+
FileUtils.mkdir_p(log_dir)
|
21
|
+
Log = Logger.new(File.join(log_dir, 'test.log'))
|
22
|
+
|
23
|
+
LogBuddy.init :logger => Log
|
24
|
+
|
25
|
+
connection = Mongo::Connection.new('127.0.0.1', 27017, :logger => Log)
|
26
|
+
DB = connection.db('test')
|
27
|
+
|
28
|
+
class Test::Unit::TestCase
|
29
|
+
def setup
|
30
|
+
DB.collections.map do |collection|
|
31
|
+
collection.remove
|
32
|
+
collection.drop_indexes
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def oh(*args)
|
37
|
+
BSON::OrderedHash.new.tap do |hash|
|
38
|
+
args.each { |a| hash[a[0]] = a[1] }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
operators = %w{gt lt gte lte ne in nin mod all size exists}
|
44
|
+
operators.delete('size') if RUBY_VERSION >= '1.9.1'
|
45
|
+
SymbolOperators = operators
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class PaginatorTest < Test::Unit::TestCase
|
4
|
+
include Plucky::Pagination
|
5
|
+
|
6
|
+
context "Object decorated with Decorator with paginator set" do
|
7
|
+
setup do
|
8
|
+
@object = [1, 2, 3, 4]
|
9
|
+
@object_id = @object.object_id
|
10
|
+
@paginator = Paginator.new(20, 2, 10)
|
11
|
+
@object.extend(Decorator)
|
12
|
+
@object.paginator(@paginator)
|
13
|
+
end
|
14
|
+
subject { @object }
|
15
|
+
|
16
|
+
should "be able to get paginator" do
|
17
|
+
subject.paginator.should == @paginator
|
18
|
+
end
|
19
|
+
|
20
|
+
[:total_entries, :current_page, :per_page, :total_pages, :out_of_bounds?,
|
21
|
+
:previous_page, :next_page, :skip, :limit, :offset].each do |method|
|
22
|
+
should "delegate #{method} to paginator" do
|
23
|
+
subject.send(method).should == @paginator.send(method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
should "not interfere with other methods on the object" do
|
28
|
+
@object.object_id.should == @object_id
|
29
|
+
@object.should == [1, 2, 3, 4]
|
30
|
+
@object.size.should == 4
|
31
|
+
@object.select { |o| o > 2 }.should == [3, 4]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class PaginatorTest < Test::Unit::TestCase
|
4
|
+
include Plucky::Pagination
|
5
|
+
|
6
|
+
context "#initialize" do
|
7
|
+
context "with total and page" do
|
8
|
+
setup { @paginator = Paginator.new(20, 2) }
|
9
|
+
subject { @paginator }
|
10
|
+
|
11
|
+
should "set total" do
|
12
|
+
subject.total_entries.should == 20
|
13
|
+
end
|
14
|
+
|
15
|
+
should "set page" do
|
16
|
+
subject.current_page.should == 2
|
17
|
+
end
|
18
|
+
|
19
|
+
should "default per_page to 25" do
|
20
|
+
subject.per_page.should == 25
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with total, page and per_page" do
|
25
|
+
setup { @paginator = Paginator.new(20, 2, 10) }
|
26
|
+
subject { @paginator }
|
27
|
+
|
28
|
+
should "set total" do
|
29
|
+
subject.total_entries.should == 20
|
30
|
+
end
|
31
|
+
|
32
|
+
should "set page" do
|
33
|
+
subject.current_page.should == 2
|
34
|
+
end
|
35
|
+
|
36
|
+
should "set per_page" do
|
37
|
+
subject.per_page.should == 10
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with string values for total, page and per_page" do
|
42
|
+
setup { @paginator = Paginator.new('20', '2', '10') }
|
43
|
+
subject { @paginator }
|
44
|
+
|
45
|
+
should "set total" do
|
46
|
+
subject.total_entries.should == 20
|
47
|
+
end
|
48
|
+
|
49
|
+
should "set page" do
|
50
|
+
subject.current_page.should == 2
|
51
|
+
end
|
52
|
+
|
53
|
+
should "set per_page" do
|
54
|
+
subject.per_page.should == 10
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "with page less than 1" do
|
59
|
+
setup { @paginator = Paginator.new(20, -2, 10) }
|
60
|
+
subject { @paginator }
|
61
|
+
|
62
|
+
should "set page to 1" do
|
63
|
+
subject.current_page.should == 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
should "alias limit to per_page" do
|
69
|
+
Paginator.new(30, 2, 30).limit.should == 30
|
70
|
+
end
|
71
|
+
|
72
|
+
should "be know total number of pages" do
|
73
|
+
Paginator.new(43, 2, 7).total_pages.should == 7
|
74
|
+
Paginator.new(40, 2, 10).total_pages.should == 4
|
75
|
+
end
|
76
|
+
|
77
|
+
context "#out_of_bounds?" do
|
78
|
+
should "be true if current_page is greater than total_pages" do
|
79
|
+
Paginator.new(2, 3, 1).should be_out_of_bounds
|
80
|
+
end
|
81
|
+
|
82
|
+
should "be false if current page is less than total_pages" do
|
83
|
+
Paginator.new(2, 1, 1).should_not be_out_of_bounds
|
84
|
+
end
|
85
|
+
|
86
|
+
should "be false if current page equals total_pages" do
|
87
|
+
Paginator.new(2, 2, 1).should_not be_out_of_bounds
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "#previous_page" do
|
92
|
+
should "be nil if there is no page less than current" do
|
93
|
+
Paginator.new(2, 1, 1).previous_page.should be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
should "be number less than current page if there is one" do
|
97
|
+
Paginator.new(2, 2, 1).previous_page.should == 1
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "#next_page" do
|
102
|
+
should "be nil if no page greater than current page" do
|
103
|
+
Paginator.new(2, 2, 1).next_page.should be_nil
|
104
|
+
end
|
105
|
+
|
106
|
+
should "be number greater than current page if there is one" do
|
107
|
+
Paginator.new(2, 1, 1).next_page.should == 2
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context "#skip" do
|
112
|
+
should "work" do
|
113
|
+
Paginator.new(30, 3, 10).skip.should == 20
|
114
|
+
end
|
115
|
+
|
116
|
+
should "be aliased to offset for will paginate" do
|
117
|
+
Paginator.new(30, 3, 10).offset.should == 20
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class CriteriaHashTest < Test::Unit::TestCase
|
4
|
+
include Plucky
|
5
|
+
|
6
|
+
context "Plucky::CriteriaHash" do
|
7
|
+
should "delegate missing methods to the source hash" do
|
8
|
+
hash = {:baz => 'wick', :foo => 'bar'}
|
9
|
+
criteria = CriteriaHash.new(hash)
|
10
|
+
criteria[:foo].should == 'bar'
|
11
|
+
criteria[:baz].should == 'wick'
|
12
|
+
criteria.keys.to_set.should == [:baz, :foo].to_set
|
13
|
+
end
|
14
|
+
|
15
|
+
SymbolOperators.each do |operator|
|
16
|
+
should "work with #{operator} symbol operator" do
|
17
|
+
CriteriaHash.new(:age.send(operator) => 21)[:age].should == {"$#{operator}" => 21}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
should "handle multiple symbol operators on the same field" do
|
22
|
+
CriteriaHash.new(:age.gt => 12, :age.lt => 20)[:age].should == {
|
23
|
+
'$gt' => 12, '$lt' => 20
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
context "#initialize_copy" do
|
28
|
+
setup do
|
29
|
+
@original = CriteriaHash.new({
|
30
|
+
:comments => {:_id => 1}, :tags => ['mongo', 'ruby'],
|
31
|
+
}, :object_ids => [:_id])
|
32
|
+
@cloned = @original.clone
|
33
|
+
end
|
34
|
+
|
35
|
+
should "duplicate source hash" do
|
36
|
+
@cloned.source.should_not equal(@original.source)
|
37
|
+
end
|
38
|
+
|
39
|
+
should "duplicate options hash" do
|
40
|
+
@cloned.options.should_not equal(@original.options)
|
41
|
+
end
|
42
|
+
|
43
|
+
should "clone duplicable? values" do
|
44
|
+
@cloned[:comments].should_not equal(@original[:comments])
|
45
|
+
@cloned[:tags].should_not equal(@original[:tags])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "#object_ids=" do
|
50
|
+
should "work with array" do
|
51
|
+
criteria = CriteriaHash.new
|
52
|
+
criteria.object_ids = [:_id]
|
53
|
+
criteria.object_ids.should == [:_id]
|
54
|
+
end
|
55
|
+
|
56
|
+
should "flatten multi-dimensional array" do
|
57
|
+
criteria = CriteriaHash.new
|
58
|
+
criteria.object_ids = [[:_id]]
|
59
|
+
criteria.object_ids.should == [:_id]
|
60
|
+
end
|
61
|
+
|
62
|
+
should "raise argument error if not array" do
|
63
|
+
assert_raises(ArgumentError) { CriteriaHash.new.object_ids = {} }
|
64
|
+
assert_raises(ArgumentError) { CriteriaHash.new.object_ids = nil }
|
65
|
+
assert_raises(ArgumentError) { CriteriaHash.new.object_ids = 'foo' }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "#[]=" do
|
70
|
+
should "leave string values for string keys alone" do
|
71
|
+
criteria = CriteriaHash.new
|
72
|
+
criteria[:foo] = 'bar'
|
73
|
+
criteria[:foo].should == 'bar'
|
74
|
+
end
|
75
|
+
|
76
|
+
should "convert string values to object ids for object id keys" do
|
77
|
+
id = BSON::ObjectId.new
|
78
|
+
criteria = CriteriaHash.new({}, :object_ids => [:_id])
|
79
|
+
criteria[:_id] = id.to_s
|
80
|
+
criteria[:_id].should == id
|
81
|
+
end
|
82
|
+
|
83
|
+
should "convert sets to arrays" do
|
84
|
+
criteria = CriteriaHash.new
|
85
|
+
criteria[:foo] = [1, 2].to_set
|
86
|
+
criteria[:foo].should == {'$in' => [1, 2]}
|
87
|
+
end
|
88
|
+
|
89
|
+
should "convert times to utc" do
|
90
|
+
time = Time.now
|
91
|
+
criteria = CriteriaHash.new
|
92
|
+
criteria[:foo] = time
|
93
|
+
criteria[:foo].should be_utc
|
94
|
+
criteria[:foo].should == time.utc
|
95
|
+
end
|
96
|
+
|
97
|
+
should "convert :id to :_id" do
|
98
|
+
criteria = CriteriaHash.new
|
99
|
+
criteria[:id] = 1
|
100
|
+
criteria[:_id].should == 1
|
101
|
+
criteria[:id].should be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
should "work with symbol operators" do
|
105
|
+
criteria = CriteriaHash.new
|
106
|
+
criteria[:_id.in] = ['foo']
|
107
|
+
criteria[:_id].should == {'$in' => ['foo']}
|
108
|
+
end
|
109
|
+
|
110
|
+
should "set each of the conditions pairs" do
|
111
|
+
criteria = CriteriaHash.new
|
112
|
+
criteria[:conditions] = {:_id => 'john', :foo => 'bar'}
|
113
|
+
criteria[:_id].should == 'john'
|
114
|
+
criteria[:foo].should == 'bar'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "with id key" do
|
119
|
+
should "convert to _id" do
|
120
|
+
id = BSON::ObjectId.new
|
121
|
+
criteria = CriteriaHash.new(:id => id)
|
122
|
+
criteria[:_id].should == id
|
123
|
+
criteria[:id].should be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
should "convert id with symbol operator to _id with modifier" do
|
127
|
+
id = BSON::ObjectId.new
|
128
|
+
criteria = CriteriaHash.new(:id.ne => id)
|
129
|
+
criteria[:_id].should == {'$ne' => id}
|
130
|
+
criteria[:id].should be_nil
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "with time value" do
|
135
|
+
should "convert to utc if not utc" do
|
136
|
+
CriteriaHash.new(:created_at => Time.now)[:created_at].utc?.should be(true)
|
137
|
+
end
|
138
|
+
|
139
|
+
should "leave utc alone" do
|
140
|
+
CriteriaHash.new(:created_at => Time.now.utc)[:created_at].utc?.should be(true)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "with array value" do
|
145
|
+
should "default to $in" do
|
146
|
+
CriteriaHash.new(:numbers => [1,2,3])[:numbers].should == {'$in' => [1,2,3]}
|
147
|
+
end
|
148
|
+
|
149
|
+
should "use existing modifier if present" do
|
150
|
+
CriteriaHash.new(:numbers => {'$all' => [1,2,3]})[:numbers].should == {'$all' => [1,2,3]}
|
151
|
+
CriteriaHash.new(:numbers => {'$any' => [1,2,3]})[:numbers].should == {'$any' => [1,2,3]}
|
152
|
+
end
|
153
|
+
|
154
|
+
should "not turn value to $in with $or key" do
|
155
|
+
CriteriaHash.new(:$or => [{:numbers => 1}, {:numbers => 2}] )[:$or].should == [{:numbers=>1}, {:numbers=>2}]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context "with set value" do
|
160
|
+
should "default to $in and convert to array" do
|
161
|
+
CriteriaHash.new(:numbers => [1,2,3].to_set)[:numbers].should == {'$in' => [1,2,3]}
|
162
|
+
end
|
163
|
+
|
164
|
+
should "use existing modifier if present and convert to array" do
|
165
|
+
CriteriaHash.new(:numbers => {'$all' => [1,2,3].to_set})[:numbers].should == {'$all' => [1,2,3]}
|
166
|
+
CriteriaHash.new(:numbers => {'$any' => [1,2,3].to_set})[:numbers].should == {'$any' => [1,2,3]}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context "with string ids for string keys" do
|
171
|
+
setup do
|
172
|
+
@id = BSON::ObjectId.new
|
173
|
+
@room_id = BSON::ObjectId.new
|
174
|
+
@criteria = CriteriaHash.new(:_id => @id.to_s, :room_id => @room_id.to_s)
|
175
|
+
end
|
176
|
+
|
177
|
+
should "leave string ids as strings" do
|
178
|
+
@criteria[:_id].should == @id.to_s
|
179
|
+
@criteria[:room_id].should == @room_id.to_s
|
180
|
+
@criteria[:_id].should be_instance_of(String)
|
181
|
+
@criteria[:room_id].should be_instance_of(String)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context "with string ids for object id keys" do
|
186
|
+
setup do
|
187
|
+
@id = BSON::ObjectId.new
|
188
|
+
@room_id = BSON::ObjectId.new
|
189
|
+
end
|
190
|
+
|
191
|
+
should "convert strings to object ids" do
|
192
|
+
criteria = CriteriaHash.new({:_id => @id.to_s, :room_id => @room_id.to_s}, :object_ids => [:_id, :room_id])
|
193
|
+
criteria[:_id].should == @id
|
194
|
+
criteria[:room_id].should == @room_id
|
195
|
+
criteria[:_id].should be_instance_of(BSON::ObjectId)
|
196
|
+
criteria[:room_id].should be_instance_of(BSON::ObjectId)
|
197
|
+
end
|
198
|
+
|
199
|
+
should "convert :id with string value to object id value" do
|
200
|
+
criteria = CriteriaHash.new({:id => @id.to_s}, :object_ids => [:_id])
|
201
|
+
criteria[:_id].should == @id
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context "with string ids for object id keys (nested)" do
|
206
|
+
setup do
|
207
|
+
@id1 = BSON::ObjectId.new
|
208
|
+
@id2 = BSON::ObjectId.new
|
209
|
+
@criteria = CriteriaHash.new({:_id => {'$in' => [@id1.to_s, @id2.to_s]}}, :object_ids => [:_id])
|
210
|
+
end
|
211
|
+
|
212
|
+
should "convert strings to object ids" do
|
213
|
+
@criteria[:_id].should == {'$in' => [@id1, @id2]}
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context "#merge" do
|
218
|
+
should "work when no keys match" do
|
219
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
220
|
+
c2 = CriteriaHash.new(:baz => 'wick')
|
221
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => 'bar', :baz => 'wick')
|
222
|
+
end
|
223
|
+
|
224
|
+
should "turn matching keys with simple values into array" do
|
225
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
226
|
+
c2 = CriteriaHash.new(:foo => 'baz')
|
227
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => {'$in' => %w[bar baz]})
|
228
|
+
end
|
229
|
+
|
230
|
+
should "unique matching key values" do
|
231
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
232
|
+
c2 = CriteriaHash.new(:foo => 'bar')
|
233
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => {'$in' => %w[bar]})
|
234
|
+
end
|
235
|
+
|
236
|
+
should "correctly merge arrays and non-arrays" do
|
237
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
238
|
+
c2 = CriteriaHash.new(:foo => %w[bar baz])
|
239
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => {'$in' => %w[bar baz]})
|
240
|
+
c2.merge(c1).should == CriteriaHash.new(:foo => {'$in' => %w[bar baz]})
|
241
|
+
end
|
242
|
+
|
243
|
+
should "be able to merge two modifier hashes" do
|
244
|
+
c1 = CriteriaHash.new('$in' => [1, 2])
|
245
|
+
c2 = CriteriaHash.new('$in' => [2, 3])
|
246
|
+
c1.merge(c2).should == CriteriaHash.new('$in' => [1, 2, 3])
|
247
|
+
end
|
248
|
+
|
249
|
+
should "merge matching keys with a single modifier" do
|
250
|
+
c1 = CriteriaHash.new(:foo => {'$in' => [1, 2, 3]})
|
251
|
+
c2 = CriteriaHash.new(:foo => {'$in' => [1, 4, 5]})
|
252
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => {'$in' => [1, 2, 3, 4, 5]})
|
253
|
+
end
|
254
|
+
|
255
|
+
should "merge matching keys with multiple modifiers" do
|
256
|
+
c1 = CriteriaHash.new(:foo => {'$in' => [1, 2, 3]})
|
257
|
+
c2 = CriteriaHash.new(:foo => {'$all' => [1, 4, 5]})
|
258
|
+
c1.merge(c2).should == CriteriaHash.new(:foo => {'$in' => [1, 2, 3], '$all' => [1, 4, 5]})
|
259
|
+
end
|
260
|
+
|
261
|
+
should "not update mergee" do
|
262
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
263
|
+
c2 = CriteriaHash.new(:foo => 'baz')
|
264
|
+
c1.merge(c2).should_not equal(c1)
|
265
|
+
c1[:foo].should == 'bar'
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context "#merge!" do
|
270
|
+
should "merge and replace" do
|
271
|
+
c1 = CriteriaHash.new(:foo => 'bar')
|
272
|
+
c2 = CriteriaHash.new(:foo => 'baz')
|
273
|
+
c1.merge!(c2)
|
274
|
+
c1[:foo].should == {'$in' => ['bar', 'baz']}
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context "#simple?" do
|
279
|
+
should "be true if only filtering by _id" do
|
280
|
+
CriteriaHash.new(:_id => 'id').should be_simple
|
281
|
+
end
|
282
|
+
|
283
|
+
should "be true if only filtering by Sci" do
|
284
|
+
CriteriaHash.new(:_id => 'id', :_type => 'Foo').should be_simple
|
285
|
+
end
|
286
|
+
|
287
|
+
should "be false if querying by anthing other than _id/Sci" do
|
288
|
+
CriteriaHash.new(:foo => 'bar').should_not be_simple
|
289
|
+
end
|
290
|
+
|
291
|
+
should "be false if querying only by _type" do
|
292
|
+
CriteriaHash.new(:_type => 'Foo').should_not be_simple
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|