dbee 2.0.0 → 2.1.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 +4 -4
- data/.rubocop.yml +11 -10
- data/.ruby-version +1 -1
- data/.travis.yml +3 -3
- data/CHANGELOG.md +38 -0
- data/README.md +125 -2
- data/dbee.gemspec +14 -6
- data/exe/.gitkeep +0 -0
- data/lib/dbee.rb +1 -0
- data/lib/dbee/constant_resolver.rb +34 -0
- data/lib/dbee/dsl/association.rb +11 -9
- data/lib/dbee/query.rb +26 -12
- data/lib/dbee/query/field.rb +40 -5
- data/lib/dbee/version.rb +1 -1
- data/spec/dbee/constant_resolver_spec.rb +53 -0
- data/spec/dbee/query/field_spec.rb +54 -6
- metadata +23 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8881fb69d8398471e0857f9b8e01a1452aaf6688a3a30aa38868b8254549e9c
|
4
|
+
data.tar.gz: ca28fbd217d3a8c7daa2c41e5d9ea7d24173ab1b57c48467c9700c5b4871c01e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1cdd0b920c5ee6c02829eebe6e9d2851401eb996f2573f8524eba027de10102e9c706de9468cfeec503ec2ecf28cce525f2511ef0952c9204bf49462bd262be
|
7
|
+
data.tar.gz: 6e6e2d772a318b8cc8960300b45ecb830bbde5973e567295eddff15f287ebf453e09df30de1d686d8a0ee157d590d4af0d48cd71e87012cc1d0606d952c2cac6
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5
|
3
|
+
NewCops: enable
|
4
|
+
|
5
|
+
Layout/LineLength:
|
2
6
|
Max: 100
|
3
7
|
|
8
|
+
Metrics/AbcSize:
|
9
|
+
Max: 16
|
10
|
+
|
4
11
|
Metrics/BlockLength:
|
5
12
|
ExcludedMethods:
|
6
13
|
- let
|
@@ -10,14 +17,8 @@ Metrics/BlockLength:
|
|
10
17
|
- specify
|
11
18
|
- define
|
12
19
|
|
13
|
-
Metrics/MethodLength:
|
14
|
-
Max: 25
|
15
|
-
|
16
|
-
AllCops:
|
17
|
-
TargetRubyVersion: 2.4
|
18
|
-
|
19
|
-
Metrics/AbcSize:
|
20
|
-
Max: 16
|
21
|
-
|
22
20
|
Metrics/ClassLength:
|
23
21
|
Max: 125
|
22
|
+
|
23
|
+
Metrics/MethodLength:
|
24
|
+
Max: 25
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.6
|
data/.travis.yml
CHANGED
@@ -4,9 +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.
|
8
|
-
- 2.
|
9
|
-
- 2.
|
7
|
+
- 2.5.8
|
8
|
+
- 2.6.6
|
9
|
+
- 2.7.1
|
10
10
|
cache: bundler
|
11
11
|
before_script:
|
12
12
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
# 2.1.0 (July 13th, 2020)
|
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
|
+
|
12
|
+
# 2.0.3 (January 7th, 2020)
|
13
|
+
|
14
|
+
### Fixes:
|
15
|
+
|
16
|
+
* Constant resolution will now explicitly set inherit to false when calling `Object#const_defined?` and `Object#const_get`. This should equate to less false positives. For example:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
class A; end
|
20
|
+
|
21
|
+
module B
|
22
|
+
class A; end
|
23
|
+
class C; end
|
24
|
+
end
|
25
|
+
```
|
26
|
+
|
27
|
+
If `B::A` is the desired class, it would not be suitable to just declare an association on `A` as that would resolve explicitly to `::A`. It also means C cannot be auto-resolved without prefixing/sharing the namespace with parent association `A`.
|
28
|
+
|
29
|
+
# 2.0.2 (November 7th, 2019)
|
30
|
+
|
31
|
+
### Additions:
|
32
|
+
|
33
|
+
* As of 2019-11-07, it is not recommended to use Ruby 2.3, but support was requested and added for Ruby 2.3.8. This is subject to being deprecated with next version.
|
34
|
+
|
35
|
+
### Fixes:
|
36
|
+
|
37
|
+
* Constantizing during inflection will now first check Object#const_defined? and if it is missing, it will now call Object#const_missing. This should work better with auto-loaded environments where constant names may collide, since Object#const_get will traverse down the entire hierarchy and may lead to false positives.
|
38
|
+
|
1
39
|
# 2.0.0 (September 3rd, 2019)
|
2
40
|
|
3
41
|
### Additions:
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Dbee arose out of a need for an ad-hoc reporting solution that included:
|
|
9
9
|
* de-coupling from our main ORM (ActiveRecord)
|
10
10
|
* Rails 5.2.1 and above compatibility
|
11
11
|
|
12
|
-
Dbee provides
|
12
|
+
Dbee provides very simple Data Modeling and Query API's and as such it is not meant to replace a traditional ORM or your data persistence layer, but compliment them. This library's goal is to output the SQL statement needed and **nothing** more.
|
13
13
|
|
14
14
|
Other solutions considered:
|
15
15
|
|
@@ -123,7 +123,7 @@ The two DSL methods: parent/child are very similar to ActiveRecord's belongs_to/
|
|
123
123
|
|
124
124
|
##### Customizing Inflection Rules
|
125
125
|
|
126
|
-
Inflection is provided via the
|
126
|
+
Inflection is provided via the [Dry::Inflector gem](https://github.com/dry-rb/dry-inflector). There are options to add custom grammar rules which you can then pass into Dbee. For example:
|
127
127
|
|
128
128
|
````ruby
|
129
129
|
Dbee.inflector = Dry::Inflector.new do |inflections|
|
@@ -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
|
|
data/dbee.gemspec
CHANGED
@@ -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.
|
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.
|
30
|
+
s.required_ruby_version = '>= 2.5'
|
23
31
|
|
24
|
-
s.add_dependency('acts_as_hashable', '~>1', '>=1.
|
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
|
-
s.add_development_dependency('rake', '~>
|
37
|
+
s.add_development_dependency('rake', '~> 13')
|
30
38
|
s.add_development_dependency('rspec')
|
31
|
-
s.add_development_dependency('rubocop', '~>0.
|
39
|
+
s.add_development_dependency('rubocop', '~>0.88.0')
|
32
40
|
s.add_development_dependency('simplecov', '~>0.17.0')
|
33
|
-
s.add_development_dependency('simplecov-console', '~>0.
|
41
|
+
s.add_development_dependency('simplecov-console', '~>0.7.0')
|
34
42
|
end
|
data/exe/.gitkeep
ADDED
File without changes
|
data/lib/dbee.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Dbee
|
11
|
+
# This class is responsible for turning strings and symbols into constants.
|
12
|
+
# It does not deal with inflection, simply just constant resolution.
|
13
|
+
class ConstantResolver
|
14
|
+
# Only use Module constant resolution if a string or symbol was passed in.
|
15
|
+
# Any other type is defined as an acceptable constant and is simply returned.
|
16
|
+
def constantize(value)
|
17
|
+
value.is_a?(String) || value.is_a?(Symbol) ? object_constant(value) : value
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# If the constant has been loaded, we can safely use it through const_get.
|
23
|
+
# If the constant has not been loaded, we need to defer to const_missing to resolve it.
|
24
|
+
# If we blindly call const_get, it may return false positives for namespaced constants
|
25
|
+
# or anything nested.
|
26
|
+
def object_constant(value)
|
27
|
+
if Object.const_defined?(value, false)
|
28
|
+
Object.const_get(value, false)
|
29
|
+
else
|
30
|
+
Object.const_missing(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/dbee/dsl/association.rb
CHANGED
@@ -19,16 +19,17 @@ module Dbee
|
|
19
19
|
raise ArgumentError, 'inflector is required' unless inflector
|
20
20
|
raise ArgumentError, 'name is required' if name.to_s.empty?
|
21
21
|
|
22
|
-
@on_class_name
|
23
|
-
@inflector
|
24
|
-
@name
|
25
|
-
@opts
|
22
|
+
@on_class_name = on_class_name
|
23
|
+
@inflector = inflector
|
24
|
+
@name = name.to_s
|
25
|
+
@opts = opts || {}
|
26
|
+
@constant_resolver = ConstantResolver.new
|
26
27
|
|
27
28
|
freeze
|
28
29
|
end
|
29
30
|
|
30
31
|
def model_constant
|
31
|
-
constantize(class_name)
|
32
|
+
constant_resolver.constantize(class_name)
|
32
33
|
end
|
33
34
|
|
34
35
|
def constraints
|
@@ -37,17 +38,18 @@ module Dbee
|
|
37
38
|
|
38
39
|
private
|
39
40
|
|
41
|
+
attr_reader :constant_resolver
|
42
|
+
|
40
43
|
def class_name
|
41
44
|
opts[:model] || relative_class_name
|
42
45
|
end
|
43
46
|
|
47
|
+
# This will automatically prefix the name of the module within the current classes
|
48
|
+
# hierarchy. If the class does not happen to be in the same namespace then it needs
|
49
|
+
# to be explicitly set in the association using 'model' option.
|
44
50
|
def relative_class_name
|
45
51
|
(on_class_name.split('::')[0...-1] + [inflector.classify(name)]).join('::')
|
46
52
|
end
|
47
|
-
|
48
|
-
def constantize(value)
|
49
|
-
value.is_a?(String) || value.is_a?(Symbol) ? Object.const_get(value) : value
|
50
|
-
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
end
|
data/lib/dbee/query.rb
CHANGED
@@ -23,15 +23,24 @@ module Dbee
|
|
23
23
|
|
24
24
|
class NoFieldsError < StandardError; end
|
25
25
|
|
26
|
-
attr_reader :fields,
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def_delegator :
|
33
|
-
|
34
|
-
|
26
|
+
attr_reader :fields,
|
27
|
+
:filters,
|
28
|
+
:groupers,
|
29
|
+
:limit,
|
30
|
+
:sorters
|
31
|
+
|
32
|
+
def_delegator :fields, :sort, :sorted_fields
|
33
|
+
def_delegator :filters, :sort, :sorted_filters
|
34
|
+
def_delegator :sorters, :sort, :sorted_sorters
|
35
|
+
def_delegator :groupers, :sort, :sorted_groupers
|
36
|
+
|
37
|
+
def initialize(
|
38
|
+
fields:,
|
39
|
+
filters: [],
|
40
|
+
groupers: [],
|
41
|
+
limit: nil,
|
42
|
+
sorters: []
|
43
|
+
)
|
35
44
|
@fields = Field.array(fields)
|
36
45
|
|
37
46
|
# If no fields were passed into a query then we will have no data to return.
|
@@ -40,6 +49,7 @@ module Dbee
|
|
40
49
|
raise NoFieldsError if @fields.empty?
|
41
50
|
|
42
51
|
@filters = Filters.array(filters).uniq
|
52
|
+
@groupers = Array(groupers).map { |k| KeyPath.get(k) }.uniq
|
43
53
|
@limit = limit.to_s.empty? ? nil : limit.to_i
|
44
54
|
@sorters = Sorters.array(sorters).uniq
|
45
55
|
|
@@ -48,10 +58,10 @@ module Dbee
|
|
48
58
|
|
49
59
|
def ==(other)
|
50
60
|
other.instance_of?(self.class) &&
|
61
|
+
other.limit == limit &&
|
51
62
|
other.sorted_fields == sorted_fields &&
|
52
63
|
other.sorted_filters == sorted_filters &&
|
53
|
-
other.sorted_sorters == sorted_sorters
|
54
|
-
other.limit == limit
|
64
|
+
other.sorted_sorters == sorted_sorters
|
55
65
|
end
|
56
66
|
alias eql? ==
|
57
67
|
|
@@ -62,7 +72,11 @@ module Dbee
|
|
62
72
|
private
|
63
73
|
|
64
74
|
def key_paths
|
65
|
-
(
|
75
|
+
(
|
76
|
+
fields.flat_map(&:key_paths) +
|
77
|
+
filters.map(&:key_path) +
|
78
|
+
sorters.map(&:key_path)
|
79
|
+
)
|
66
80
|
end
|
67
81
|
end
|
68
82
|
end
|
data/lib/dbee/query/field.rb
CHANGED
@@ -15,24 +15,55 @@ module Dbee
|
|
15
15
|
class Field
|
16
16
|
acts_as_hashable
|
17
17
|
|
18
|
-
|
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(
|
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
|
-
@
|
24
|
-
@display
|
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
|
-
|
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? ==
|
@@ -40,6 +71,10 @@ module Dbee
|
|
40
71
|
def <=>(other)
|
41
72
|
"#{key_path}#{display}" <=> "#{other.key_path}#{other.display}"
|
42
73
|
end
|
74
|
+
|
75
|
+
def key_paths
|
76
|
+
[key_path] + filters.map(&:key_path)
|
77
|
+
end
|
43
78
|
end
|
44
79
|
end
|
45
80
|
end
|
data/lib/dbee/version.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2019-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require 'spec_helper'
|
11
|
+
|
12
|
+
describe Dbee::ConstantResolver do
|
13
|
+
module A
|
14
|
+
class B; end
|
15
|
+
class E; end
|
16
|
+
end
|
17
|
+
|
18
|
+
class B; end
|
19
|
+
|
20
|
+
module C
|
21
|
+
class D; end
|
22
|
+
class E; end
|
23
|
+
|
24
|
+
module F
|
25
|
+
class G; end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'resolves nested constant with the same as an ancestor constants sibling' do
|
30
|
+
expect(subject.constantize('A::B')).to eq(::A::B)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'resolves root constant' do
|
34
|
+
expect(subject.constantize('B')).to eq(::B)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not resolve constant in a different parent module' do
|
38
|
+
expect { subject.constantize('C::B') }.to raise_error(NameError)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'does not resolve constant in a different parent module' do
|
42
|
+
expect { subject.constantize('D') }.to raise_error(NameError)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'resolves same leaf constants specific to their parents' do
|
46
|
+
expect(subject.constantize('A::E')).to eq(::A::E)
|
47
|
+
expect(subject.constantize('C::E')).to eq(::C::E)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'does not resolve constant without its parent' do
|
51
|
+
expect { subject.constantize('F') }.to raise_error(NameError)
|
52
|
+
end
|
53
|
+
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
|
-
|
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
|
-
|
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(
|
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.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Ruggio
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-13 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.
|
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.
|
32
|
+
version: 1.2.0
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: dry-inflector
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,14 +78,14 @@ dependencies:
|
|
78
78
|
requirements:
|
79
79
|
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '13'
|
82
82
|
type: :development
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
86
|
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
88
|
+
version: '13'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rspec
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,14 +106,14 @@ dependencies:
|
|
106
106
|
requirements:
|
107
107
|
- - "~>"
|
108
108
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.
|
109
|
+
version: 0.88.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.
|
116
|
+
version: 0.88.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.
|
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.
|
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,8 +166,10 @@ 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
|
+
- lib/dbee/constant_resolver.rb
|
172
173
|
- lib/dbee/dsl/association.rb
|
173
174
|
- lib/dbee/dsl/association_builder.rb
|
174
175
|
- lib/dbee/dsl/methods.rb
|
@@ -203,6 +204,7 @@ files:
|
|
203
204
|
- lib/dbee/query/sorters/descending.rb
|
204
205
|
- lib/dbee/version.rb
|
205
206
|
- spec/dbee/base_spec.rb
|
207
|
+
- spec/dbee/constant_resolver_spec.rb
|
206
208
|
- spec/dbee/key_chain_spec.rb
|
207
209
|
- spec/dbee/key_path_spec.rb
|
208
210
|
- spec/dbee/model/constraints/base_spec.rb
|
@@ -225,7 +227,12 @@ files:
|
|
225
227
|
homepage: https://github.com/bluemarblepayroll/dbee
|
226
228
|
licenses:
|
227
229
|
- MIT
|
228
|
-
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
|
229
236
|
post_install_message:
|
230
237
|
rdoc_options: []
|
231
238
|
require_paths:
|
@@ -234,7 +241,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
234
241
|
requirements:
|
235
242
|
- - ">="
|
236
243
|
- !ruby/object:Gem::Version
|
237
|
-
version: 2.
|
244
|
+
version: '2.5'
|
238
245
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
239
246
|
requirements:
|
240
247
|
- - ">="
|
@@ -247,6 +254,7 @@ specification_version: 4
|
|
247
254
|
summary: Adhoc Reporting SQL Generator
|
248
255
|
test_files:
|
249
256
|
- spec/dbee/base_spec.rb
|
257
|
+
- spec/dbee/constant_resolver_spec.rb
|
250
258
|
- spec/dbee/key_chain_spec.rb
|
251
259
|
- spec/dbee/key_path_spec.rb
|
252
260
|
- spec/dbee/model/constraints/base_spec.rb
|