opium 1.5.0 → 1.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/opium/model/criteria.rb +27 -26
- data/lib/opium/version.rb +1 -1
- data/spec/opium/model/criteria_spec.rb +72 -58
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afcd218c0464f3b8a8b47c9f3203007f78a3096c
|
4
|
+
data.tar.gz: 899c86f06d5e7b5ff90e4fe24573964a0f4dc1f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aac084bb325da3d6b1bb5458c4c63cbf39e811daa97c3d06a48e96951937ac18d7b9af9b0b18d47b3cf5caa16574fba50d7412937516b99d704010ef43e689d9
|
7
|
+
data.tar.gz: 3deaf7216912daad377f38e4a4dd34afbf9d8be1c49cbe6b142a904d8558e7ba6905a350b7a12e3df9ae0bc8f546eca60a8e6f2bb60214bc76e736817e36a282
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 1.5.1
|
2
|
+
### Resolved Issues
|
3
|
+
- Model::Criteria should now respond to #size correctly.
|
4
|
+
|
1
5
|
## 1.5.0
|
2
6
|
### New Features
|
3
7
|
- Opium will now work with ActiveModel 5.* going forward. Use a version before 1.5 if ActiveModel 4.* compatibility is needed. As a side-effect, supported rubies moves to anything above 2.2.2
|
data/lib/opium/model/criteria.rb
CHANGED
@@ -3,73 +3,73 @@ module Opium
|
|
3
3
|
class Criteria
|
4
4
|
include Opium::Model::Queryable::ClassMethods
|
5
5
|
include Enumerable
|
6
|
-
|
6
|
+
|
7
7
|
class_attribute :models
|
8
8
|
self.models = {}.with_indifferent_access
|
9
|
-
|
9
|
+
|
10
10
|
def initialize( model_name )
|
11
11
|
@model_name = model_name.respond_to?(:name) ? model_name.name : model_name
|
12
12
|
constraints[:count] = 1
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
attr_reader :model_name
|
16
|
-
|
16
|
+
|
17
17
|
def to_partial_path
|
18
18
|
model._to_partial_path
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def model
|
22
22
|
models[model_name] ||= model_name.constantize
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def chain
|
26
26
|
Marshal.load( Marshal.dump( self ) ).tap {|m| m.instance_variable_set( :@cache, nil )}
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
def constraints
|
30
30
|
@constraints ||= {}.with_indifferent_access
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def update_constraint( constraint, value )
|
34
34
|
chain.tap {|c| c.update_constraint!( constraint, value )}
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def update_constraint!( constraint, value )
|
38
38
|
update_hash_value :constraints, constraint, value
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def constraints?
|
42
42
|
!constraints.except(:count).empty?
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def variables
|
46
46
|
@variables ||= {}.with_indifferent_access
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def update_variable( variable, value )
|
50
50
|
chain.tap {|c| c.update_variable!( variable, value )}
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def update_variable!( variable, value )
|
54
54
|
update_hash_value :variables, variable, value
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def variables?
|
58
58
|
!variables.empty?
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def empty?
|
62
62
|
count == 0
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
def criteria
|
66
66
|
self
|
67
67
|
end
|
68
|
-
|
68
|
+
|
69
69
|
def ==( other )
|
70
70
|
other.is_a?( self.class ) && self.model_name == other.model_name && self.constraints == other.constraints && self.variables == other.variables
|
71
71
|
end
|
72
|
-
|
72
|
+
|
73
73
|
def each(&block)
|
74
74
|
if !block_given?
|
75
75
|
to_enum(:each)
|
@@ -88,34 +88,35 @@ module Opium
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
def inspect
|
93
93
|
inspected_constraints = constraints.map {|k, v| [k, v.inspect].join(': ')}.join(', ')
|
94
94
|
inspected_constraints.prepend ' ' if inspected_constraints.size > 0
|
95
95
|
"#<#{ self.class.name }<#{ model_name }>#{ inspected_constraints }>"
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
def to_parse
|
99
99
|
{}.with_indifferent_access.tap do |result|
|
100
100
|
result[:query] = { where: constraints[:where], className: model_name } if constraints[:where]
|
101
101
|
result[:key] = constraints[:keys] if constraints[:keys]
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def uncache
|
106
106
|
super.tap do |criteria|
|
107
107
|
criteria.instance_variable_set(:@cache, nil)
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
def total_count
|
112
112
|
count && variables[:total_count]
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
|
+
alias_method :size, :total_count
|
115
116
|
alias_method :to_ary, :to_a
|
116
|
-
|
117
|
+
|
117
118
|
private
|
118
|
-
|
119
|
+
|
119
120
|
def update_hash_value( hash_name, key, value )
|
120
121
|
hash = self.send( hash_name )
|
121
122
|
if hash[key].nil? || !value.is_a?(Hash)
|
@@ -126,4 +127,4 @@ module Opium
|
|
126
127
|
end
|
127
128
|
end
|
128
129
|
end
|
129
|
-
end
|
130
|
+
end
|
data/lib/opium/version.rb
CHANGED
@@ -6,10 +6,10 @@ describe Opium::Model::Criteria do
|
|
6
6
|
include Opium::Model
|
7
7
|
field :title, type: String
|
8
8
|
field :price, type: Float
|
9
|
-
|
9
|
+
|
10
10
|
stub('model_name').and_return(ActiveModel::Name.new(klass, nil, 'Game'))
|
11
11
|
end )
|
12
|
-
|
12
|
+
|
13
13
|
stub_request( :get, 'https://api.parse.com/1/classes/Game?count=1' ).with( body: {} ).
|
14
14
|
to_return( status: 200, headers: { 'Content-Type' => 'application/json' }, body: {
|
15
15
|
count: 10,
|
@@ -19,13 +19,13 @@ describe Opium::Model::Criteria do
|
|
19
19
|
]
|
20
20
|
}.to_json )
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
after do
|
24
24
|
Opium::Model::Criteria.models.clear
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
subject { Opium::Model::Criteria.new( 'Object' ) }
|
28
|
-
|
28
|
+
|
29
29
|
it { is_expected.to be_a( Opium::Model::Queryable::ClassMethods ) }
|
30
30
|
it { is_expected.to be_an( Enumerable ) }
|
31
31
|
it { is_expected.to respond_to( :chain ) }
|
@@ -37,9 +37,9 @@ describe Opium::Model::Criteria do
|
|
37
37
|
it { is_expected.to respond_to( :to_parse ) }
|
38
38
|
it { is_expected.to respond_to( :each ) }
|
39
39
|
it { is_expected.to respond_to( :to_a, :to_ary ) }
|
40
|
-
it { is_expected.to respond_to( :count, :total_count ) }
|
40
|
+
it { is_expected.to respond_to( :count, :total_count, :size ) }
|
41
41
|
it { is_expected.to respond_to( :to_partial_path ) }
|
42
|
-
|
42
|
+
|
43
43
|
describe '#chain' do
|
44
44
|
it 'returns a copy of the object' do
|
45
45
|
result = subject.chain
|
@@ -48,8 +48,8 @@ describe Opium::Model::Criteria do
|
|
48
48
|
result.should_not equal( subject )
|
49
49
|
end
|
50
50
|
end
|
51
|
-
|
52
|
-
describe '#update_constraint' do
|
51
|
+
|
52
|
+
describe '#update_constraint' do
|
53
53
|
it 'chains the criteria and alter the specified constraint on the copy' do
|
54
54
|
result = subject.update_constraint( :order, ['title', 1] )
|
55
55
|
result.should be_a( Opium::Model::Criteria )
|
@@ -58,20 +58,20 @@ describe Opium::Model::Criteria do
|
|
58
58
|
result.constraints.should have_key( :order )
|
59
59
|
result.constraints[:order].should == ['title', 1]
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it 'merges hash-valued constraints' do
|
63
63
|
subject.constraints['where'] = { score: { '$lte' => 321 } }
|
64
64
|
result = subject.update_constraint( 'where', price: { '$gte' => 123 } )
|
65
65
|
result.constraints['where'].should =~ { 'score' => { '$lte' => 321 }, 'price' => { '$gte' => 123 } }
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
it 'deep merges hash-valued constraints' do
|
69
69
|
subject.constraints['where'] = { score: { '$lte' => 321 } }
|
70
70
|
result = subject.update_constraint( 'where', score: { '$gte' => 123 } )
|
71
71
|
result.constraints['where'].should =~ { 'score' => { '$lte' => 321, '$gte' => 123 } }
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
describe '#update_variable' do
|
76
76
|
it 'chains the criteria and alter the specified instance variable on the copy' do
|
77
77
|
result = subject.update_variable( :cache, true )
|
@@ -83,136 +83,136 @@ describe Opium::Model::Criteria do
|
|
83
83
|
result.variables[:cache].should == true
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
describe '#==' do
|
88
88
|
let( :first ) { Opium::Model::Criteria.new( 'Object' ).update_constraint( :order, ['title', 1] ) }
|
89
89
|
let( :second ) { Opium::Model::Criteria.new( 'Object' ).update_constraint( :order, ['title', 1] ) }
|
90
|
-
|
90
|
+
|
91
91
|
it 'should not affect :equal?' do
|
92
92
|
first.should_not equal( second )
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
it 'is based on the criteria constraints' do
|
96
96
|
first.should == second
|
97
97
|
end
|
98
|
-
|
98
|
+
|
99
99
|
it 'is based on the criteria variables' do
|
100
100
|
third = first.update_variable( :cache, true )
|
101
101
|
second.should_not == third
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
describe '#criteria' do
|
106
106
|
subject { Opium::Model::Criteria.new( 'Object' ).update_constraint( :order, ['title', 1] ) }
|
107
|
-
|
107
|
+
|
108
108
|
it 'is == to self' do
|
109
109
|
subject.criteria.should == subject
|
110
110
|
end
|
111
|
-
|
111
|
+
|
112
112
|
it 'is not a duplicate of self' do
|
113
113
|
subject.criteria.should equal( subject )
|
114
114
|
end
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
describe '#model' do
|
118
118
|
subject { Opium::Model::Criteria.new( 'Game' ) }
|
119
|
-
|
119
|
+
|
120
120
|
it 'is the constantized version of :model_name' do
|
121
121
|
subject.model_name.should == 'Game'
|
122
122
|
subject.model.should == Game
|
123
123
|
end
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
126
|
describe '#empty?' do
|
127
127
|
before do
|
128
128
|
stub_request(:get, "https://api.parse.com/1/classes/Game?count=1&where=%7B%22price%22:%7B%22$gte%22:9000.0%7D%7D").
|
129
129
|
to_return(
|
130
|
-
status: 200,
|
130
|
+
status: 200,
|
131
131
|
body: {
|
132
132
|
count: 0,
|
133
133
|
results: []
|
134
|
-
}.to_json,
|
134
|
+
}.to_json,
|
135
135
|
headers: { content_type: 'application/json' }
|
136
136
|
)
|
137
137
|
end
|
138
|
-
|
138
|
+
|
139
139
|
subject { Game.criteria }
|
140
|
-
|
140
|
+
|
141
141
|
it { expect { subject.empty? }.to_not raise_exception }
|
142
142
|
it do
|
143
143
|
expect( subject ).to receive(:count).once.and_call_original
|
144
144
|
subject.empty?
|
145
145
|
end
|
146
|
-
|
146
|
+
|
147
147
|
it 'returns true if count is 0' do
|
148
148
|
subject.gte( price: 9000.0 ).empty?.should == true
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
it 'returns false if count is not 0' do
|
152
152
|
subject.criteria.empty? == false
|
153
153
|
end
|
154
154
|
end
|
155
|
-
|
155
|
+
|
156
156
|
describe '#constraints?' do
|
157
157
|
it 'returns true if count is not the only constraint' do
|
158
158
|
Game.limit( 10 ).constraints?.should == true
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
it 'returns false if count is the only constraint' do
|
162
162
|
Game.criteria.constraints?.should == false
|
163
163
|
end
|
164
164
|
end
|
165
|
-
|
165
|
+
|
166
166
|
describe '#each' do
|
167
167
|
subject { Game.criteria }
|
168
|
-
|
168
|
+
|
169
169
|
context 'without a block' do
|
170
170
|
it 'returns an Enumerator' do
|
171
171
|
subject.each.should be_a( Enumerator )
|
172
172
|
end
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
175
|
context 'with a block' do
|
176
176
|
it "calls its :model's :http_get" do
|
177
177
|
subject.model.should receive(:http_get).with(query: subject.constraints)
|
178
178
|
subject.each {|model| }
|
179
179
|
end
|
180
|
-
|
180
|
+
|
181
181
|
it 'yields to its block any results it finds' do
|
182
182
|
expect {|b| subject.each &b }.to yield_control.twice
|
183
183
|
end
|
184
|
-
|
184
|
+
|
185
185
|
it 'yields to its block Opium::Model objects (Game in context)' do
|
186
186
|
expect {|b| subject.each &b }.to yield_successive_args(Opium::Model, Opium::Model)
|
187
187
|
expect {|b| subject.each &b }.to yield_successive_args(Game, Game)
|
188
188
|
end
|
189
|
-
|
189
|
+
|
190
190
|
it "calls its :model's :http_get when counting" do
|
191
191
|
subject.model.should receive(:http_get).with(query: subject.constraints).twice
|
192
192
|
subject.each {|model| }
|
193
193
|
subject.each.count
|
194
194
|
end
|
195
195
|
end
|
196
|
-
|
196
|
+
|
197
197
|
context 'when #cached?' do
|
198
198
|
subject { Game.criteria.cache }
|
199
|
-
|
199
|
+
|
200
200
|
it 'calls its :model\'s :http_get only once' do
|
201
201
|
subject.model.should receive(:http_get).with(query: subject.constraints).once
|
202
202
|
subject.each {|model| }
|
203
203
|
subject.each {|model| }
|
204
204
|
end
|
205
|
-
|
205
|
+
|
206
206
|
it 'yields to its block any results it finds' do
|
207
207
|
expect {|b| subject.each &b }.to yield_control.twice
|
208
208
|
expect {|b| subject.each &b }.to yield_control.twice
|
209
209
|
end
|
210
|
-
|
210
|
+
|
211
211
|
it 'yields to its block Opium::Model objects (Game in context)' do
|
212
212
|
expect {|b| subject.each &b }.to yield_successive_args(Opium::Model, Opium::Model)
|
213
213
|
expect {|b| subject.each &b }.to yield_successive_args(Game, Game)
|
214
214
|
end
|
215
|
-
|
215
|
+
|
216
216
|
it "does not call its :model's :http_get when counting" do
|
217
217
|
subject.model.should receive(:http_get).with(query: subject.constraints).once
|
218
218
|
subject.each {|model| }
|
@@ -220,62 +220,76 @@ describe Opium::Model::Criteria do
|
|
220
220
|
end
|
221
221
|
end
|
222
222
|
end
|
223
|
-
|
223
|
+
|
224
224
|
describe '#uncache' do
|
225
225
|
subject { Game.criteria.cache }
|
226
|
-
|
226
|
+
|
227
227
|
it 'causes #each to call its :model\'s :http_get twice' do
|
228
228
|
subject.model.should receive(:http_get).with(query: subject.constraints).twice
|
229
229
|
subject.each {|model| }
|
230
230
|
subject.uncache.each {|model| }
|
231
231
|
end
|
232
|
-
|
232
|
+
|
233
233
|
it 'deletes its @cache' do
|
234
234
|
subject.each {|model| }
|
235
235
|
subject.uncache.instance_variable_get(:@cache).should be_nil
|
236
236
|
end
|
237
237
|
end
|
238
|
-
|
238
|
+
|
239
239
|
describe '#count' do
|
240
240
|
subject { Game.criteria }
|
241
|
-
|
241
|
+
|
242
242
|
it { expect { subject.count }.to_not raise_exception }
|
243
243
|
it do
|
244
244
|
expect( subject ).to receive(:each).and_call_original
|
245
245
|
subject.count
|
246
246
|
end
|
247
|
-
|
247
|
+
|
248
248
|
it 'equals the number of items from #each' do
|
249
249
|
expect( subject.count ).to be == 2
|
250
250
|
end
|
251
251
|
end
|
252
|
-
|
252
|
+
|
253
253
|
describe '#total_count' do
|
254
254
|
subject { Game.criteria }
|
255
|
-
|
255
|
+
|
256
256
|
it { expect { subject.total_count }.to_not raise_exception }
|
257
257
|
it do
|
258
258
|
expect( subject ).to receive(:each).and_call_original
|
259
259
|
subject.total_count
|
260
260
|
end
|
261
|
-
|
261
|
+
|
262
262
|
it "equals the 'count' result returned from parse" do
|
263
263
|
expect( subject.total_count ).to be == 10
|
264
264
|
end
|
265
265
|
end
|
266
|
-
|
266
|
+
|
267
|
+
describe '#size' do
|
268
|
+
subject { Game.criteria }
|
269
|
+
|
270
|
+
it { expect { subject.size }.to_not raise_exception }
|
271
|
+
it do
|
272
|
+
expect( subject ).to receive(:each).and_call_original
|
273
|
+
subject.size
|
274
|
+
end
|
275
|
+
|
276
|
+
it "equals the 'count' result returned from parse" do
|
277
|
+
expect( subject.size ).to be == 10
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
267
281
|
describe '#to_parse' do
|
268
282
|
subject { Game.criteria }
|
269
|
-
|
283
|
+
|
270
284
|
it { expect( subject.to_parse ).to be_a( Hash ) }
|
271
|
-
|
285
|
+
|
272
286
|
it 'has a "query" key, if a "where" constraint exists, containing a "where" and a "className"' do
|
273
287
|
Game.between( price: 5..10 ).to_parse.tap do |criteria|
|
274
288
|
criteria.should have_key( 'query' )
|
275
289
|
criteria['query'].should =~ { 'where' => { 'price' => { '$gte' => 5, '$lte' => 10 } }, 'className' => 'Game' }
|
276
290
|
end
|
277
291
|
end
|
278
|
-
|
292
|
+
|
279
293
|
it 'should have a "key" key, if a "keys" constraint exists' do
|
280
294
|
Game.keys( :price ).to_parse.tap do |criteria|
|
281
295
|
criteria.should have_key( 'key' )
|
@@ -283,14 +297,14 @@ describe Opium::Model::Criteria do
|
|
283
297
|
end
|
284
298
|
end
|
285
299
|
end
|
286
|
-
|
300
|
+
|
287
301
|
describe '#to_partial_path' do
|
288
302
|
subject { Game.criteria }
|
289
|
-
|
303
|
+
|
290
304
|
it { expect { subject.to_partial_path }.to_not raise_exception }
|
291
|
-
|
305
|
+
|
292
306
|
it 'comes from the model class' do
|
293
307
|
expect( subject.to_partial_path ).to eq 'games/game'
|
294
308
|
end
|
295
309
|
end
|
296
|
-
end
|
310
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Bowers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-01-
|
11
|
+
date: 2017-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|