ardm-aggregates 1.2.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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +11 -0
- data/Gemfile +55 -0
- data/LICENSE +20 -0
- data/README.rdoc +45 -0
- data/Rakefile +4 -0
- data/VERSION +1 -0
- data/ardm-aggregates.gemspec +24 -0
- data/lib/ardm-aggregates.rb +1 -0
- data/lib/dm-aggregates.rb +60 -0
- data/lib/dm-aggregates/adapters/dm-do-adapter.rb +100 -0
- data/lib/dm-aggregates/aggregate_functions.rb +1 -0
- data/lib/dm-aggregates/collection.rb +13 -0
- data/lib/dm-aggregates/core_ext/symbol.rb +7 -0
- data/lib/dm-aggregates/functions.rb +232 -0
- data/lib/dm-aggregates/model.rb +13 -0
- data/lib/dm-aggregates/operators.rb +25 -0
- data/lib/dm-aggregates/query.rb +27 -0
- data/lib/dm-aggregates/repository.rb +13 -0
- data/lib/dm-aggregates/version.rb +5 -0
- data/spec/isolated/require_after_setup_spec.rb +21 -0
- data/spec/isolated/require_before_setup_spec.rb +21 -0
- data/spec/isolated/require_spec.rb +13 -0
- data/spec/public/collection_spec.rb +125 -0
- data/spec/public/model_spec.rb +11 -0
- data/spec/public/shared/aggregate_shared_spec.rb +322 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +57 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +123 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Aggregates
|
3
|
+
module Operators
|
4
|
+
def count
|
5
|
+
DataMapper::Query::Operator.new(self, :count)
|
6
|
+
end
|
7
|
+
|
8
|
+
def min
|
9
|
+
DataMapper::Query::Operator.new(self, :min)
|
10
|
+
end
|
11
|
+
|
12
|
+
def max
|
13
|
+
DataMapper::Query::Operator.new(self, :max)
|
14
|
+
end
|
15
|
+
|
16
|
+
def avg
|
17
|
+
DataMapper::Query::Operator.new(self, :avg)
|
18
|
+
end
|
19
|
+
|
20
|
+
def sum
|
21
|
+
DataMapper::Query::Operator.new(self, :sum)
|
22
|
+
end
|
23
|
+
end # module Operators
|
24
|
+
end # module Aggregates
|
25
|
+
end # module DataMapper
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Aggregates
|
3
|
+
module Query
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
6
|
+
# FIXME: figure out a cleaner approach than AMC
|
7
|
+
alias_method :assert_valid_fields_without_operator, :assert_valid_fields
|
8
|
+
alias_method :assert_valid_fields, :assert_valid_fields_with_operator
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_valid_fields_with_operator(fields, unique)
|
13
|
+
operators, fields = fields.partition { |f| f.kind_of?(DataMapper::Query::Operator) }
|
14
|
+
|
15
|
+
operators.each do |operator|
|
16
|
+
target = operator.target
|
17
|
+
|
18
|
+
unless target == :all || @properties.include?(target)
|
19
|
+
raise ArgumentError, "+options[:fields]+ entry #{target.inspect} does not map to a property in #{model}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_valid_fields_without_operator(fields, unique)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'isolated/require_spec'
|
3
|
+
require 'dm-core/spec/setup'
|
4
|
+
|
5
|
+
# To really test this behavior, this spec needs to be run in isolation and not
|
6
|
+
# as part of the typical rake spec run, which requires dm-aggregates upfront
|
7
|
+
|
8
|
+
if %w[ postgres mysql sqlite oracle sqlserver ].include?(ENV['ADAPTER'])
|
9
|
+
|
10
|
+
describe "require 'dm-aggregates after calling DataMapper.setup" do
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
@adapter = DataMapper::Spec.adapter
|
14
|
+
require 'dm-aggregates'
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_behave_like "require 'dm-aggregates'"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec'
|
2
|
+
require 'isolated/require_spec'
|
3
|
+
require 'dm-core/spec/setup'
|
4
|
+
|
5
|
+
# To really test this behavior, this spec needs to be run in isolation and not
|
6
|
+
# as part of the typical rake spec run, which requires dm-aggregates upfront
|
7
|
+
|
8
|
+
if %w[ postgres mysql sqlite oracle sqlserver ].include?(ENV['ADAPTER'])
|
9
|
+
|
10
|
+
describe "require 'dm-aggregates' before calling DataMapper.setup" do
|
11
|
+
|
12
|
+
before(:all) do
|
13
|
+
require 'dm-aggregates'
|
14
|
+
@adapter = DataMapper::Spec.adapter
|
15
|
+
end
|
16
|
+
|
17
|
+
it_should_behave_like "require 'dm-aggregates'"
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
shared_examples_for "require 'dm-aggregates'" do
|
2
|
+
|
3
|
+
%w[ Repository Model Collection Query ].each do |name|
|
4
|
+
it "should include the aggregate api in DataMapper::#{name}" do
|
5
|
+
(DataMapper.const_get(name) < DataMapper::Aggregates.const_get(name)).should be(true)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should include the aggregate api into the adapter" do
|
10
|
+
@adapter.respond_to?(:aggregate).should be(true)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMapper::Collection do
|
4
|
+
supported_by :sqlite, :mysql, :postgres do
|
5
|
+
let(:dragons) { Dragon.all }
|
6
|
+
let(:countries) { Country.all }
|
7
|
+
|
8
|
+
it_should_behave_like 'It Has Setup Resources'
|
9
|
+
it_should_behave_like 'An Aggregatable Class'
|
10
|
+
|
11
|
+
describe 'ignore invalid query' do
|
12
|
+
let(:dragons) { Dragon.all.all(:id => []) }
|
13
|
+
|
14
|
+
[ :size, :count ].each do |method|
|
15
|
+
describe "##{method}" do
|
16
|
+
subject { dragons.send(method) }
|
17
|
+
|
18
|
+
it { should == 0 }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#min' do
|
23
|
+
subject { dragons.min(:id) }
|
24
|
+
|
25
|
+
it { should be_nil }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#max' do
|
29
|
+
subject { dragons.max(:id) }
|
30
|
+
|
31
|
+
it { should be_nil }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#avg' do
|
35
|
+
subject { dragons.avg(:id) }
|
36
|
+
|
37
|
+
it { should be_nil }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#sum' do
|
41
|
+
subject { dragons.sum(:id) }
|
42
|
+
|
43
|
+
it { should be_nil }
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#aggregate' do
|
47
|
+
subject { dragons.aggregate(:id) }
|
48
|
+
|
49
|
+
it { should == [] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with collections created with Set operations' do
|
54
|
+
let(:collection) { dragons.all(:name => 'George') | dragons.all(:name => 'Puff') }
|
55
|
+
|
56
|
+
describe '#size' do
|
57
|
+
subject { collection.size }
|
58
|
+
|
59
|
+
it { should == 2 }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#count' do
|
63
|
+
subject { collection.count }
|
64
|
+
|
65
|
+
it { should == 2 }
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#min' do
|
69
|
+
subject { collection.min(:toes_on_claw) }
|
70
|
+
|
71
|
+
it { should == 3 }
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#max' do
|
75
|
+
subject { collection.max(:toes_on_claw) }
|
76
|
+
|
77
|
+
it { should == 4 }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#avg' do
|
81
|
+
subject { collection.avg(:toes_on_claw) }
|
82
|
+
|
83
|
+
it { should == 3.5 }
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#sum' do
|
87
|
+
subject { collection.sum(:toes_on_claw) }
|
88
|
+
|
89
|
+
it { should == 7 }
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#aggregate' do
|
93
|
+
subject { collection.aggregate(:all.count, :name.count, :toes_on_claw.min, :toes_on_claw.max, :toes_on_claw.avg, :toes_on_claw.sum)}
|
94
|
+
|
95
|
+
it { should == [ 2, 2, 3, 4, 3.5, 7 ] }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'with a collection limited to 1 result' do
|
100
|
+
let(:dragons) { Dragon.all(:limit => 1) }
|
101
|
+
|
102
|
+
describe '#size' do
|
103
|
+
subject { dragons.size }
|
104
|
+
|
105
|
+
it { should == 1 }
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#count' do
|
109
|
+
subject { dragons.count }
|
110
|
+
|
111
|
+
it { pending('TODO: make count apply to the limited collection. Currently limit applies after the count') { should == 1 } }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'with the order reversed by the grouping field' do
|
116
|
+
subject { dragons.aggregate(:birth_at, :all.count) }
|
117
|
+
|
118
|
+
let(:dragons) { Dragon.all(:order => [ :birth_at.desc ]) }
|
119
|
+
|
120
|
+
it 'displays the results in reverse order' do
|
121
|
+
should == Dragon.aggregate(:birth_at, :all.count).reverse
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMapper::Model do
|
4
|
+
supported_by :sqlite, :mysql, :postgres do
|
5
|
+
let(:dragons) { Dragon }
|
6
|
+
let(:countries) { Country }
|
7
|
+
|
8
|
+
it_should_behave_like 'It Has Setup Resources'
|
9
|
+
it_should_behave_like 'An Aggregatable Class'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,322 @@
|
|
1
|
+
shared_examples_for 'It Has Setup Resources' do
|
2
|
+
before :all do
|
3
|
+
@mysql = defined?(DataMapper::Adapters::MysqlAdapter) && @adapter.kind_of?(DataMapper::Adapters::MysqlAdapter)
|
4
|
+
@postgres = defined?(DataMapper::Adapters::PostgresAdapter) && @adapter.kind_of?(DataMapper::Adapters::PostgresAdapter)
|
5
|
+
|
6
|
+
@skip = (@mysql || @postgres) && ENV['TZ'].to_s.downcase != 'utc'
|
7
|
+
end
|
8
|
+
|
9
|
+
before :all do
|
10
|
+
DataMapper.auto_migrate!
|
11
|
+
|
12
|
+
@birth_at = DateTime.now
|
13
|
+
@birth_on = Date.parse(@birth_at.to_s)
|
14
|
+
@birth_time = Time.parse(@birth_at.to_s)
|
15
|
+
|
16
|
+
@chuck = Knight.create(:name => 'Chuck')
|
17
|
+
@larry = Knight.create(:name => 'Larry')
|
18
|
+
|
19
|
+
Dragon.create(:name => 'George', :is_fire_breathing => false, :toes_on_claw => 3, :birth_at => @birth_at, :birth_on => @birth_on, :birth_time => @birth_time, :knight => @chuck)
|
20
|
+
Dragon.create(:name => 'Puff', :is_fire_breathing => true, :toes_on_claw => 4, :birth_at => @birth_at, :birth_on => @birth_on, :birth_time => @birth_time, :knight => @larry)
|
21
|
+
Dragon.create(:name => nil, :is_fire_breathing => true, :toes_on_claw => 5, :birth_at => nil, :birth_on => nil, :birth_time => nil)
|
22
|
+
|
23
|
+
gold_kilo_price = 277738.70
|
24
|
+
@gold_tonne_price = gold_kilo_price * 10000
|
25
|
+
|
26
|
+
Country.create(
|
27
|
+
:name => 'China',
|
28
|
+
:population => 1330044605,
|
29
|
+
:birth_rate => 13.71,
|
30
|
+
:gold_reserve_tonnes => 600.0,
|
31
|
+
:gold_reserve_value => 600.0 * @gold_tonne_price # => 32150000
|
32
|
+
)
|
33
|
+
|
34
|
+
Country.create(
|
35
|
+
:name => 'United States',
|
36
|
+
:population => 303824646,
|
37
|
+
:birth_rate => 14.18,
|
38
|
+
:gold_reserve_tonnes => 8133.5,
|
39
|
+
:gold_reserve_value => 8133.5 * @gold_tonne_price
|
40
|
+
)
|
41
|
+
|
42
|
+
Country.create(
|
43
|
+
:name => 'Brazil',
|
44
|
+
:population => 191908598,
|
45
|
+
:birth_rate => 16.04,
|
46
|
+
:gold_reserve_tonnes => nil # example of no stats available
|
47
|
+
)
|
48
|
+
|
49
|
+
Country.create(
|
50
|
+
:name => 'Russia',
|
51
|
+
:population => 140702094,
|
52
|
+
:birth_rate => 11.03,
|
53
|
+
:gold_reserve_tonnes => 438.2,
|
54
|
+
:gold_reserve_value => 438.2 * @gold_tonne_price
|
55
|
+
)
|
56
|
+
|
57
|
+
Country.create(
|
58
|
+
:name => 'Japan',
|
59
|
+
:population => 127288419,
|
60
|
+
:birth_rate => 7.87,
|
61
|
+
:gold_reserve_tonnes => 765.2,
|
62
|
+
:gold_reserve_value => 765.2 * @gold_tonne_price
|
63
|
+
)
|
64
|
+
|
65
|
+
Country.create(
|
66
|
+
:name => 'Mexico',
|
67
|
+
:population => 109955400,
|
68
|
+
:birth_rate => 20.04,
|
69
|
+
:gold_reserve_tonnes => nil # example of no stats available
|
70
|
+
)
|
71
|
+
|
72
|
+
Country.create(
|
73
|
+
:name => 'Germany',
|
74
|
+
:population => 82369548,
|
75
|
+
:birth_rate => 8.18,
|
76
|
+
:gold_reserve_tonnes => 3417.4,
|
77
|
+
:gold_reserve_value => 3417.4 * @gold_tonne_price
|
78
|
+
)
|
79
|
+
|
80
|
+
@approx_by = 0.0001
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
shared_examples_for 'An Aggregatable Class' do
|
85
|
+
describe '#size' do
|
86
|
+
it_should_behave_like 'count with no arguments'
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#count' do
|
90
|
+
it_should_behave_like 'count with no arguments'
|
91
|
+
|
92
|
+
context 'with a property name' do
|
93
|
+
it 'counts the results' do
|
94
|
+
dragons.count(:name).should == 2
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'counts the results with conditions having operators' do
|
98
|
+
dragons.count(:name, :toes_on_claw.gt => 3).should == 1
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'counts the results with raw conditions' do
|
102
|
+
statement = 'is_fire_breathing = ?'
|
103
|
+
dragons.count(:name, :conditions => [ statement, false ]).should == 1
|
104
|
+
dragons.count(:name, :conditions => [ statement, true ]).should == 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#min' do
|
110
|
+
context 'with no arguments' do
|
111
|
+
it 'raises an error' do
|
112
|
+
expect { dragons.min }.to raise_error(ArgumentError)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'with a property name' do
|
117
|
+
it 'provides the lowest value of an Integer property' do
|
118
|
+
dragons.min(:toes_on_claw).should == 3
|
119
|
+
countries.min(:population).should == 82369548
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'provides the lowest value of a Float property' do
|
123
|
+
countries.min(:birth_rate).should be_kind_of(Float)
|
124
|
+
countries.min(:birth_rate).should >= 7.87 - @approx_by # approx match
|
125
|
+
countries.min(:birth_rate).should <= 7.87 + @approx_by # approx match
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'provides the lowest value of a BigDecimal property' do
|
129
|
+
countries.min(:gold_reserve_value).should be_kind_of(BigDecimal)
|
130
|
+
countries.min(:gold_reserve_value).should == BigDecimal('1217050983400.0')
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'provides the lowest value of a DateTime property' do
|
134
|
+
pending_if 'TODO: returns incorrect value until DO handles TZs properly', @skip do
|
135
|
+
dragons.min(:birth_at).should be_kind_of(DateTime)
|
136
|
+
dragons.min(:birth_at).to_s.should == @birth_at.to_s
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'provides the lowest value of a Date property' do
|
141
|
+
dragons.min(:birth_on).should be_kind_of(Date)
|
142
|
+
dragons.min(:birth_on).should == @birth_on
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'provides the lowest value of a Time property' do
|
146
|
+
dragons.min(:birth_time).should be_kind_of(Time)
|
147
|
+
dragons.min(:birth_time).to_s.should == @birth_time.to_s
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'provides the lowest value when conditions provided' do
|
151
|
+
dragons.min(:toes_on_claw, :is_fire_breathing => true).should == 4
|
152
|
+
dragons.min(:toes_on_claw, :is_fire_breathing => false).should == 3
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#max' do
|
158
|
+
context 'with no arguments' do
|
159
|
+
it 'raises an error' do
|
160
|
+
expect { dragons.max }.to raise_error(ArgumentError)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'with a property name' do
|
165
|
+
it 'provides the highest value of an Integer property' do
|
166
|
+
dragons.max(:toes_on_claw).should == 5
|
167
|
+
countries.max(:population).should == 1330044605
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'provides the highest value of a Float property' do
|
171
|
+
countries.max(:birth_rate).should be_kind_of(Float)
|
172
|
+
countries.max(:birth_rate).should >= 20.04 - @approx_by # approx match
|
173
|
+
countries.max(:birth_rate).should <= 20.04 + @approx_by # approx match
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'provides the highest value of a BigDecimal property' do
|
177
|
+
countries.max(:gold_reserve_value).should == BigDecimal('22589877164500.0')
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'provides the highest value of a DateTime property' do
|
181
|
+
pending_if 'TODO: returns incorrect value until DO handles TZs properly', @skip do
|
182
|
+
dragons.min(:birth_at).should be_kind_of(DateTime)
|
183
|
+
dragons.min(:birth_at).to_s.should == @birth_at.to_s
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'provides the highest value of a Date property' do
|
188
|
+
dragons.min(:birth_on).should be_kind_of(Date)
|
189
|
+
dragons.min(:birth_on).should == @birth_on
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'provides the highest value of a Time property' do
|
193
|
+
dragons.min(:birth_time).should be_kind_of(Time)
|
194
|
+
dragons.min(:birth_time).to_s.should == @birth_time.to_s
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'provides the highest value when conditions provided' do
|
198
|
+
dragons.max(:toes_on_claw, :is_fire_breathing => true).should == 5
|
199
|
+
dragons.max(:toes_on_claw, :is_fire_breathing => false).should == 3
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#avg' do
|
205
|
+
context 'with no arguments' do
|
206
|
+
it 'raises an error' do
|
207
|
+
expect { dragons.avg }.to raise_error(ArgumentError)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'with a property name' do
|
212
|
+
it 'provides the average value of an Integer property' do
|
213
|
+
dragons.avg(:toes_on_claw).should be_kind_of(Float)
|
214
|
+
dragons.avg(:toes_on_claw).should == 4.0
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'provides the average value of a Float property' do
|
218
|
+
mean_birth_rate = (13.71 + 14.18 + 16.04 + 11.03 + 7.87 + 20.04 + 8.18) / 7
|
219
|
+
countries.avg(:birth_rate).should be_kind_of(Float)
|
220
|
+
countries.avg(:birth_rate).should >= mean_birth_rate - @approx_by # approx match
|
221
|
+
countries.avg(:birth_rate).should <= mean_birth_rate + @approx_by # approx match
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'provides the average value of a BigDecimal property' do
|
225
|
+
mean_gold_reserve_value = ((600.0 + 8133.50 + 438.20 + 765.20 + 3417.40) * @gold_tonne_price) / 5
|
226
|
+
countries.avg(:gold_reserve_value).should be_kind_of(BigDecimal)
|
227
|
+
countries.avg(:gold_reserve_value).should == BigDecimal(mean_gold_reserve_value.to_s)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'provides the average value when conditions provided' do
|
231
|
+
dragons.avg(:toes_on_claw, :is_fire_breathing => true).should == 4.5
|
232
|
+
dragons.avg(:toes_on_claw, :is_fire_breathing => false).should == 3
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe '#sum' do
|
238
|
+
context 'with no arguments' do
|
239
|
+
it 'raises an error' do
|
240
|
+
expect { dragons.sum }.to raise_error(ArgumentError)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'with a property name' do
|
245
|
+
it 'provides the sum of values for an Integer property' do
|
246
|
+
dragons.sum(:toes_on_claw).should == 12
|
247
|
+
|
248
|
+
total_population = 1330044605 + 303824646 + 191908598 + 140702094 +
|
249
|
+
127288419 + 109955400 + 82369548
|
250
|
+
countries.sum(:population).should == total_population
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'provides the sum of values for a Float property' do
|
254
|
+
total_tonnes = 600.0 + 8133.5 + 438.2 + 765.2 + 3417.4
|
255
|
+
countries.sum(:gold_reserve_tonnes).should be_kind_of(Float)
|
256
|
+
countries.sum(:gold_reserve_tonnes).should >= total_tonnes - @approx_by # approx match
|
257
|
+
countries.sum(:gold_reserve_tonnes).should <= total_tonnes + @approx_by # approx match
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'provides the sum of values for a BigDecimal property' do
|
261
|
+
countries.sum(:gold_reserve_value).should == BigDecimal('37090059214100.0')
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'provides the average value when conditions provided' do
|
265
|
+
dragons.sum(:toes_on_claw, :is_fire_breathing => true).should == 9
|
266
|
+
dragons.sum(:toes_on_claw, :is_fire_breathing => false).should == 3
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe '#aggregate' do
|
272
|
+
context 'with no arguments' do
|
273
|
+
it 'raises an error' do
|
274
|
+
expect { dragons.aggregate }.to raise_error(ArgumentError)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'with only aggregate fields specified' do
|
279
|
+
it 'provides aggregate results' do
|
280
|
+
results = dragons.aggregate(:all.count, :name.count, :toes_on_claw.min, :toes_on_claw.max, :toes_on_claw.avg, :toes_on_claw.sum)
|
281
|
+
results.should == [ 3, 2, 3, 5, 4.0, 12 ]
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context 'with aggregate fields and a property to group by' do
|
286
|
+
it 'provides aggregate results' do
|
287
|
+
results = dragons.aggregate(:all.count, :name.count, :toes_on_claw.min, :toes_on_claw.max, :toes_on_claw.avg, :toes_on_claw.sum, :is_fire_breathing)
|
288
|
+
results.should == [ [ 1, 1, 3, 3, 3.0, 3, false ], [ 2, 1, 4, 5, 4.5, 9, true ] ]
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
describe 'query path issue' do
|
294
|
+
it 'does not break when a query path is specified' do
|
295
|
+
dragon = dragons.first(Dragon.knight.name => 'Chuck')
|
296
|
+
dragon.name.should == 'George'
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
shared_examples_for 'count with no arguments' do
|
302
|
+
it 'counts the results' do
|
303
|
+
dragons.count.should == 3
|
304
|
+
|
305
|
+
countries.count.should == 7
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'counts the results with conditions having operators' do
|
309
|
+
dragons.count(:toes_on_claw.gt => 3).should == 2
|
310
|
+
|
311
|
+
countries.count(:birth_rate.lt => 12).should == 3
|
312
|
+
countries.count(:population.gt => 1000000000).should == 1
|
313
|
+
countries.count(:population.gt => 2000000000).should == 0
|
314
|
+
countries.count(:population.lt => 10).should == 0
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'counts the results with raw conditions' do
|
318
|
+
dragon_statement = 'is_fire_breathing = ?'
|
319
|
+
dragons.count(:conditions => [ dragon_statement, false ]).should == 1
|
320
|
+
dragons.count(:conditions => [ dragon_statement, true ]).should == 2
|
321
|
+
end
|
322
|
+
end
|