sbf-dm-aggregates 1.3.0.beta

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.
@@ -0,0 +1,325 @@
1
+ shared_examples 'It Has Setup Resources' do
2
+ before :all do
3
+ @mysql = defined?(DataMapper::Adapters::MysqlAdapter) && @adapter.is_a?(DataMapper::Adapters::MysqlAdapter)
4
+ @postgres = defined?(DataMapper::Adapters::PostgresAdapter) && @adapter.is_a?(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',
20
+ is_fire_breathing: false, toes_on_claw: 3, birth_at: @birth_at, birth_on: @birth_on, birth_time: @birth_time, knight: @chuck)
21
+ Dragon.create(name: 'Puff',
22
+ is_fire_breathing: true, toes_on_claw: 4, birth_at: @birth_at, birth_on: @birth_on, birth_time: @birth_time, knight: @larry)
23
+ Dragon.create(name: nil, is_fire_breathing: true, toes_on_claw: 5, birth_at: nil, birth_on: nil, birth_time: nil)
24
+
25
+ gold_kilo_price = 277_738.70
26
+ @gold_tonne_price = gold_kilo_price * 10_000
27
+
28
+ Country.create(
29
+ name: 'China',
30
+ population: 1_330_044_605,
31
+ birth_rate: 13.71,
32
+ gold_reserve_tonnes: 600.0,
33
+ gold_reserve_value: 600.0 * @gold_tonne_price # => 32150000
34
+ )
35
+
36
+ Country.create(
37
+ name: 'United States',
38
+ population: 303_824_646,
39
+ birth_rate: 14.18,
40
+ gold_reserve_tonnes: 8133.5,
41
+ gold_reserve_value: 8133.5 * @gold_tonne_price
42
+ )
43
+
44
+ Country.create(
45
+ name: 'Brazil',
46
+ population: 191_908_598,
47
+ birth_rate: 16.04,
48
+ gold_reserve_tonnes: nil # example of no stats available
49
+ )
50
+
51
+ Country.create(
52
+ name: 'Russia',
53
+ population: 140_702_094,
54
+ birth_rate: 11.03,
55
+ gold_reserve_tonnes: 438.2,
56
+ gold_reserve_value: 438.2 * @gold_tonne_price
57
+ )
58
+
59
+ Country.create(
60
+ name: 'Japan',
61
+ population: 127_288_419,
62
+ birth_rate: 7.87,
63
+ gold_reserve_tonnes: 765.2,
64
+ gold_reserve_value: 765.2 * @gold_tonne_price
65
+ )
66
+
67
+ Country.create(
68
+ name: 'Mexico',
69
+ population: 109_955_400,
70
+ birth_rate: 20.04,
71
+ gold_reserve_tonnes: nil # example of no stats available
72
+ )
73
+
74
+ Country.create(
75
+ name: 'Germany',
76
+ population: 82_369_548,
77
+ birth_rate: 8.18,
78
+ gold_reserve_tonnes: 3417.4,
79
+ gold_reserve_value: 3417.4 * @gold_tonne_price
80
+ )
81
+
82
+ @approx_by = 0.0001
83
+ end
84
+ end
85
+
86
+ shared_examples 'An Aggregatable Class' do
87
+ describe '#size' do
88
+ it_behaves_like 'count with no arguments'
89
+ end
90
+
91
+ describe '#count' do
92
+ it_behaves_like 'count with no arguments'
93
+
94
+ context 'with a property name' do
95
+ it 'counts the results' do
96
+ expect(dragons.count(:name)).to eq 2
97
+ end
98
+
99
+ it 'counts the results with conditions having operators' do
100
+ expect(dragons.count(:name, :toes_on_claw.gt => 3)).to eq 1
101
+ end
102
+
103
+ it 'counts the results with raw conditions' do
104
+ statement = 'is_fire_breathing = ?'
105
+ expect(dragons.count(:name, conditions: [statement, false])).to eq 1
106
+ expect(dragons.count(:name, conditions: [statement, true])).to eq 1
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '#min' do
112
+ context 'with no arguments' do
113
+ it 'raises an error' do
114
+ expect { dragons.min }.to raise_error(ArgumentError)
115
+ end
116
+ end
117
+
118
+ context 'with a property name' do
119
+ it 'provides the lowest value of an Integer property' do
120
+ expect(dragons.min(:toes_on_claw)).to eq 3
121
+ expect(countries.min(:population)).to eq 82_369_548
122
+ end
123
+
124
+ it 'provides the lowest value of a Float property' do
125
+ expect(countries.min(:birth_rate)).to be_kind_of(Float)
126
+ expect(countries.min(:birth_rate)).to be >= 7.87 - @approx_by # approx match
127
+ expect(countries.min(:birth_rate)).to be <= 7.87 + @approx_by # approx match
128
+ end
129
+
130
+ it 'provides the lowest value of a BigDecimal property' do
131
+ expect(countries.min(:gold_reserve_value)).to be_kind_of(BigDecimal)
132
+ expect(countries.min(:gold_reserve_value)).to eq BigDecimal('1217050983400.0')
133
+ end
134
+
135
+ it 'provides the lowest value of a DateTime property' do
136
+ pending_if 'TODO: returns incorrect value until DO handles TZs properly', @skip do
137
+ expect(dragons.min(:birth_at)).to be_kind_of(DateTime)
138
+ expect(dragons.min(:birth_at).to_s).to eq @birth_at.to_s
139
+ end
140
+ end
141
+
142
+ it 'provides the lowest value of a Date property' do
143
+ expect(dragons.min(:birth_on)).to be_kind_of(Date)
144
+ expect(dragons.min(:birth_on)).to eq @birth_on
145
+ end
146
+
147
+ it 'provides the lowest value of a Time property' do
148
+ expect(dragons.min(:birth_time)).to be_kind_of(Time)
149
+ expect(dragons.min(:birth_time).to_s).to eq @birth_time.to_s
150
+ end
151
+
152
+ it 'provides the lowest value when conditions provided' do
153
+ expect(dragons.min(:toes_on_claw, is_fire_breathing: true)).to eq 4
154
+ expect(dragons.min(:toes_on_claw, is_fire_breathing: false)).to eq 3
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '#max' do
160
+ context 'with no arguments' do
161
+ it 'raises an error' do
162
+ expect { dragons.max }.to raise_error(ArgumentError)
163
+ end
164
+ end
165
+
166
+ context 'with a property name' do
167
+ it 'provides the highest value of an Integer property' do
168
+ expect(dragons.max(:toes_on_claw)).to eq 5
169
+ expect(countries.max(:population)).to eq 1_330_044_605
170
+ end
171
+
172
+ it 'provides the highest value of a Float property' do
173
+ expect(countries.max(:birth_rate)).to be_kind_of(Float)
174
+ expect(countries.max(:birth_rate)).to be >= 20.04 - @approx_by # approx match
175
+ expect(countries.max(:birth_rate)).to be <= 20.04 + @approx_by # approx match
176
+ end
177
+
178
+ it 'provides the highest value of a BigDecimal property' do
179
+ expect(countries.max(:gold_reserve_value)).to eq BigDecimal('22589877164500.0')
180
+ end
181
+
182
+ it 'provides the highest value of a DateTime property' do
183
+ pending_if 'TODO: returns incorrect value until DO handles TZs properly', @skip do
184
+ expect(dragons.min(:birth_at)).to be_kind_of(DateTime)
185
+ expect(dragons.min(:birth_at).to_s).to eq @birth_at.to_s
186
+ end
187
+ end
188
+
189
+ it 'provides the highest value of a Date property' do
190
+ expect(dragons.min(:birth_on)).to be_kind_of(Date)
191
+ expect(dragons.min(:birth_on)).to eq @birth_on
192
+ end
193
+
194
+ it 'provides the highest value of a Time property' do
195
+ expect(dragons.min(:birth_time)).to be_kind_of(Time)
196
+ expect(dragons.min(:birth_time).to_s).to eq @birth_time.to_s
197
+ end
198
+
199
+ it 'provides the highest value when conditions provided' do
200
+ expect(dragons.max(:toes_on_claw, is_fire_breathing: true)).to eq 5
201
+ expect(dragons.max(:toes_on_claw, is_fire_breathing: false)).to eq 3
202
+ end
203
+ end
204
+ end
205
+
206
+ describe '#avg' do
207
+ context 'with no arguments' do
208
+ it 'raises an error' do
209
+ expect { dragons.avg }.to raise_error(ArgumentError)
210
+ end
211
+ end
212
+
213
+ context 'with a property name' do
214
+ it 'provides the average value of an Integer property' do
215
+ expect(dragons.avg(:toes_on_claw)).to be_kind_of(Float)
216
+ expect(dragons.avg(:toes_on_claw)).to eq 4.0
217
+ end
218
+
219
+ it 'provides the average value of a Float property' do
220
+ mean_birth_rate = (13.71 + 14.18 + 16.04 + 11.03 + 7.87 + 20.04 + 8.18) / 7
221
+ expect(countries.avg(:birth_rate)).to be_kind_of(Float)
222
+ expect(countries.avg(:birth_rate)).to be >= mean_birth_rate - @approx_by # approx match
223
+ expect(countries.avg(:birth_rate)).to be <= mean_birth_rate + @approx_by # approx match
224
+ end
225
+
226
+ it 'provides the average value of a BigDecimal property' do
227
+ mean_gold_reserve_value = ((600.0 + 8133.50 + 438.20 + 765.20 + 3417.40) * @gold_tonne_price) / 5
228
+ expect(countries.avg(:gold_reserve_value)).to be_kind_of(BigDecimal)
229
+ expect(countries.avg(:gold_reserve_value)).to eq BigDecimal(mean_gold_reserve_value.to_s)
230
+ end
231
+
232
+ it 'provides the average value when conditions provided' do
233
+ expect(dragons.avg(:toes_on_claw, is_fire_breathing: true)).to eq 4.5
234
+ expect(dragons.avg(:toes_on_claw, is_fire_breathing: false)).to eq 3
235
+ end
236
+ end
237
+ end
238
+
239
+ describe '#sum' do
240
+ context 'with no arguments' do
241
+ it 'raises an error' do
242
+ expect { dragons.sum }.to raise_error(ArgumentError)
243
+ end
244
+ end
245
+
246
+ context 'with a property name' do
247
+ it 'provides the sum of values for an Integer property' do
248
+ expect(dragons.sum(:toes_on_claw)).to eq 12
249
+
250
+ total_population = 1_330_044_605 + 303_824_646 + 191_908_598 + 140_702_094 +
251
+ 127_288_419 + 109_955_400 + 82_369_548
252
+ expect(countries.sum(:population)).to eq total_population
253
+ end
254
+
255
+ it 'provides the sum of values for a Float property' do
256
+ total_tonnes = 600.0 + 8133.5 + 438.2 + 765.2 + 3417.4
257
+ expect(countries.sum(:gold_reserve_tonnes)).to be_kind_of(Float)
258
+ expect(countries.sum(:gold_reserve_tonnes)).to be >= total_tonnes - @approx_by # approx match
259
+ expect(countries.sum(:gold_reserve_tonnes)).to be <= total_tonnes + @approx_by # approx match
260
+ end
261
+
262
+ it 'provides the sum of values for a BigDecimal property' do
263
+ expect(countries.sum(:gold_reserve_value)).to eq BigDecimal('37090059214100.0')
264
+ end
265
+
266
+ it 'provides the average value when conditions provided' do
267
+ expect(dragons.sum(:toes_on_claw, is_fire_breathing: true)).to eq 9
268
+ expect(dragons.sum(:toes_on_claw, is_fire_breathing: false)).to eq 3
269
+ end
270
+ end
271
+ end
272
+
273
+ describe '#aggregate' do
274
+ context 'with no arguments' do
275
+ it 'raises an error' do
276
+ expect { dragons.aggregate }.to raise_error(ArgumentError)
277
+ end
278
+ end
279
+
280
+ context 'with only aggregate fields specified' do
281
+ it 'provides aggregate results' do
282
+ results = dragons.aggregate(:all.count, :name.count, :toes_on_claw.min, :toes_on_claw.max, :toes_on_claw.avg, :toes_on_claw.sum)
283
+ expect(results).to eq [3, 2, 3, 5, 4.0, 12]
284
+ end
285
+ end
286
+
287
+ context 'with aggregate fields and a property to group by' do
288
+ it 'provides aggregate results' do
289
+ results = dragons.aggregate(:all.count, :name.count,
290
+ :toes_on_claw.min, :toes_on_claw.max, :toes_on_claw.avg, :toes_on_claw.sum, :is_fire_breathing)
291
+ expect(results).to eq [[1, 1, 3, 3, 3.0, 3, false], [2, 1, 4, 5, 4.5, 9, true]]
292
+ end
293
+ end
294
+ end
295
+
296
+ describe 'query path issue' do
297
+ it 'does not break when a query path is specified' do
298
+ dragon = dragons.first(Dragon.knight.name => 'Chuck')
299
+ expect(dragon.name).to eq 'George'
300
+ end
301
+ end
302
+ end
303
+
304
+ shared_examples 'count with no arguments' do
305
+ it 'counts the results' do
306
+ expect(dragons.count).to eq 3
307
+
308
+ expect(countries.count).to eq 7
309
+ end
310
+
311
+ it 'counts the results with conditions having operators' do
312
+ expect(dragons.count(:toes_on_claw.gt => 3)).to eq 2
313
+
314
+ expect(countries.count(:birth_rate.lt => 12)).to eq 3
315
+ expect(countries.count(:population.gt => 1_000_000_000)).to eq 1
316
+ expect(countries.count(:population.gt => 2_000_000_000)).to eq 0
317
+ expect(countries.count(:population.lt => 10)).to eq 0
318
+ end
319
+
320
+ it 'counts the results with raw conditions' do
321
+ dragon_statement = 'is_fire_breathing = ?'
322
+ expect(dragons.count(conditions: [dragon_statement, false])).to eq 1
323
+ expect(dragons.count(conditions: [dragon_statement, true])).to eq 2
324
+ end
325
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,6 @@
1
+ --exclude "spec,^/"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
@@ -0,0 +1,55 @@
1
+
2
+ require 'dm-core/spec/setup'
3
+ require 'dm-core/spec/lib/adapter_helpers'
4
+ require 'dm-core/spec/lib/pending_helpers'
5
+
6
+ require 'dm-aggregates'
7
+ require 'dm-migrations'
8
+
9
+ require 'public/shared/aggregate_shared_spec'
10
+
11
+ DataMapper::Spec.setup
12
+
13
+ RSpec.configure do |config|
14
+ config.extend(DataMapper::Spec::Adapters::Helpers)
15
+ config.include(DataMapper::Spec::PendingHelpers)
16
+
17
+ config.before(:all) do
18
+ # A simplistic example, using with an Integer property
19
+ class ::Knight
20
+ include DataMapper::Resource
21
+
22
+ property :id, Serial
23
+ property :name, String
24
+ end
25
+
26
+ class ::Dragon
27
+ include DataMapper::Resource
28
+
29
+ property :id, Serial
30
+ property :name, String
31
+ property :is_fire_breathing, Boolean
32
+ property :toes_on_claw, Integer
33
+ property :birth_at, DateTime
34
+ property :birth_on, Date
35
+ property :birth_time, Time
36
+
37
+ belongs_to :knight, required: false
38
+ end
39
+
40
+ # A more complex example, with BigDecimal and Float properties
41
+ # Statistics taken from CIA World Factbook:
42
+ # https://www.cia.gov/library/publications/the-world-factbook/
43
+ class ::Country
44
+ include DataMapper::Resource
45
+
46
+ property :id, Serial
47
+ property :name, String, required: true
48
+ property :population, Integer
49
+ property :birth_rate, Float, precision: 4, scale: 2
50
+ property :gold_reserve_tonnes, Float, precision: 6, scale: 2
51
+ property :gold_reserve_value, Decimal, precision: 15, scale: 1 # approx. value in USD
52
+ end
53
+ DataMapper.finalize
54
+ end
55
+ end
@@ -0,0 +1,6 @@
1
+ desc 'Release all gems (native, binaries for JRuby and Windows)'
2
+ task :release do
3
+ command = "gem push sbf-dm-aggregates-1.3.0.beta.gem"
4
+ puts "Executing #{command.inspect}:"
5
+ # sh command
6
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,21 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ begin
4
+ task(:default).clear
5
+ task(:spec).clear
6
+
7
+ RSpec::Core::RakeTask.new(:spec) do |spec|
8
+ spec.pattern = 'spec/**/*_spec.rb'
9
+
10
+ require 'simplecov'
11
+ SimpleCov.start do
12
+ minimum_coverage 100
13
+ end
14
+ end
15
+ rescue LoadError
16
+ task :spec do
17
+ abort 'rspec is not available. In order to run spec, you must: gem install rspec'
18
+ end
19
+ end
20
+
21
+ task default: :spec
data/tasks/yard.rake ADDED
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'yard'
3
+
4
+ YARD::Rake::YardocTask.new
5
+ rescue LoadError
6
+ task :yard do
7
+ abort 'YARD is not available. In order to run yard, you must: gem install yard'
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ begin
2
+ require 'pathname'
3
+ require 'yardstick/rake/measurement'
4
+ require 'yardstick/rake/verify'
5
+
6
+ # yardstick_measure task
7
+ Yardstick::Rake::Measurement.new
8
+
9
+ # verify_measurements task
10
+ Yardstick::Rake::Verify.new do |verify|
11
+ verify.threshold = 100
12
+ end
13
+ rescue LoadError
14
+ %w(yardstick_measure verify_measurements).each do |name|
15
+ task name.to_s do
16
+ abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sbf-dm-aggregates
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.0.beta
5
+ platform: ruby
6
+ authors:
7
+ - Emmanuel Gomez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sbf-dm-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.3.0.beta
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.3.0.beta
27
+ description: DataMapper plugin providing support for aggregates, functions on collections
28
+ and datasets.
29
+ email:
30
+ - emmanuel.gomez@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files:
34
+ - LICENSE
35
+ - README.rdoc
36
+ files:
37
+ - ".gitignore"
38
+ - ".rspec"
39
+ - ".rubocop.yml"
40
+ - Gemfile
41
+ - LICENSE
42
+ - README.rdoc
43
+ - Rakefile
44
+ - VERSION
45
+ - dm-aggregates.gemspec
46
+ - lib/dm-aggregates.rb
47
+ - lib/dm-aggregates/adapters/dm-do-adapter.rb
48
+ - lib/dm-aggregates/aggregate_functions.rb
49
+ - lib/dm-aggregates/collection.rb
50
+ - lib/dm-aggregates/core_ext/symbol.rb
51
+ - lib/dm-aggregates/functions.rb
52
+ - lib/dm-aggregates/model.rb
53
+ - lib/dm-aggregates/query.rb
54
+ - lib/dm-aggregates/repository.rb
55
+ - lib/dm-aggregates/symbol_operators.rb
56
+ - lib/dm-aggregates/version.rb
57
+ - spec/isolated/require_after_setup_spec.rb
58
+ - spec/isolated/require_before_setup_spec.rb
59
+ - spec/isolated/require_spec.rb
60
+ - spec/public/collection_spec.rb
61
+ - spec/public/model_spec.rb
62
+ - spec/public/shared/aggregate_shared_spec.rb
63
+ - spec/rcov.opts
64
+ - spec/spec_helper.rb
65
+ - tasks/release.rake
66
+ - tasks/spec.rake
67
+ - tasks/yard.rake
68
+ - tasks/yardstick.rake
69
+ homepage: https://datamapper.org
70
+ licenses:
71
+ - Nonstandard
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 2.7.8
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">"
85
+ - !ruby/object:Gem::Version
86
+ version: 1.3.1
87
+ requirements: []
88
+ rubygems_version: 3.4.10
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: DataMapper plugin providing support for aggregates on collections
92
+ test_files: []