itrigga-param_fu 0.2.0 → 0.3.0
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/VERSION +1 -1
- data/lib/trigga/param_fu/param_fu.rb +61 -15
- data/spec/param_fu_spec.rb +274 -11
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Trigga
|
2
2
|
module ParamFu
|
3
3
|
def self.included(base)
|
4
|
-
base.extend(
|
5
|
-
base.send(:include,
|
4
|
+
base.extend(AllMethods)
|
5
|
+
base.send(:include, AllMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
module
|
8
|
+
module AllMethods
|
9
9
|
def require_obj_or_id(opts, key)
|
10
10
|
obj_or_id(opts,key)
|
11
11
|
raise ArgumentError.new("#{key} or #{key_with_id(key)} are required") unless opts[key_with_id(key)]
|
@@ -47,24 +47,70 @@ module Trigga
|
|
47
47
|
condition
|
48
48
|
end
|
49
49
|
|
50
|
+
|
50
51
|
# fallback when we don't have ActiveSupport's pluralize method available
|
51
52
|
def to_plural(s)
|
52
53
|
(s.match(/[aeiou]$/i) ? s + 's' : s + 'es' )
|
53
54
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
|
56
|
+
# Give this a hash per model in the format:
|
57
|
+
# Model class => { param_name => { :operator=>(db operator - defaults to '='),
|
58
|
+
# => :field_name=>(field_name in the database - defaults to param_name)
|
59
|
+
# => }
|
60
|
+
# => }
|
61
|
+
# and it will return an ActiveRecord finder :conditions clause using any params which are present in the given :params
|
62
|
+
# e.g. if you have params = { :created_date_from=>'2011-10-09 00:01:02', :status=>'A', :click_url=>'items.html' }
|
63
|
+
# then calling:
|
64
|
+
#
|
65
|
+
# params_to_conditions( :params=>params, :models=>{
|
66
|
+
# Click => {:click_url=>{ :operator=>"like", :field_name=>'request_path' },
|
67
|
+
# :status => {},
|
68
|
+
# :http_referer=>{:operator=>'like'},
|
69
|
+
# :created_date_from => {:operator=> ">=", :field_name=>'timestamp'}
|
70
|
+
# }
|
71
|
+
# })
|
72
|
+
#
|
73
|
+
#
|
74
|
+
# will generate:
|
75
|
+
#
|
76
|
+
# [ 'clicks.request_path like (?) AND clicks.status = ? AND clicks.created_date_from >= ?', '%items.html%', 'A', '2011-10-09 00:01:02' ]
|
77
|
+
#
|
78
|
+
# It will ignore any criteria given which are NOT in the given :params hash
|
79
|
+
#
|
80
|
+
def params_to_conditions( opts={} )
|
81
|
+
require_param(opts, :params, :models)
|
82
|
+
|
83
|
+
conds = { :where=>[], :values=>[] }
|
84
|
+
|
85
|
+
puts "<br />opts = #{opts.inspect}<br />"
|
86
|
+
opts[:models].each { |model_class, field_defs|
|
87
|
+
puts "model_class = #{model_class.inspect}"
|
88
|
+
parsed_model_conditions = model_conditions( opts[:params], model_class, field_defs )
|
89
|
+
puts "parsed_model_conditions = #{parsed_model_conditions.inspect}"
|
90
|
+
conds[:where] += parsed_model_conditions[:where]
|
91
|
+
conds[:values] += parsed_model_conditions[:values]
|
92
|
+
}
|
93
|
+
|
94
|
+
[ conds[:where].join(" AND ") ] + conds[:values]
|
62
95
|
end
|
63
|
-
|
64
|
-
|
96
|
+
|
97
|
+
def model_conditions( opts, model_class, field_defs )
|
98
|
+
h = {:where=>[], :values=>[]}
|
99
|
+
field_defs.each{ |field_name, definition|
|
100
|
+
parsed_field_def = parse_field_definition( opts, model_class, field_name, definition )
|
101
|
+
h[:where] += parsed_field_def[:where]
|
102
|
+
h[:values] += parsed_field_def[:values]
|
103
|
+
}
|
104
|
+
h
|
65
105
|
end
|
66
|
-
|
67
|
-
|
106
|
+
|
107
|
+
def parse_field_definition( opts, model_class, param_name, definition )
|
108
|
+
c = {:where=>[], :values=>[]}
|
109
|
+
if opts[param_name]
|
110
|
+
c[:where] << "( #{model_class.table_name}.#{definition[:field_name] || param_name.to_s} #{definition[:operator] || '='} (?) )"
|
111
|
+
c[:values] << opts[param_name]
|
112
|
+
end
|
113
|
+
c
|
68
114
|
end
|
69
115
|
end
|
70
116
|
end
|
data/spec/param_fu_spec.rb
CHANGED
@@ -145,21 +145,284 @@ describe ::Trigga::ParamFu do
|
|
145
145
|
end
|
146
146
|
end
|
147
147
|
end
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
@
|
148
|
+
|
149
|
+
describe "parse_field_definition" do
|
150
|
+
before(:each) do
|
151
|
+
@params = { :param_1 => 'param_1 value' }
|
152
|
+
@model_class = mock("model class")
|
153
|
+
@model_class.stub!(:table_name).and_return( 'model_class_table_name' )
|
154
|
+
@param_name = :param_name
|
155
|
+
@definition = { :operator=>'=', :field_name=>'field_name'}
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should return a Hash" do
|
159
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition ).should be_a(Hash)
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "returned Hash" do
|
163
|
+
it "should have a key for :where" do
|
164
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].should_not be_nil
|
165
|
+
end
|
166
|
+
it "should have a key for :values" do
|
167
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should_not be_nil
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when the given opts has a key matching the given param_name" do
|
171
|
+
before(:each) do
|
172
|
+
@param_name = :param_1
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should add an element to the :where key" do
|
176
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].size.should == 1
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "where clause" do
|
180
|
+
it "should be wrapped in brackets" do
|
181
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].should =~ /^\s*\(.*\)\s*$/
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "inside the brackets" do
|
185
|
+
before(:each) do
|
186
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should start with the model_class's table name as a scope" do
|
190
|
+
@inside_the_brackets.should =~ /\s*model_class_table_name\..*/
|
191
|
+
end
|
192
|
+
|
193
|
+
context "When the definition has a :fieldname" do
|
194
|
+
before(:each) do
|
195
|
+
@definition[:field_name] = 'field_name'
|
196
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should use the :fieldname" do
|
200
|
+
@inside_the_brackets.should =~ /\s*[^\.]+\.field_name.*/
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "When the definition has no :fieldname" do
|
205
|
+
before(:each) do
|
206
|
+
@definition[:field_name] = nil
|
207
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should use the given param_name converted to a string as the field name" do
|
211
|
+
@inside_the_brackets.should =~ /\s*[^\.]+\.param_1.*/
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "When the definition has a :operator" do
|
216
|
+
before(:each) do
|
217
|
+
@definition[:operator] = 'my_operator'
|
218
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should use the :operator" do
|
222
|
+
@inside_the_brackets.should =~ /.*\bmy_operator\b.*/
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "When the definition has no :operator" do
|
227
|
+
before(:each) do
|
228
|
+
@definition[:operator] = nil
|
229
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should use = as the :operator" do
|
233
|
+
@inside_the_brackets.should =~ /[^=]+\s*=\s*[^=]+/
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should end with (?)" do
|
238
|
+
@inside_the_brackets.should =~ /\(\?\)\s*$/
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should add the corresponding value to the :values key" do
|
244
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should == ['param_1 value']
|
245
|
+
end
|
246
|
+
end
|
155
247
|
end
|
156
248
|
end
|
157
249
|
|
158
|
-
describe "
|
159
|
-
|
160
|
-
|
161
|
-
@
|
250
|
+
describe "model_conditions" do
|
251
|
+
before(:each) do
|
252
|
+
@params = { :param_1 => 'param_1 value' }
|
253
|
+
@model_class = mock("model class")
|
254
|
+
@mock_parsed_field_def_1 = {:where=>['where 1'], :values=>['values 1']}
|
255
|
+
@mock_parsed_field_def_2 = {:where=>['where 2'], :values=>['values 2']}
|
256
|
+
Tester.stub!(:parse_field_definition).and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
257
|
+
@definitions = { :key=>'=', :field_name=>'field_name'}
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should return a Hash" do
|
261
|
+
Tester.model_conditions( @params, @model_class, @definitions ).should be_a(Hash)
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "returned Hash" do
|
265
|
+
it "should have a key for :where" do
|
266
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:where].should_not be_nil
|
267
|
+
end
|
268
|
+
it "should have a key for :values" do
|
269
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:values].should_not be_nil
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context "for each given field_def" do
|
274
|
+
before(:each) do
|
275
|
+
@definitions = { :field_name_1 => (@mock_definition_1={}), :field_name_2 => (@mock_definition_2={}) }
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should call parse_field_definition" do
|
279
|
+
Tester.should_receive(:parse_field_definition).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
280
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "parse_field_definition call params" do
|
284
|
+
it "should pass the given opts" do
|
285
|
+
Tester.should_receive(:parse_field_definition).with( @params, anything, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
286
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should pass the given model class" do
|
290
|
+
Tester.should_receive(:parse_field_definition).with( anything, @model_class, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
291
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should pass each field_name" do
|
295
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
296
|
+
args[2].should == :field_name_1
|
297
|
+
@mock_parsed_field_def_1
|
298
|
+
end
|
299
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
300
|
+
args[2].should == :field_name_2
|
301
|
+
@mock_parsed_field_def_2
|
302
|
+
end
|
303
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should pass the field_name's definition" do
|
307
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
308
|
+
args[3].should == @mock_definition_1
|
309
|
+
@mock_parsed_field_def_1
|
310
|
+
end
|
311
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
312
|
+
args[3].should == @mock_definition_2
|
313
|
+
@mock_parsed_field_def_2
|
314
|
+
end
|
315
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should add the :where key from the parsed field definition to the :where key of the return hash " do
|
321
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:where].should == ['where 1', 'where 2']
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should add the :values key from the parsed field definition to the :values key of the return hash " do
|
325
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:values].should == ['values 1', 'values 2']
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
describe "params_to_conditions" do
|
332
|
+
before(:each) do
|
333
|
+
@mock_params = mock('params')
|
334
|
+
@model_class_1 = "model class 1"
|
335
|
+
@model_class_2 = "model class 2"
|
336
|
+
@models = { @model_class_1 => 'model class def 1', @model_class_2 => 'model class def 2' }
|
337
|
+
@mock_parsed_model_def_1 = {:where=>['where 1'], :values=>['values 1']}
|
338
|
+
@mock_parsed_model_def_2 = {:where=>['where 2'], :values=>['values 2']}
|
339
|
+
Tester.stub!(:model_conditions).and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
340
|
+
end
|
341
|
+
|
342
|
+
context "when not given a :params key" do
|
343
|
+
it "should raise an ArgumentError" do
|
344
|
+
lambda{ Tester.params_to_conditions(:blart=>'flange', :models=>'models') }.should raise_error(ArgumentError)
|
345
|
+
end
|
162
346
|
end
|
347
|
+
context "when not given a :models key" do
|
348
|
+
it "should raise an ArgumentError" do
|
349
|
+
lambda{ Tester.params_to_conditions(:blart=>'flange', :params=>'params') }.should raise_error(ArgumentError)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context "for each given model" do
|
354
|
+
before(:each) do
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should call model_conditions" do
|
359
|
+
Tester.should_receive(:model_conditions).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
360
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
361
|
+
end
|
362
|
+
|
363
|
+
describe "model_conditions_call_params" do
|
364
|
+
it "should pass on the given :params" do
|
365
|
+
Tester.should_receive(:model_conditions).with(@mock_params, anything, anything).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
366
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should pass each model class" do
|
370
|
+
Tester.should_receive(:model_conditions) do |args|
|
371
|
+
args[1].should == 'model class 1'
|
372
|
+
@mock_parsed_model_def_1
|
373
|
+
end
|
374
|
+
Tester.should_receive(:model_conditions) do |args|
|
375
|
+
args[1].should == 'model class 2'
|
376
|
+
@mock_parsed_model_def_2
|
377
|
+
end
|
378
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should pass the models field definitions" do
|
382
|
+
Tester.should_receive(:model_conditions) do |args|
|
383
|
+
args[2].should == 'model class def 1'
|
384
|
+
@mock_parsed_model_def_1
|
385
|
+
end
|
386
|
+
Tester.should_receive(:model_conditions) do |args|
|
387
|
+
args[2].should == 'model class def 2'
|
388
|
+
@mock_parsed_model_def_2
|
389
|
+
end
|
390
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
describe "returned value" do
|
396
|
+
it "should be an array" do
|
397
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models ).should be_a(Array)
|
398
|
+
end
|
399
|
+
|
400
|
+
describe "first element" do
|
401
|
+
it "should be a string" do
|
402
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should be_a(String)
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should have the :where keys from the parsed model definitions joined with AND " do
|
406
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should == "where 1 AND where 2"
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "subsequent elements" do
|
411
|
+
it "should be the values from the parsed model definitions" do
|
412
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[1].should == 'values 1'
|
413
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[2].should == 'values 2'
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
describe "instance_methods" do
|
422
|
+
it "should not raise an error" do
|
423
|
+
lambda {
|
424
|
+
@t.require_obj_or_id( {:key=>'val'}, :key )
|
425
|
+
}.should_not raise_error
|
163
426
|
end
|
164
427
|
end
|
165
428
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itrigga-param_fu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Al Davidson
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-11-
|
19
|
+
date: 2011-11-10 00:00:00 +00:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|