birddog 0.0.4 → 0.0.5
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/Gemfile +2 -2
- data/birddog.gemspec +1 -0
- data/lib/birddog/birddog.rb +127 -5
- data/lib/birddog/version.rb +1 -1
- data/specs/common_aggregates_spec.rb +76 -0
- data/specs/complex_scope_spec.rb +0 -1
- data/specs/spec_helper.rb +4 -0
- metadata +30 -18
data/Gemfile
CHANGED
data/birddog.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_development_dependency "minitest"
|
23
23
|
s.add_development_dependency "rake"
|
24
24
|
s.add_development_dependency "sqlite3-ruby"
|
25
|
+
s.add_development_dependency "pry"
|
25
26
|
|
26
27
|
s.add_runtime_dependency "chronic"
|
27
28
|
s.add_runtime_dependency "activerecord"
|
data/lib/birddog/birddog.rb
CHANGED
@@ -8,12 +8,17 @@ module Birddog
|
|
8
8
|
include ::Birddog::FieldConditions
|
9
9
|
|
10
10
|
AREL_KEYS = [:select, :limit, :joins, :includes, :group, :from, :where, :having]
|
11
|
-
|
12
11
|
attr_reader :fields
|
13
12
|
|
14
13
|
def initialize(model)
|
15
14
|
@model = model
|
16
15
|
@fields = {}
|
16
|
+
@averagable = []
|
17
|
+
@minimumable = []
|
18
|
+
@maximumable = []
|
19
|
+
@sumable = []
|
20
|
+
|
21
|
+
define_common_aggregates_for(model)
|
17
22
|
end
|
18
23
|
|
19
24
|
def field(name, options={}, &mapping)
|
@@ -42,6 +47,30 @@ module Birddog
|
|
42
47
|
aggregate?(name) ? define_aggregate_field(name, @fields[name]) : define_field(name, @fields[name])
|
43
48
|
end
|
44
49
|
|
50
|
+
def averagable(*fields)
|
51
|
+
fields.flatten.each do |avg_field|
|
52
|
+
@averagable << avg_field
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def minimumable(*fields)
|
57
|
+
fields.flatten.each do |min_field|
|
58
|
+
@minimumable << min_field
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def maximumable(*fields)
|
63
|
+
fields.flatten.each do |max_field|
|
64
|
+
@maximumable << max_field
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def sumable(*fields)
|
69
|
+
fields.flatten.each do |sum_field|
|
70
|
+
@sumable << sum_field
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
45
74
|
def keyword(name, &block)
|
46
75
|
define_scope(name, &block)
|
47
76
|
end
|
@@ -95,12 +124,16 @@ module Birddog
|
|
95
124
|
end
|
96
125
|
private :scope_name_for
|
97
126
|
|
127
|
+
def define_static_scope(name, &scope)
|
128
|
+
@model.__send__(:scope, name, scope)
|
129
|
+
end
|
130
|
+
private :define_static_scope
|
131
|
+
|
98
132
|
def define_scope(name, &scope)
|
99
|
-
@model.
|
133
|
+
@model.__send__(:scope, scope_name_for(name), scope)
|
100
134
|
end
|
101
135
|
private :define_scope
|
102
136
|
|
103
|
-
|
104
137
|
def callable_or_cast(field, condition, value)
|
105
138
|
if field[:cast] && field[:cast].respond_to?(:call)
|
106
139
|
field[:cast].call(value.gsub(condition, ""))
|
@@ -162,17 +195,106 @@ module Birddog
|
|
162
195
|
end
|
163
196
|
private :tokenize
|
164
197
|
|
198
|
+
def define_common_aggregates_for(model)
|
199
|
+
_common_average_for(model)
|
200
|
+
_common_sum_for(model)
|
201
|
+
_common_minimum_for(model)
|
202
|
+
_common_maximum_for(model)
|
203
|
+
end
|
204
|
+
private :define_common_aggregates_for
|
205
|
+
|
206
|
+
def _common_average_for(model)
|
207
|
+
define_static_scope(:_birddog_average) do |field, value|
|
208
|
+
field_name = "average_#{field}"
|
209
|
+
scope = { :select => @model.arel_table[field].average.as(field_name) }
|
210
|
+
warn_common_aggregate_conditional if conditional?(value)
|
211
|
+
scope
|
212
|
+
end
|
213
|
+
end
|
214
|
+
private :_common_average_for
|
215
|
+
|
216
|
+
def _common_sum_for(model)
|
217
|
+
define_static_scope(:_birddog_sum) do |field, value|
|
218
|
+
field_name = "sum_#{field}"
|
219
|
+
scope = { :select => @model.arel_table[field].sum.as(field_name) }
|
220
|
+
warn_common_aggregate_conditional if conditional?(value)
|
221
|
+
scope
|
222
|
+
end
|
223
|
+
end
|
224
|
+
private :_common_sum_for
|
225
|
+
|
226
|
+
def _common_minimum_for(model)
|
227
|
+
define_static_scope(:_birddog_minimum) do |field, value|
|
228
|
+
field_name = "minimum_#{field}"
|
229
|
+
scope = { :select => @model.arel_table[field].minimum.as(field_name) }
|
230
|
+
warn_common_aggregate_conditional if conditional?(value)
|
231
|
+
scope
|
232
|
+
end
|
233
|
+
end
|
234
|
+
private :_common_minimum_for
|
235
|
+
|
236
|
+
def _common_maximum_for(model)
|
237
|
+
define_static_scope(:_birddog_maximum) do |field, value|
|
238
|
+
field_name = "maximum_#{field}"
|
239
|
+
scope = { :select => @model.arel_table[field].maximum.as(field_name) }
|
240
|
+
warn_common_aggregate_conditional if conditional?(value)
|
241
|
+
scope
|
242
|
+
end
|
243
|
+
end
|
244
|
+
private :_common_maximum_for
|
245
|
+
|
246
|
+
def aggregate_scope_for(model, key, value)
|
247
|
+
aggregate_scope = nil
|
248
|
+
field_name = nil
|
249
|
+
key = key.to_s
|
250
|
+
|
251
|
+
case
|
252
|
+
when key =~ /^(average_)([a-zA-Z_]*)/ && @averagable.include?($2.to_sym) then
|
253
|
+
aggregate_scope = "_birddog_average"
|
254
|
+
field_name = $2
|
255
|
+
when key =~ /^(sum_)([a-zA-Z_]*)/ && @sumable.include?($2.to_sym) then
|
256
|
+
aggregate_scope = "_birddog_sum"
|
257
|
+
field_name = $2
|
258
|
+
when key =~ /^(minimum_)([a-zA-Z_]*)/ && @minimumable.include?($2.to_sym) then
|
259
|
+
aggregate_scope = "_birddog_minimum"
|
260
|
+
field_name = $2
|
261
|
+
when key =~ /^(maximum_)([a-zA-Z_]*)/ && @maximumable.include?($2.to_sym) then
|
262
|
+
aggregate_scope = "_birddog_maximum"
|
263
|
+
field_name = $2
|
264
|
+
end
|
265
|
+
|
266
|
+
[aggregate_scope, field_name]
|
267
|
+
end
|
268
|
+
private :aggregate_scope_for
|
269
|
+
|
165
270
|
def scope_for(model, key, value)
|
166
|
-
scope_name =
|
271
|
+
scope_name, field = aggregate_scope_for(model, key, value)
|
272
|
+
scope_name = scope_name_for(key) unless scope_name
|
167
273
|
|
168
274
|
if model.respond_to?(scope_name)
|
169
|
-
|
275
|
+
send_params = [field, value].compact
|
276
|
+
model.__send__(scope_name, *send_params)
|
170
277
|
else
|
171
278
|
model.scoped
|
172
279
|
end
|
173
280
|
end
|
174
281
|
private :scope_for
|
175
282
|
|
283
|
+
def warn_common_aggregate_conditional
|
284
|
+
raise "WARNING"
|
285
|
+
rescue => e
|
286
|
+
warn <<-WARNING
|
287
|
+
===================================================================
|
288
|
+
Birddog currently does not process conditionals on common aggregates
|
289
|
+
your program may not behave as expected.
|
290
|
+
|
291
|
+
Called at:
|
292
|
+
|
293
|
+
#{e.backtrace.join("#{$/} ")}
|
294
|
+
===================================================================
|
295
|
+
WARNING
|
296
|
+
end
|
297
|
+
|
176
298
|
end
|
177
299
|
|
178
300
|
end
|
data/lib/birddog/version.rb
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Birddog::Birddog do
|
4
|
+
before :each do
|
5
|
+
User.destroy_all
|
6
|
+
Product.destroy_all
|
7
|
+
@john = User.create(:first_name => "John", :last_name => "Doe")
|
8
|
+
@ducky = @john.products.create(:name => "Rubber Duck", :value => 10)
|
9
|
+
@tv = @john.products.create(:name => "TV", :value => 200)
|
10
|
+
@bike = @john.products.create(:name => "Bike", :value => 100)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "averagable" do
|
14
|
+
it "implements the common average scope" do
|
15
|
+
Product.must_respond_to(:_birddog_average)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "creates a query on the column desired when scope is average_*" do
|
19
|
+
sql = Product.scopes_for_query("average_value").to_sql
|
20
|
+
sql.must_match(/value/)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "calculates the average and returns it in the result set" do
|
24
|
+
avg = Product.scopes_for_query("average_value").first
|
25
|
+
avg.average_value.must_equal((100 + 200 + 10) / 3.0)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "minimumable" do
|
30
|
+
it "implements the common minimum scope" do
|
31
|
+
Product.must_respond_to(:_birddog_minimum)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "creates a query on the column desired when scope is minimum_*" do
|
35
|
+
sql = Product.scopes_for_query("minimum_value").to_sql
|
36
|
+
sql.must_match(/minimum/)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "calculates the minimum and returns it in the result set" do
|
40
|
+
avg = Product.scopes_for_query("minimum_value").first
|
41
|
+
avg.minimum_value.must_equal(10)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "maximumable" do
|
46
|
+
it "implements the common maximum scope" do
|
47
|
+
Product.must_respond_to(:_birddog_maximum)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "creates a query on the column desired when scope is maximum_*" do
|
51
|
+
sql = Product.scopes_for_query("maximum_value").to_sql
|
52
|
+
sql.must_match(/maximum/)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "calculates the maximum and returns it in the result set" do
|
56
|
+
avg = Product.scopes_for_query("maximum_value").first
|
57
|
+
avg.maximum_value.must_equal(200)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "sumable" do
|
62
|
+
it "implements the common sum scope" do
|
63
|
+
Product.must_respond_to(:_birddog_sum)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "creates a query on the column desired when scope is sum_*" do
|
67
|
+
sql = Product.scopes_for_query("sum_value").to_sql
|
68
|
+
sql.must_match(/sum/)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "calculates the sum and returns it in the result set" do
|
72
|
+
avg = Product.scopes_for_query("sum_value").first
|
73
|
+
avg.sum_value.must_equal(310)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/specs/complex_scope_spec.rb
CHANGED
data/specs/spec_helper.rb
CHANGED
@@ -62,6 +62,10 @@ class Product < ActiveRecord::Base
|
|
62
62
|
belongs_to :user
|
63
63
|
|
64
64
|
birddog do |search|
|
65
|
+
search.averagable :value
|
66
|
+
search.minimumable :value
|
67
|
+
search.maximumable :value
|
68
|
+
search.sumable :value
|
65
69
|
search.text_search "products.name", "products.value"
|
66
70
|
|
67
71
|
search.field :name, :regex => true, :wildcard => true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: birddog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-29 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
16
|
-
requirement: &
|
16
|
+
requirement: &12855260 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12855260
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &12854640 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12854640
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sqlite3-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &12854040 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,21 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *12854040
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: pry
|
49
|
+
requirement: &12853440 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *12853440
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: chronic
|
49
|
-
requirement: &
|
60
|
+
requirement: &12852700 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :runtime
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *12852700
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: activerecord
|
60
|
-
requirement: &
|
71
|
+
requirement: &12852260 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :runtime
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *12852260
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: activesupport
|
71
|
-
requirement: &
|
82
|
+
requirement: &12851700 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :runtime
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *12851700
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: squeel
|
82
|
-
requirement: &
|
93
|
+
requirement: &12850900 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :runtime
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *12850900
|
91
102
|
description: Seeeeeeeee Readme
|
92
103
|
email:
|
93
104
|
- brandonsdewitt@gmail.com
|
@@ -109,6 +120,7 @@ files:
|
|
109
120
|
- lib/birddog/searchable.rb
|
110
121
|
- lib/birddog/version.rb
|
111
122
|
- specs/birddog_spec.rb
|
123
|
+
- specs/common_aggregates_spec.rb
|
112
124
|
- specs/complex_scope_spec.rb
|
113
125
|
- specs/field_conditions_spec.rb
|
114
126
|
- specs/spec_helper.rb
|
@@ -127,7 +139,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
139
|
version: '0'
|
128
140
|
segments:
|
129
141
|
- 0
|
130
|
-
hash: -
|
142
|
+
hash: -1855020977643402553
|
131
143
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
144
|
none: false
|
133
145
|
requirements:
|
@@ -136,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
148
|
version: '0'
|
137
149
|
segments:
|
138
150
|
- 0
|
139
|
-
hash: -
|
151
|
+
hash: -1855020977643402553
|
140
152
|
requirements: []
|
141
153
|
rubyforge_project: birddog
|
142
154
|
rubygems_version: 1.8.10
|