plucky 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|