dbee 2.0.1 → 2.1.1
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 +42 -0
- data/README.md +139 -0
- 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 -24
- 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
- data/spec/dbee/query_spec.rb +0 -8
- 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: b3c9c1444028bdfd5a4aa9eeb8c98055184f1b2cec2b819376e3f5344850d3b9
|
4
|
+
data.tar.gz: '059ac6adca29bae5a1eb0fc9f13247159047f1e8c82b3b31398d4492913ef595'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f67474cd84508029e3f3ca6e91ee2a1192b3cb1f8bf36f6b2d18a9c51e75ba3af897b01ea16676c6c79b000bd8d44d1381a7785fa56a9b81b906d47332e1c687
|
7
|
+
data.tar.gz: 6d6d061db4ef0c39cc1af32368d725c8354af5fc143a562f10e3beed7c3d260f7ddc93ab2aaff6016c483f370e9ccfec5e54c72dffcb8044c723025cb40dfdb5
|
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,45 @@
|
|
1
|
+
# 2.1.1 (July 14th, 2020)
|
2
|
+
|
3
|
+
* Removed guard that ensured a query has at least one field to establish a more rational base-case.
|
4
|
+
|
5
|
+
# 2.1.0 (July 13th, 2020)
|
6
|
+
|
7
|
+
### Additions:
|
8
|
+
|
9
|
+
* Added Dbee::Query::Field#aggregator (such as ave, min, max, sum, etc.)
|
10
|
+
* Added Dbee::Query::Field#filters (allows for doing select column filtering)
|
11
|
+
|
12
|
+
### Changes:
|
13
|
+
|
14
|
+
* Bumped minimum Ruby version to 2.5
|
15
|
+
|
16
|
+
# 2.0.3 (January 7th, 2020)
|
17
|
+
|
18
|
+
### Fixes:
|
19
|
+
|
20
|
+
* 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:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
class A; end
|
24
|
+
|
25
|
+
module B
|
26
|
+
class A; end
|
27
|
+
class C; end
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
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`.
|
32
|
+
|
33
|
+
# 2.0.2 (November 7th, 2019)
|
34
|
+
|
35
|
+
### Additions:
|
36
|
+
|
37
|
+
* 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.
|
38
|
+
|
39
|
+
### Fixes:
|
40
|
+
|
41
|
+
* 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.
|
42
|
+
|
1
43
|
# 2.0.0 (September 3rd, 2019)
|
2
44
|
|
3
45
|
### Additions:
|
data/README.md
CHANGED
@@ -363,6 +363,22 @@ You execute a Query against a Data Model, using a Provider. The sample provider
|
|
363
363
|
|
364
364
|
Here are some sample executions based off the preceding examples:
|
365
365
|
|
366
|
+
##### Base Case
|
367
|
+
|
368
|
+
If a query has no fields then it is implied you would like all fields on the root table. For example:
|
369
|
+
|
370
|
+
````ruby
|
371
|
+
require 'dbee/providers/active_record_provider'
|
372
|
+
|
373
|
+
class Practice < Dbee::Base; end
|
374
|
+
|
375
|
+
provider = Dbee::Providers::ActiveRecordProvider.new
|
376
|
+
query = {}
|
377
|
+
sql = Dbee.sql(Practice, query, provider)
|
378
|
+
````
|
379
|
+
|
380
|
+
It equivalent to saying: `SELECT practices.* FROM practices`. This helps to establish a deterministic base-case: it returns the same implicit columns that is independent of sql joins (sorters and/or filters may require sql joins.)
|
381
|
+
|
366
382
|
##### Code-First Execution
|
367
383
|
|
368
384
|
````ruby
|
@@ -407,6 +423,129 @@ sql = Dbee.sql(model, query, provider)
|
|
407
423
|
|
408
424
|
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
425
|
|
426
|
+
#### Aggregation
|
427
|
+
|
428
|
+
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:
|
429
|
+
|
430
|
+
**Data Model**:
|
431
|
+
|
432
|
+
````yaml
|
433
|
+
name: practice
|
434
|
+
models:
|
435
|
+
- name: patients
|
436
|
+
constraints:
|
437
|
+
- type: reference
|
438
|
+
name: practice_id
|
439
|
+
parent: id
|
440
|
+
````
|
441
|
+
|
442
|
+
**Query**:
|
443
|
+
|
444
|
+
````ruby
|
445
|
+
query = {
|
446
|
+
fields: [
|
447
|
+
{
|
448
|
+
key_path: 'id',
|
449
|
+
display: 'Practice ID #',
|
450
|
+
},
|
451
|
+
{
|
452
|
+
key_path: 'name',
|
453
|
+
display: 'Practice Name',
|
454
|
+
},
|
455
|
+
{
|
456
|
+
key_path: 'patients.id',
|
457
|
+
display: 'Total Patients',
|
458
|
+
aggregator: :count
|
459
|
+
},
|
460
|
+
]
|
461
|
+
````
|
462
|
+
|
463
|
+
An example of a materialized result would be something akin to:
|
464
|
+
|
465
|
+
Practice ID # | Practice Name | Total Patients
|
466
|
+
------------- | --------------- | --------------
|
467
|
+
1 | Families Choice | 293
|
468
|
+
2 | Awesome Choice | 2305
|
469
|
+
3 | Best Value | 1200
|
470
|
+
|
471
|
+
A complete list of aggregator values can be found by inspecting the `Dbee::Query::Field::Aggregator` constant.
|
472
|
+
|
473
|
+
#### Field/Column Level Filtering & Pivoting
|
474
|
+
|
475
|
+
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:
|
476
|
+
|
477
|
+
**Data/Schema Example**:
|
478
|
+
|
479
|
+
patients:
|
480
|
+
|
481
|
+
id | first | last
|
482
|
+
-- | ----- | -----
|
483
|
+
1 | frank | rizzo
|
484
|
+
|
485
|
+
patient_fields:
|
486
|
+
|
487
|
+
id | patient_id | key | value
|
488
|
+
-- | ---------- | --------------- | -----
|
489
|
+
1 | 1 | dob | 1900-01-01
|
490
|
+
2 | 1 | drivers_license | ABC123
|
491
|
+
|
492
|
+
**Model Configuration**:
|
493
|
+
|
494
|
+
````yaml
|
495
|
+
name: patients
|
496
|
+
models:
|
497
|
+
- name: patient_fields
|
498
|
+
constraints:
|
499
|
+
- type: reference
|
500
|
+
parent: id
|
501
|
+
name: patient_id
|
502
|
+
````
|
503
|
+
|
504
|
+
**Query**:
|
505
|
+
|
506
|
+
````ruby
|
507
|
+
query = {
|
508
|
+
fields: [
|
509
|
+
{
|
510
|
+
key_path: 'id',
|
511
|
+
display: 'ID #'
|
512
|
+
},
|
513
|
+
{
|
514
|
+
key_path: 'first',
|
515
|
+
display: 'First Name'
|
516
|
+
},
|
517
|
+
{
|
518
|
+
aggregator: :max,
|
519
|
+
key_path: 'patient_fields.value',
|
520
|
+
display: 'Date of Birth',
|
521
|
+
filters: [
|
522
|
+
{
|
523
|
+
key_path: 'patient_fields.key',
|
524
|
+
value: 'dob'
|
525
|
+
}
|
526
|
+
]
|
527
|
+
},
|
528
|
+
{
|
529
|
+
aggregator: :max,
|
530
|
+
key_path: 'patient_fields.value',
|
531
|
+
display: 'Drivers License #',
|
532
|
+
filters: [
|
533
|
+
{
|
534
|
+
key_path: 'patient_fields.key',
|
535
|
+
value: 'drivers_license'
|
536
|
+
}
|
537
|
+
]
|
538
|
+
}
|
539
|
+
}
|
540
|
+
}
|
541
|
+
````
|
542
|
+
|
543
|
+
Executing the query above against the data and model would yield:
|
544
|
+
|
545
|
+
ID # | First Name | Date of Birth | Drivers License #
|
546
|
+
-- | ---------- | ------------- | -----------------
|
547
|
+
1 | frank | 1900-01-01 | ABC123
|
548
|
+
|
410
549
|
|
411
550
|
## Contributing
|
412
551
|
|
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
37
|
s.add_development_dependency('rake', '~> 13')
|
30
38
|
s.add_development_dependency('rspec')
|
31
|
-
s.add_development_dependency('rubocop', '~>0.
|
32
|
-
s.add_development_dependency('simplecov', '~>0.
|
33
|
-
s.add_development_dependency('simplecov-console', '~>0.
|
39
|
+
s.add_development_dependency('rubocop', '~>0.88.0')
|
40
|
+
s.add_development_dependency('simplecov', '~>0.18.5')
|
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
@@ -21,37 +21,35 @@ module Dbee
|
|
21
21
|
extend Forwardable
|
22
22
|
acts_as_hashable
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def_delegator :filters,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@
|
43
|
-
@limit = limit.to_s.empty? ? nil : limit.to_i
|
44
|
-
@sorters = Sorters.array(sorters).uniq
|
24
|
+
attr_reader :fields,
|
25
|
+
:filters,
|
26
|
+
:limit,
|
27
|
+
:sorters
|
28
|
+
|
29
|
+
def_delegator :fields, :sort, :sorted_fields
|
30
|
+
def_delegator :filters, :sort, :sorted_filters
|
31
|
+
def_delegator :sorters, :sort, :sorted_sorters
|
32
|
+
|
33
|
+
def initialize(
|
34
|
+
fields: [],
|
35
|
+
filters: [],
|
36
|
+
limit: nil,
|
37
|
+
sorters: []
|
38
|
+
)
|
39
|
+
@fields = Field.array(fields)
|
40
|
+
@filters = Filters.array(filters).uniq
|
41
|
+
@limit = limit.to_s.empty? ? nil : limit.to_i
|
42
|
+
@sorters = Sorters.array(sorters).uniq
|
45
43
|
|
46
44
|
freeze
|
47
45
|
end
|
48
46
|
|
49
47
|
def ==(other)
|
50
48
|
other.instance_of?(self.class) &&
|
49
|
+
other.limit == limit &&
|
51
50
|
other.sorted_fields == sorted_fields &&
|
52
51
|
other.sorted_filters == sorted_filters &&
|
53
|
-
other.sorted_sorters == sorted_sorters
|
54
|
-
other.limit == limit
|
52
|
+
other.sorted_sorters == sorted_sorters
|
55
53
|
end
|
56
54
|
alias eql? ==
|
57
55
|
|
@@ -62,7 +60,11 @@ module Dbee
|
|
62
60
|
private
|
63
61
|
|
64
62
|
def key_paths
|
65
|
-
(
|
63
|
+
(
|
64
|
+
fields.flat_map(&:key_paths) +
|
65
|
+
filters.map(&:key_path) +
|
66
|
+
sorters.map(&:key_path)
|
67
|
+
)
|
66
68
|
end
|
67
69
|
end
|
68
70
|
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
|
data/spec/dbee/query_spec.rb
CHANGED
@@ -36,14 +36,6 @@ describe Dbee::Query do
|
|
36
36
|
end
|
37
37
|
|
38
38
|
describe '#initialize' do
|
39
|
-
it 'should raise an ArgumentError if fields keyword is missing' do
|
40
|
-
expect { described_class.new }.to raise_error(ArgumentError)
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'should raise a NoFieldsError if no fields were passed in' do
|
44
|
-
expect { described_class.new(fields: []) }.to raise_error(Dbee::Query::NoFieldsError)
|
45
|
-
end
|
46
|
-
|
47
39
|
it 'should remove duplicate filters (keep first instance)' do
|
48
40
|
query_hash = {
|
49
41
|
fields: [
|
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.1
|
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-14 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
|
@@ -106,50 +106,49 @@ 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
|
120
120
|
requirements:
|
121
121
|
- - "~>"
|
122
122
|
- !ruby/object:Gem::Version
|
123
|
-
version: 0.
|
123
|
+
version: 0.18.5
|
124
124
|
type: :development
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
128
|
- - "~>"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: 0.
|
130
|
+
version: 0.18.5
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
132
|
name: simplecov-console
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
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
|