dbee 2.0.3 → 2.1.0.pre.alpha

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a84b1a2e86f04be67850fa1bfe79aa9a52d1548db6ba8c76df551b5257a00bd8
4
- data.tar.gz: 2c7d2d5b847e805f46c94019c72b6d7c79990ebd2d4b7d8a3d940278b267a904
3
+ metadata.gz: acc518f50b6b9e95165347240882ca415194e6b641e68ff292d5b2a6d3937527
4
+ data.tar.gz: 954dbcdfac112f2098e7c1828d8c243369092526ee65179c9819ceaafddc70f7
5
5
  SHA512:
6
- metadata.gz: 83f756643490546309610118e1ff5efb501c3db51c0322e5a2bb7a0fe2bc96b5164362d9531e6ff11371fee8a6096ba38c04f5c269bf590670fa76c03d62bb45
7
- data.tar.gz: 449063144c4ba5babd0358e7d8851686d4cf7520d2aef2a9444175e616cc9a9a01fe8c3596c941e24ce4dafa5c7e4aaa0fe8d8ac378953f61d97e2acbc4a36b8
6
+ metadata.gz: 5731c83ec9b0ded7f36c6b07d16597f97337240bd65bbec7dc82a9ca7f4de4da0cac9063a6e9aa9cf8199e6f5c32e7ab0a2904684b64bebde9e996f9bceb8e41
7
+ data.tar.gz: c47a038d7fac640a620a13373460bbd8df05a35b209264de1b0fedd727eab072925d0f2cfa82a800ddd2362756f887b0cd227d1e1cd01c98a0334b1c3cd55cd0
@@ -1,6 +1,18 @@
1
- Metrics/LineLength:
1
+ AllCops:
2
+ TargetRubyVersion: 2.5
3
+
4
+ Layout/LineLength:
2
5
  Max: 100
3
6
 
7
+ Lint/RaiseException:
8
+ Enabled: True
9
+
10
+ Lint/StructNewOverride:
11
+ Enabled: True
12
+
13
+ Metrics/AbcSize:
14
+ Max: 16
15
+
4
16
  Metrics/BlockLength:
5
17
  ExcludedMethods:
6
18
  - let
@@ -10,14 +22,17 @@ Metrics/BlockLength:
10
22
  - specify
11
23
  - define
12
24
 
25
+ Metrics/ClassLength:
26
+ Max: 125
27
+
13
28
  Metrics/MethodLength:
14
29
  Max: 25
15
30
 
16
- AllCops:
17
- TargetRubyVersion: 2.3
31
+ Style/HashEachMethods:
32
+ Enabled: True
18
33
 
19
- Metrics/AbcSize:
20
- Max: 16
34
+ Style/HashTransformKeys:
35
+ Enabled: True
21
36
 
22
- Metrics/ClassLength:
23
- Max: 125
37
+ Style/HashTransformValues:
38
+ Enabled: True
@@ -1 +1 @@
1
- 2.6.5
1
+ 2.6.6
@@ -4,10 +4,9 @@ env:
4
4
  language: ruby
5
5
  rvm:
6
6
  # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
7
- - 2.3.8
8
- - 2.4.6
9
- - 2.5.5
10
- - 2.6.5
7
+ - 2.5.8
8
+ - 2.6.6
9
+ - 2.7.1
11
10
  cache: bundler
12
11
  before_script:
13
12
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
@@ -1,3 +1,14 @@
1
+ # 2.1.0 (TBD)
2
+
3
+ ### Additions:
4
+
5
+ * Added Dbee::Query::Field#aggregator (such as ave, min, max, sum, etc.)
6
+ * Added Dbee::Query::Field#filters (allows for doing select column filtering)
7
+
8
+ ### Changes:
9
+
10
+ * Bumped minimum Ruby version to 2.5
11
+
1
12
  # 2.0.3 (January 7th, 2020)
2
13
 
3
14
  ### Fixes:
data/README.md CHANGED
@@ -407,6 +407,129 @@ sql = Dbee.sql(model, query, provider)
407
407
 
408
408
  The above examples showed how to use a plugin provider, see the plugin provider's documentation for more information about its options and use.
409
409
 
410
+ #### Aggregation
411
+
412
+ Fields can be configured to use aggregation by setting its `aggregator` attribute. For example, say we wanted to count the number of patients per practice:
413
+
414
+ **Data Model**:
415
+
416
+ ````yaml
417
+ name: practice
418
+ models:
419
+ - name: patients
420
+ constraints:
421
+ - type: reference
422
+ name: practice_id
423
+ parent: id
424
+ ````
425
+
426
+ **Query**:
427
+
428
+ ````ruby
429
+ query = {
430
+ fields: [
431
+ {
432
+ key_path: 'id',
433
+ display: 'Practice ID #',
434
+ },
435
+ {
436
+ key_path: 'name',
437
+ display: 'Practice Name',
438
+ },
439
+ {
440
+ key_path: 'patients.id',
441
+ display: 'Total Patients',
442
+ aggregator: :count
443
+ },
444
+ ]
445
+ ````
446
+
447
+ An example of a materialized result would be something akin to:
448
+
449
+ Practice ID # | Practice Name | Total Patients
450
+ ------------- | --------------- | --------------
451
+ 1 | Families Choice | 293
452
+ 2 | Awesome Choice | 2305
453
+ 3 | Best Value | 1200
454
+
455
+ A complete list of aggregator values can be found by inspecting the `Dbee::Query::Field::Aggregator` constant.
456
+
457
+ #### Field/Column Level Filtering & Pivoting
458
+
459
+ Fields can also have filters which provide post-filtering (on the select-level instead of at query-level.) This can be used in conjunction with aggregate functions to provide pivoting. For example:
460
+
461
+ **Data/Schema Example**:
462
+
463
+ patients:
464
+
465
+ id | first | last
466
+ -- | ----- | -----
467
+ 1 | frank | rizzo
468
+
469
+ patient_fields:
470
+
471
+ id | patient_id | key | value
472
+ -- | ---------- | --------------- | -----
473
+ 1 | 1 | dob | 1900-01-01
474
+ 2 | 1 | drivers_license | ABC123
475
+
476
+ **Model Configuration**:
477
+
478
+ ````yaml
479
+ name: patients
480
+ models:
481
+ - name: patient_fields
482
+ constraints:
483
+ - type: reference
484
+ parent: id
485
+ name: patient_id
486
+ ````
487
+
488
+ **Query**:
489
+
490
+ ````ruby
491
+ query = {
492
+ fields: [
493
+ {
494
+ key_path: 'id',
495
+ display: 'ID #'
496
+ },
497
+ {
498
+ key_path: 'first',
499
+ display: 'First Name'
500
+ },
501
+ {
502
+ aggregator: :max,
503
+ key_path: 'patient_fields.value',
504
+ display: 'Date of Birth',
505
+ filters: [
506
+ {
507
+ key_path: 'patient_fields.key',
508
+ value: 'dob'
509
+ }
510
+ ]
511
+ },
512
+ {
513
+ aggregator: :max,
514
+ key_path: 'patient_fields.value',
515
+ display: 'Drivers License #',
516
+ filters: [
517
+ {
518
+ key_path: 'patient_fields.key',
519
+ value: 'drivers_license'
520
+ }
521
+ ]
522
+ }
523
+ }
524
+ }
525
+ ````
526
+
527
+ Executing the query above against the data and model would yield:
528
+
529
+ ID # | First Name | Date of Birth | Drivers License #
530
+ -- | ---------- | ------------- | -----------------
531
+ 1 | frank | 1900-01-01 | ABC123
532
+
410
533
 
411
534
  ## Contributing
412
535
 
@@ -15,20 +15,28 @@ Gem::Specification.new do |s|
15
15
  s.email = ['mruggio@bluemarblepayroll.com']
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.bindir = 'exe'
19
+ s.executables = []
19
20
  s.homepage = 'https://github.com/bluemarblepayroll/dbee'
20
21
  s.license = 'MIT'
22
+ s.metadata = {
23
+ 'bug_tracker_uri' => 'https://github.com/bluemarblepayroll/dbee/issues',
24
+ 'changelog_uri' => 'https://github.com/bluemarblepayroll/dbee/blob/master/CHANGELOG.md',
25
+ 'documentation_uri' => 'https://www.rubydoc.info/gems/dbee',
26
+ 'homepage_uri' => s.homepage,
27
+ 'source_code_uri' => s.homepage
28
+ }
21
29
 
22
- s.required_ruby_version = '>= 2.3.8'
30
+ s.required_ruby_version = '>= 2.5'
23
31
 
24
- s.add_dependency('acts_as_hashable', '~>1', '>=1.1.0')
32
+ s.add_dependency('acts_as_hashable', '~>1', '>=1.2.0')
25
33
  s.add_dependency('dry-inflector', '~>0')
26
34
 
27
35
  s.add_development_dependency('guard-rspec', '~>4.7')
28
36
  s.add_development_dependency('pry', '~>0')
29
37
  s.add_development_dependency('rake', '~> 13')
30
38
  s.add_development_dependency('rspec')
31
- s.add_development_dependency('rubocop', '~>0.79.0')
39
+ s.add_development_dependency('rubocop', '~>0.81.0')
32
40
  s.add_development_dependency('simplecov', '~>0.17.0')
33
- s.add_development_dependency('simplecov-console', '~>0.6.0')
41
+ s.add_development_dependency('simplecov-console', '~>0.7.0')
34
42
  end
File without changes
@@ -25,10 +25,8 @@ module Dbee
25
25
 
26
26
  attr_reader :fields, :filters, :limit, :sorters
27
27
 
28
- def_delegator :fields, :sort, :sorted_fields
29
-
28
+ def_delegator :fields, :sort, :sorted_fields
30
29
  def_delegator :filters, :sort, :sorted_filters
31
-
32
30
  def_delegator :sorters, :sort, :sorted_sorters
33
31
 
34
32
  def initialize(fields:, filters: [], limit: nil, sorters: [])
@@ -15,24 +15,55 @@ module Dbee
15
15
  class Field
16
16
  acts_as_hashable
17
17
 
18
- attr_reader :key_path, :display
18
+ module Aggregator
19
+ AVE = :ave
20
+ COUNT = :count
21
+ MAX = :max
22
+ MIN = :min
23
+ SUM = :sum
24
+ end
25
+ include Aggregator
26
+
27
+ attr_reader :aggregator, :display, :filters, :key_path
19
28
 
20
- def initialize(key_path:, display: nil)
29
+ def initialize(
30
+ aggregator: nil,
31
+ display: nil,
32
+ filters: [],
33
+ key_path:
34
+ )
21
35
  raise ArgumentError, 'key_path is required' if key_path.to_s.empty?
22
36
 
23
- @key_path = KeyPath.get(key_path)
24
- @display = (display.to_s.empty? ? key_path : display).to_s
37
+ @aggregator = aggregator ? Aggregator.const_get(aggregator.to_s.upcase.to_sym) : nil
38
+ @display = (display.to_s.empty? ? key_path : display).to_s
39
+ @filters = Filters.array(filters).uniq
40
+ @key_path = KeyPath.get(key_path)
25
41
 
26
42
  freeze
27
43
  end
28
44
 
45
+ def filters?
46
+ filters.any?
47
+ end
48
+
49
+ def aggregator?
50
+ !aggregator.nil?
51
+ end
52
+
29
53
  def hash
30
- "#{key_path}#{display}".hash
54
+ [
55
+ aggregator,
56
+ display,
57
+ filters,
58
+ key_path
59
+ ].hash
31
60
  end
32
61
 
33
62
  def ==(other)
34
63
  other.instance_of?(self.class) &&
64
+ other.aggregator == aggregator &&
35
65
  other.key_path == key_path &&
66
+ other.filters == filters &&
36
67
  other.display == display
37
68
  end
38
69
  alias eql? ==
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Dbee
11
- VERSION = '2.0.3'
11
+ VERSION = '2.1.0-alpha'
12
12
  end
@@ -10,6 +10,31 @@
10
10
  require 'spec_helper'
11
11
 
12
12
  describe Dbee::Query::Field do
13
+ let(:config) do
14
+ {
15
+ display: 'd',
16
+ key_path: 'a.b.c'
17
+ }
18
+ end
19
+
20
+ let(:config_with_aggregation_and_filters) do
21
+ config.merge(
22
+ aggregator: :ave,
23
+ filters: [
24
+ {
25
+ key_path: 'a.b',
26
+ value: 'something'
27
+ }
28
+ ]
29
+ )
30
+ end
31
+
32
+ subject { described_class.new(config_with_aggregation_and_filters) }
33
+
34
+ let(:subject_without_aggregation_and_filters) do
35
+ described_class.new(config)
36
+ end
37
+
13
38
  it 'should act as hashable' do
14
39
  expect(described_class).to respond_to(:make)
15
40
  expect(described_class).to respond_to(:array)
@@ -24,16 +49,19 @@ describe Dbee::Query::Field do
24
49
  end
25
50
 
26
51
  context 'equality' do
27
- let(:config) { { key_path: 'a.b.c', display: 'd' } }
52
+ specify '#hash produces same output as [aggregator, key_path, and display]' do
53
+ expected = [
54
+ subject.aggregator,
55
+ subject.display,
56
+ subject.filters,
57
+ subject.key_path
58
+ ].hash
28
59
 
29
- subject { described_class.new(config) }
30
-
31
- specify '#hash produces same output as concatenated string hash of key_path and display' do
32
- expect(subject.hash).to eq("#{config[:key_path]}#{config[:display]}".hash)
60
+ expect(subject.hash).to eq(expected)
33
61
  end
34
62
 
35
63
  specify '#== and #eql? compare attributes' do
36
- object2 = described_class.new(config)
64
+ object2 = described_class.new(config_with_aggregation_and_filters)
37
65
 
38
66
  expect(subject).to eq(object2)
39
67
  expect(subject).to eql(object2)
@@ -44,4 +72,24 @@ describe Dbee::Query::Field do
44
72
  expect(subject).not_to eq(nil)
45
73
  end
46
74
  end
75
+
76
+ describe '#aggregator?' do
77
+ it 'returns true if not nil' do
78
+ expect(subject.aggregator?).to be true
79
+ end
80
+
81
+ it 'returns false if nil' do
82
+ expect(subject_without_aggregation_and_filters.aggregator?).to be false
83
+ end
84
+ end
85
+
86
+ describe '#filters?' do
87
+ it 'returns true if at least one filter' do
88
+ expect(subject.filters?).to be true
89
+ end
90
+
91
+ it 'returns false if nil' do
92
+ expect(subject_without_aggregation_and_filters.filters?).to be false
93
+ end
94
+ end
47
95
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbee
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-07 00:00:00.000000000 Z
11
+ date: 2020-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '1'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 1.1.0
22
+ version: 1.2.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '1'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 1.1.0
32
+ version: 1.2.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: dry-inflector
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -106,14 +106,14 @@ dependencies:
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: 0.79.0
109
+ version: 0.81.0
110
110
  type: :development
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: 0.79.0
116
+ version: 0.81.0
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: simplecov
119
119
  requirement: !ruby/object:Gem::Requirement
@@ -134,22 +134,21 @@ dependencies:
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: 0.6.0
137
+ version: 0.7.0
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: 0.6.0
144
+ version: 0.7.0
145
145
  description: " Dbee provides a simple-to-use data modeling and query API. The
146
146
  query API can produce SQL using other ORMs, such as Arel/ActiveRecord. The targeted
147
147
  use-case for Dbee is ad-hoc reporting, so the total SQL feature-set that Dbee supports
148
148
  is rather limited.\n"
149
149
  email:
150
150
  - mruggio@bluemarblepayroll.com
151
- executables:
152
- - console
151
+ executables: []
153
152
  extensions: []
154
153
  extra_rdoc_files: []
155
154
  files:
@@ -167,6 +166,7 @@ files:
167
166
  - Rakefile
168
167
  - bin/console
169
168
  - dbee.gemspec
169
+ - exe/.gitkeep
170
170
  - lib/dbee.rb
171
171
  - lib/dbee/base.rb
172
172
  - lib/dbee/constant_resolver.rb
@@ -227,7 +227,12 @@ files:
227
227
  homepage: https://github.com/bluemarblepayroll/dbee
228
228
  licenses:
229
229
  - MIT
230
- metadata: {}
230
+ metadata:
231
+ bug_tracker_uri: https://github.com/bluemarblepayroll/dbee/issues
232
+ changelog_uri: https://github.com/bluemarblepayroll/dbee/blob/master/CHANGELOG.md
233
+ documentation_uri: https://www.rubydoc.info/gems/dbee
234
+ homepage_uri: https://github.com/bluemarblepayroll/dbee
235
+ source_code_uri: https://github.com/bluemarblepayroll/dbee
231
236
  post_install_message:
232
237
  rdoc_options: []
233
238
  require_paths:
@@ -236,12 +241,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
236
241
  requirements:
237
242
  - - ">="
238
243
  - !ruby/object:Gem::Version
239
- version: 2.3.8
244
+ version: '2.5'
240
245
  required_rubygems_version: !ruby/object:Gem::Requirement
241
246
  requirements:
242
- - - ">="
247
+ - - ">"
243
248
  - !ruby/object:Gem::Version
244
- version: '0'
249
+ version: 1.3.1
245
250
  requirements: []
246
251
  rubygems_version: 3.0.3
247
252
  signing_key: