dbee 1.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +8 -0
  3. data/.gitignore +6 -0
  4. data/.rubocop.yml +23 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +26 -0
  7. data/CHANGELOG.md +7 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +16 -0
  11. data/LICENSE +7 -0
  12. data/README.md +368 -0
  13. data/Rakefile +15 -0
  14. data/bin/console +18 -0
  15. data/dbee.gemspec +33 -0
  16. data/lib/dbee/base.rb +109 -0
  17. data/lib/dbee/model/constraints/base.rb +36 -0
  18. data/lib/dbee/model/constraints/reference.rb +42 -0
  19. data/lib/dbee/model/constraints/static.rb +40 -0
  20. data/lib/dbee/model/constraints.rb +26 -0
  21. data/lib/dbee/model.rb +79 -0
  22. data/lib/dbee/providers/null_provider.rb +21 -0
  23. data/lib/dbee/providers.rb +10 -0
  24. data/lib/dbee/query/field.rb +41 -0
  25. data/lib/dbee/query/filters/base.rb +39 -0
  26. data/lib/dbee/query/filters/contains.rb +19 -0
  27. data/lib/dbee/query/filters/equals.rb +19 -0
  28. data/lib/dbee/query/filters/greater_than.rb +19 -0
  29. data/lib/dbee/query/filters/greater_than_or_equal_to.rb +19 -0
  30. data/lib/dbee/query/filters/less_than.rb +19 -0
  31. data/lib/dbee/query/filters/less_than_or_equal_to.rb +19 -0
  32. data/lib/dbee/query/filters/not_contain.rb +19 -0
  33. data/lib/dbee/query/filters/not_equals.rb +19 -0
  34. data/lib/dbee/query/filters/not_start_with.rb +19 -0
  35. data/lib/dbee/query/filters/starts_with.rb +19 -0
  36. data/lib/dbee/query/filters.rb +40 -0
  37. data/lib/dbee/query/key_path.rb +54 -0
  38. data/lib/dbee/query/sorter.rb +53 -0
  39. data/lib/dbee/query.rb +45 -0
  40. data/lib/dbee/version.rb +12 -0
  41. data/lib/dbee.rb +28 -0
  42. data/spec/dbee/base_spec.rb +35 -0
  43. data/spec/dbee/model/constraints/base_spec.rb +42 -0
  44. data/spec/dbee/model/constraints/reference_spec.rb +37 -0
  45. data/spec/dbee/model/constraints/static_spec.rb +29 -0
  46. data/spec/dbee/model/constraints_spec.rb +25 -0
  47. data/spec/dbee/model_spec.rb +113 -0
  48. data/spec/dbee/providers/null_provider_spec.rb +22 -0
  49. data/spec/dbee/query/field_spec.rb +42 -0
  50. data/spec/dbee/query/filters/base_spec.rb +42 -0
  51. data/spec/dbee/query/filters_spec.rb +33 -0
  52. data/spec/dbee/query/key_path_spec.rb +35 -0
  53. data/spec/dbee/query/sorter_spec.rb +72 -0
  54. data/spec/dbee/query_spec.rb +94 -0
  55. data/spec/dbee_spec.rb +60 -0
  56. data/spec/fixtures/models.rb +115 -0
  57. data/spec/fixtures/models.yaml +101 -0
  58. data/spec/spec_helper.rb +52 -0
  59. metadata +239 -0
@@ -0,0 +1,72 @@
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::Query::Sorter do
13
+ it 'should act as hashable' do
14
+ expect(described_class).to respond_to(:make)
15
+ expect(described_class).to respond_to(:array)
16
+ end
17
+
18
+ context '#initialize' do
19
+ specify 'key_path is required' do
20
+ expect { described_class.new(key_path: '') }.to raise_error(ArgumentError)
21
+ expect { described_class.new(key_path: nil) }.to raise_error(ArgumentError)
22
+ expect { described_class.new }.to raise_error(ArgumentError)
23
+ end
24
+ end
25
+
26
+ context 'equality' do
27
+ let(:config) { { key_path: 'a.b.c', direction: :descending } }
28
+
29
+ subject { described_class.new(config) }
30
+
31
+ specify '#hash produces same output as concatenated string hash of key_path and direction' do
32
+ expect(subject.hash).to eq("#{config[:key_path]}#{config[:direction]}".hash)
33
+ end
34
+
35
+ specify '#== and #eql? compare attributes' do
36
+ object2 = described_class.new(config)
37
+
38
+ expect(subject).to eq(object2)
39
+ expect(subject).to eql(object2)
40
+ end
41
+ end
42
+
43
+ describe 'direction helpers' do
44
+ context 'when direction is ascending' do
45
+ let(:config) { { key_path: 'a.b.c' } }
46
+
47
+ subject { described_class.new(config) }
48
+
49
+ it '#ascending? is true' do
50
+ expect(subject.ascending?).to be true
51
+ end
52
+
53
+ it '#descending? is false' do
54
+ expect(subject.descending?).to be false
55
+ end
56
+ end
57
+
58
+ context 'when direction is descending' do
59
+ let(:config) { { key_path: 'a.b.c', direction: :descending } }
60
+
61
+ subject { described_class.new(config) }
62
+
63
+ it '#ascending? is false' do
64
+ expect(subject.ascending?).to be false
65
+ end
66
+
67
+ it '#descending? is true' do
68
+ expect(subject.descending?).to be true
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,94 @@
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::Query do
13
+ let(:config) do
14
+ {
15
+ fields: [
16
+ { key_path: 'matt.nick.sam', display: 'some display' },
17
+ { key_path: 'katie' },
18
+ { key_path: 'jordan.pippen' }
19
+ ],
20
+ sorters: [
21
+ { key_path: :sort_me },
22
+ { key_path: :sort_me_too, direction: :descending }
23
+ ],
24
+ limit: 125
25
+ }
26
+ end
27
+
28
+ subject { described_class.make(config) }
29
+
30
+ specify '#eql? compares attributes' do
31
+ expect(subject).to eq(described_class.make(config))
32
+ end
33
+
34
+ context 'README examples' do
35
+ EXAMPLES = {
36
+ 'Get all practices' => {
37
+ fields: [
38
+ { key_path: 'id' },
39
+ { key_path: 'active' },
40
+ { key_path: 'name' }
41
+ ]
42
+ },
43
+ 'Get all practices, limit to 10, and sort by name (descending) then id (ascending)' => {
44
+ fields: [
45
+ { key_path: 'id' },
46
+ { key_path: 'active' },
47
+ { key_path: 'name' }
48
+ ],
49
+ sorters: [
50
+ { key_path: 'name', direction: :descending },
51
+ { key_path: 'id' }
52
+ ],
53
+ limit: 10
54
+ },
55
+ "Get top 5 active practices and patient whose name start with 'Sm':" => {
56
+ fields: [
57
+ { key_path: 'name', display: 'Practice Name' },
58
+ { key_path: 'patients.first', display: 'Patient First Name' },
59
+ { key_path: 'patients.middle', display: 'Patient Middle Name' },
60
+ { key_path: 'patients.last', display: 'Patient Last Name' }
61
+ ],
62
+ filters: [
63
+ { type: :equals, key_path: 'active', value: true },
64
+ { type: :starts_with, key_path: 'patients.last', value: 'Sm' }
65
+ ],
66
+ limit: 5
67
+ },
68
+ 'Get practice IDs, patient IDs, names, and cell phone numbers that starts with 555' => {
69
+ fields: [
70
+ { key_path: 'id', display: 'Practice ID #' },
71
+ { key_path: 'patients.id', display: 'Patient ID #' },
72
+ { key_path: 'patients.first', display: 'Patient First Name' },
73
+ { key_path: 'patients.middle', display: 'Patient Middle Name' },
74
+ { key_path: 'patients.last', display: 'Patient Last Name' },
75
+ { key_path: 'patients.cell_phone_numbers.phone_number', display: 'Patient Cell #' }
76
+ ],
77
+ filters: [
78
+ { type: :equals, key_path: 'active', value: true },
79
+ {
80
+ type: :starts_with,
81
+ key_path: 'patients.cell_phone_numbers.phone_number',
82
+ value: '555'
83
+ }
84
+ ]
85
+ }
86
+ }.freeze
87
+
88
+ EXAMPLES.each_pair do |name, query|
89
+ specify name do
90
+ expect(described_class.make(query)).to be_a(described_class)
91
+ end
92
+ end
93
+ end
94
+ end
data/spec/dbee_spec.rb ADDED
@@ -0,0 +1,60 @@
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
+ require 'fixtures/models'
12
+
13
+ describe Dbee do
14
+ describe '#sql' do
15
+ let(:provider) { Dbee::Providers::NullProvider.new }
16
+
17
+ let(:query) { {} }
18
+
19
+ it 'accepts a hash as a model and passes a Model instance to provider#sql' do
20
+ model = { name: 'something' }
21
+
22
+ expect(provider).to receive(:sql).with(Dbee::Model.make(model), Dbee::Query.make(query))
23
+
24
+ described_class.sql(model, query, provider)
25
+ end
26
+
27
+ it 'accepts a Dbee::Model instance as a model and passes a Model instance to provider#sql' do
28
+ model = Dbee::Model.make(name: 'something')
29
+
30
+ expect(provider).to receive(:sql).with(Dbee::Model.make(model), Dbee::Query.make(query))
31
+
32
+ described_class.sql(model, query, provider)
33
+ end
34
+
35
+ it 'accepts a Dbee::Base constant as a model and passes a Model instance to provider#sql' do
36
+ model = Models::Theaters
37
+
38
+ expect(provider).to receive(:sql).with(model.to_model, Dbee::Query.make(query))
39
+
40
+ described_class.sql(model, query, provider)
41
+ end
42
+
43
+ it 'accepts a Dbee::Query instance as a query and passes a Query instance to provider#sql' do
44
+ model = Models::Theaters
45
+ query = Dbee::Query.make(query)
46
+
47
+ expect(provider).to receive(:sql).with(model.to_model, Dbee::Query.make(query))
48
+
49
+ described_class.sql(model, query, provider)
50
+ end
51
+
52
+ it 'accepts a hash as a query and passes a Query instance to provider#sql' do
53
+ model = Models::Theaters
54
+
55
+ expect(provider).to receive(:sql).with(model.to_model, Dbee::Query.make(query))
56
+
57
+ described_class.sql(model, query, provider)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,115 @@
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 Models
11
+ class Movies < Dbee::Base
12
+ end
13
+
14
+ class PhoneNumbers < Dbee::Base
15
+ end
16
+
17
+ class Demographics < Dbee::Base
18
+ association :phone_numbers, model: PhoneNumbers,
19
+ constraints: {
20
+ type: :reference,
21
+ name: :demographic_id,
22
+ parent: :id
23
+ }
24
+ end
25
+
26
+ class MembersBase < Dbee::Base
27
+ association :demos, model: Demographics,
28
+ constraints: { type: :reference, name: :member_id, parent: :id }
29
+
30
+ association :movies, model: Movies,
31
+ constraints: { type: :reference, name: :member_id, parent: :id }
32
+ end
33
+
34
+ class Members < MembersBase
35
+ association :favorite_comic_movies, model: Movies, constraints: [
36
+ { type: :reference, name: :member_id, parent: :id },
37
+ { type: :static, name: :genre, value: 'comic' }
38
+ ]
39
+
40
+ association :favorite_mystery_movies, model: Movies, constraints: [
41
+ { type: :reference, name: :member_id, parent: :id },
42
+ { type: :static, name: :genre, value: 'mystery' }
43
+ ]
44
+
45
+ association :favorite_comedy_movies, model: Movies, constraints: [
46
+ { type: :reference, name: :member_id, parent: :id },
47
+ { type: :static, name: :genre, value: 'comedy' }
48
+ ]
49
+ end
50
+
51
+ class TheatersBase < Dbee::Base
52
+ end
53
+
54
+ class Theaters < TheatersBase
55
+ association :members, model: Members, constraints: [
56
+ { type: :reference, name: :tid, parent: :id },
57
+ { type: :reference, name: :partition, parent: :partition }
58
+ ]
59
+ end
60
+
61
+ class A < Dbee::Base
62
+ table 'table_set_to_a'
63
+ end
64
+
65
+ class B < A
66
+ table 'table_set_to_b'
67
+ end
68
+
69
+ class C < A
70
+ end
71
+
72
+ class D < A
73
+ table ''
74
+ end
75
+
76
+ class E < B
77
+ table 'table_set_to_e'
78
+ end
79
+ end
80
+
81
+ module ReadmeDataModels
82
+ class PhoneNumbers < Dbee::Base
83
+ table :phones
84
+ end
85
+
86
+ class Notes < Dbee::Base
87
+ end
88
+
89
+ class Patients < Dbee::Base
90
+ association :notes, model: Notes, constraints: {
91
+ type: :reference, name: :patient_id, parent: :id
92
+ }
93
+
94
+ association :work_phone_number, model: PhoneNumbers, constraints: [
95
+ { type: :reference, name: :patient_id, parent: :id },
96
+ { type: :static, name: :phone_number_type, value: 'work' }
97
+ ]
98
+
99
+ association :cell_phone_number, model: PhoneNumbers, constraints: [
100
+ { type: :reference, name: :patient_id, parent: :id },
101
+ { type: :static, name: :phone_number_type, value: 'cell' }
102
+ ]
103
+
104
+ association :fax_phone_number, model: PhoneNumbers, constraints: [
105
+ { type: :reference, name: :patient_id, parent: :id },
106
+ { type: :static, name: :phone_number_type, value: 'fax' }
107
+ ]
108
+ end
109
+
110
+ class Practices < Dbee::Base
111
+ association :patients, model: Patients, constraints: {
112
+ type: :reference, name: :practice_id, parent: :id
113
+ }
114
+ end
115
+ end
@@ -0,0 +1,101 @@
1
+ Theaters, Members, and Movies:
2
+ name: theaters
3
+ table: theaters
4
+ models:
5
+ - name: members
6
+ table: members
7
+ constraints:
8
+ - type: reference
9
+ parent: id
10
+ name: tid
11
+ - type: reference
12
+ parent: partition
13
+ name: partition
14
+ models:
15
+ - name: demos
16
+ table: demographics
17
+ constraints:
18
+ - type: reference
19
+ parent: id
20
+ name: member_id
21
+ models:
22
+ - name: phone_numbers
23
+ table: phone_numbers
24
+ constraints:
25
+ - type: reference
26
+ parent: id
27
+ name: demographic_id
28
+ - name: movies
29
+ table: movies
30
+ constraints:
31
+ - type: reference
32
+ parent: id
33
+ name: member_id
34
+ - name: favorite_comic_movies
35
+ table: movies
36
+ constraints:
37
+ - type: reference
38
+ parent: id
39
+ name: member_id
40
+ - type: static
41
+ name: genre
42
+ value: comic
43
+ - name: favorite_mystery_movies
44
+ table: movies
45
+ constraints:
46
+ - type: reference
47
+ parent: id
48
+ name: member_id
49
+ - type: static
50
+ name: genre
51
+ value: mystery
52
+ - name: favorite_comedy_movies
53
+ table: movies
54
+ constraints:
55
+ - type: reference
56
+ parent: id
57
+ name: member_id
58
+ - type: static
59
+ name: genre
60
+ value: comedy
61
+ Readme:
62
+ name: practices
63
+ models:
64
+ - name: patients
65
+ constraints:
66
+ - type: reference
67
+ name: practice_id
68
+ parent: id
69
+ models:
70
+ - name: notes
71
+ constraints:
72
+ - type: reference
73
+ name: patient_id
74
+ parent: id
75
+ - name: work_phone_number
76
+ table: phones
77
+ constraints:
78
+ - type: reference
79
+ name: patient_id
80
+ parent: id
81
+ - type: static
82
+ name: phone_number_type
83
+ value: work
84
+ - name: cell_phone_number
85
+ table: phones
86
+ constraints:
87
+ - type: reference
88
+ name: patient_id
89
+ parent: id
90
+ - type: static
91
+ name: phone_number_type
92
+ value: cell
93
+ - name: fax_phone_number
94
+ table: phones
95
+ constraints:
96
+ - type: reference
97
+ name: patient_id
98
+ parent: id
99
+ - type: static
100
+ name: phone_number_type
101
+ value: fax
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2018-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 'yaml'
11
+ require 'pry'
12
+
13
+ unless ENV['DISABLE_SIMPLECOV'] == 'true'
14
+ require 'simplecov'
15
+ require 'simplecov-console'
16
+
17
+ SimpleCov.formatter = SimpleCov::Formatter::Console
18
+ SimpleCov.start do
19
+ add_filter %r{\A/spec/}
20
+ end
21
+ end
22
+
23
+ require './lib/dbee'
24
+
25
+ def fixture_path(*filename)
26
+ File.join('spec', 'fixtures', filename)
27
+ end
28
+
29
+ def yaml_fixture(*filename)
30
+ YAML.safe_load(fixture(*filename))
31
+ end
32
+
33
+ def fixture(*filename)
34
+ File.open(fixture_path(*filename), 'r:bom|utf-8').read
35
+ end
36
+
37
+ def yaml_fixture_files(*directory)
38
+ Dir[File.join('spec', 'fixtures', *directory, '*.yaml')].map do |filename|
39
+ [
40
+ filename,
41
+ yaml_file_read(filename)
42
+ ]
43
+ end.to_h
44
+ end
45
+
46
+ def yaml_file_read(*filename)
47
+ YAML.safe_load(file_read(*filename))
48
+ end
49
+
50
+ def file_read(*filename)
51
+ File.open(File.join(*filename), 'r:bom|utf-8').read
52
+ end