dbee 1.0.0.pre.alpha → 1.0.0.pre.alpha.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3da5072dedecfdcd75c8f1478c3a4f60bf477af59a48005044dc0e839e3a85d
4
- data.tar.gz: 13bcece761321e1690907a05a87c257ad2829b9607152eab5d0f74f2b64605fa
3
+ metadata.gz: 985c6ab788915c22ed43fea867eb23d4dc4622a2457e814bbedbcd7c42f8d43a
4
+ data.tar.gz: ffbceb601e3be40c40f002eb36d8ebc7f2f401add22d18c8b4793de69330cc33
5
5
  SHA512:
6
- metadata.gz: 266465af7710306656ff8dc171a89c4f1f190c6d20e1959072a50bbead4e508ab4740f4c047ee187908a4414ee5b7e6f3fba66bbba8a0f2868a449165f4a1ff2
7
- data.tar.gz: '09f63b6d657888cbc33d637422632345980f44cd53a56995cdc470585291aa7f77d38c877e7fa6a9c654f3f3f61890ee7a88fddf53d9b349bdddac3d7ef80f89'
6
+ metadata.gz: 5a8c4b1974893e73ef057e947828305b4fcf6ea76733f88758b290b140c956c62a11a1a32de7bc9eb20d82cd70f38e052024bf78511daa2ee1913aae5307b7d1
7
+ data.tar.gz: 8b6212eda28dcd468bd2de7325fd635865831a0991a28a3784fad472b3f5fe719aceefa0b5200c0517cad08e47bc6380e0c9a244cf19e5715c51c05ee128ccd3
data/README.md CHANGED
@@ -115,6 +115,8 @@ module ReadmeDataModels
115
115
  end
116
116
 
117
117
  class Practices < Dbee::Base
118
+ boolean_column :active, nullable: false
119
+
118
120
  association :patients, model: Patients, constraints: {
119
121
  type: :reference, name: :practice_id, parent: :id
120
122
  }
@@ -123,7 +125,10 @@ end
123
125
 
124
126
  ````
125
127
 
126
- *Note: the 'table' directive is optional, and if omitted, the classes name will be turned into snake_case and used. In the above example you can see we wanted the class name of PhoneNumbers but the table is actually 'phones'*
128
+ A couple notes:
129
+
130
+ * the 'table' directive is optional, and if omitted, the classes name will be turned into snake_case and used. In the above example you can see we wanted the class name of PhoneNumbers but the table is actually 'phones'
131
+ * it is not required that all columns be explicitly defined but it does provide value coercion. By default, all undefined columns are of type Dbee::Model::Columns::Undefined.
127
132
 
128
133
  #### Configuration-First Data Modeling
129
134
 
@@ -131,6 +136,10 @@ You can choose to alternatively describe your data model using configuration. T
131
136
 
132
137
  ````yaml
133
138
  name: practices
139
+ columns:
140
+ - name: active
141
+ type: boolean
142
+ nullable: false
134
143
  models:
135
144
  - name: patients
136
145
  constraints:
data/lib/dbee/base.rb CHANGED
@@ -12,6 +12,10 @@ module Dbee
12
12
  # Model declaration.
13
13
  class Base
14
14
  class << self
15
+ def boolean_column(name, opts = {})
16
+ columns_by_name[name.to_s] = opts.merge(name: name, type: :boolean)
17
+ end
18
+
15
19
  def table(name)
16
20
  @table_name = name.to_s
17
21
 
@@ -35,6 +39,10 @@ module Dbee
35
39
  @table_name.to_s
36
40
  end
37
41
 
42
+ def columns_by_name
43
+ @columns_by_name ||= {}
44
+ end
45
+
38
46
  def associations_by_name
39
47
  @associations_by_name ||= {}
40
48
  end
@@ -47,6 +55,12 @@ module Dbee
47
55
  ''
48
56
  end
49
57
 
58
+ def inherited_columns_by_name
59
+ reversed_subclasses.each_with_object({}) do |subclass, memo|
60
+ memo.merge!(subclass.columns_by_name)
61
+ end
62
+ end
63
+
50
64
  def inherited_associations_by_name
51
65
  reversed_subclasses.each_with_object({}) do |subclass, memo|
52
66
  memo.merge!(subclass.associations_by_name)
@@ -65,6 +79,7 @@ module Dbee
65
79
 
66
80
  def model_config(name, constraints)
67
81
  {
82
+ columns: columns,
68
83
  constraints: constraints,
69
84
  models: associations,
70
85
  name: name,
@@ -82,6 +97,12 @@ module Dbee
82
97
  inherited_table.empty? ? inflected_name : inherited_table
83
98
  end
84
99
 
100
+ def columns
101
+ inherited_columns_by_name.values.each_with_object([]) do |config, memo|
102
+ memo << Model::Columns.make(config)
103
+ end
104
+ end
105
+
85
106
  def associations
86
107
  inherited_associations_by_name.values.each_with_object([]) do |config, memo|
87
108
  model_klass = config[:model]
@@ -0,0 +1,63 @@
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_relative 'undefined'
11
+
12
+ module Dbee
13
+ class Model
14
+ class Columns
15
+ # Describes a boolean column. The main value here is the value is pretty pliable.
16
+ # For example: the value 'y' or '1' will be coerced to true.
17
+ class Boolean < Undefined
18
+ attr_reader :nullable
19
+
20
+ alias nullable? nullable
21
+
22
+ def initialize(name:, nullable: true)
23
+ super(name: name)
24
+
25
+ @nullable = nullable
26
+
27
+ freeze
28
+ end
29
+
30
+ def ==(other)
31
+ super && other.nullable == nullable
32
+ end
33
+ alias eql? ==
34
+
35
+ def coerce(value)
36
+ if nullable? && nully?(value)
37
+ nil
38
+ elsif truthy?(value)
39
+ true
40
+ else
41
+ false
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def null_or_empty?(val)
48
+ val.nil? || val.to_s.empty?
49
+ end
50
+
51
+ # rubocop:disable Style/DoubleNegation
52
+ def nully?(val)
53
+ null_or_empty?(val) || !!(val.to_s =~ /(nil|null)$/i)
54
+ end
55
+
56
+ def truthy?(val)
57
+ !!(val.to_s =~ /(true|t|yes|y|1)$/i)
58
+ end
59
+ # rubocop:enable Style/DoubleNegation
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,37 @@
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
+ class Model
12
+ class Columns
13
+ # Any non-configured column will automatically be this type.
14
+ # Also doubles as the base class for all columns specification subclasses.
15
+ class Undefined
16
+ acts_as_hashable
17
+
18
+ attr_reader :name
19
+
20
+ def initialize(name:)
21
+ raise ArgumentError, 'name is required' if name.to_s.empty?
22
+
23
+ @name = name.to_s
24
+ end
25
+
26
+ def coerce(value)
27
+ value
28
+ end
29
+
30
+ def ==(other)
31
+ other.name == name
32
+ end
33
+ alias eql? ==
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
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_relative 'columns/boolean'
11
+ require_relative 'columns/undefined'
12
+
13
+ module Dbee
14
+ class Model
15
+ # Top-level class that allows for the making of columns. For example, you can call this as:
16
+ # - Columns.make(type: :boolean, name: :something)
17
+ # - Columns.make(type: :undefined, name: :something_else)
18
+ class Columns
19
+ acts_as_hashable_factory
20
+
21
+ register 'boolean', Boolean
22
+ register 'undefined', Undefined
23
+ end
24
+ end
25
+ end
data/lib/dbee/model.rb CHANGED
@@ -7,6 +7,7 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
+ require_relative 'model/columns'
10
11
  require_relative 'model/constraints'
11
12
 
12
13
  module Dbee
@@ -21,10 +22,11 @@ module Dbee
21
22
 
22
23
  attr_reader :constraints, :name
23
24
 
24
- def initialize(name:, constraints: [], models: [], table: '')
25
+ def initialize(name:, columns: [], constraints: [], models: [], table: '')
25
26
  raise ArgumentError, 'name is required' if name.to_s.empty?
26
27
 
27
28
  @name = name.to_s
29
+ @columns_by_name = name_hash(Columns.array(columns))
28
30
  @constraints = Constraints.array(constraints)
29
31
  @models_by_name = name_hash(Model.array(models))
30
32
  @table = table.to_s
@@ -44,6 +46,14 @@ module Dbee
44
46
  models_by_name.values
45
47
  end
46
48
 
49
+ def columns
50
+ columns_by_name.values
51
+ end
52
+
53
+ def column(name)
54
+ columns_by_name[name.to_s] || Columns::Undefined.new(name: name)
55
+ end
56
+
47
57
  def ancestors(parts = [], alias_chain = [], found = {})
48
58
  return found if Array(parts).empty?
49
59
 
@@ -68,12 +78,13 @@ module Dbee
68
78
  other.name == name &&
69
79
  other.table == table &&
70
80
  other.models == models &&
71
- other.constraints == constraints
81
+ other.constraints == constraints &&
82
+ other.columns == columns
72
83
  end
73
84
  alias eql? ==
74
85
 
75
86
  private
76
87
 
77
- attr_reader :models_by_name
88
+ attr_reader :models_by_name, :columns_by_name
78
89
  end
79
90
  end
data/lib/dbee/version.rb CHANGED
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Dbee
11
- VERSION = '1.0.0-alpha'
11
+ VERSION = '1.0.0-alpha.1'
12
12
  end
@@ -0,0 +1,74 @@
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
+ # frozen_string_literal: true
11
+
12
+ #
13
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
14
+ #
15
+ # This source code is licensed under the MIT license found in the
16
+ # LICENSE file in the root directory of this source tree.
17
+ #
18
+
19
+ require 'spec_helper'
20
+
21
+ describe Dbee::Model::Columns::Boolean do
22
+ specify 'equality compares attributes' do
23
+ config = {
24
+ name: :a,
25
+ nullable: false
26
+ }
27
+
28
+ column1 = described_class.make(config)
29
+ column2 = described_class.make(config)
30
+
31
+ expect(column1).to eq(column2)
32
+ expect(column1).to eql(column2)
33
+ end
34
+
35
+ describe '#coerce' do
36
+ context 'when not nullable and value is a string' do
37
+ subject { described_class.make(name: :active, nullable: false) }
38
+
39
+ %w[y Y yes YES Yes yEs t True TRUE T TrUe 1].each do |value|
40
+ it "converts #{value} to true" do
41
+ expect(subject.coerce(value)).to be true
42
+ end
43
+ end
44
+
45
+ %w[n N no NO No nO f F FALSE 0 nil null Nil Null NULL NIL].each do |value|
46
+ it "converts #{value} to true" do
47
+ expect(subject.coerce(value)).to be false
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'when nullable and value is a string' do
53
+ subject { described_class.make(name: :active, nullable: true) }
54
+
55
+ %w[y Y yes YES Yes yEs t True TRUE T TrUe 1].each do |value|
56
+ it "converts #{value} to true" do
57
+ expect(subject.coerce(value)).to be true
58
+ end
59
+ end
60
+
61
+ %w[n N no NO No nO f F FALSE 0].each do |value|
62
+ it "converts #{value} to true" do
63
+ expect(subject.coerce(value)).to be false
64
+ end
65
+ end
66
+
67
+ %w[nil null Nil Null NULL NIL].each do |value|
68
+ it "converts #{value} to true" do
69
+ expect(subject.coerce(value)).to be nil
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,38 @@
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
+ # frozen_string_literal: true
11
+
12
+ #
13
+ # Copyright (c) 2019-present, Blue Marble Payroll, LLC
14
+ #
15
+ # This source code is licensed under the MIT license found in the
16
+ # LICENSE file in the root directory of this source tree.
17
+ #
18
+
19
+ require 'spec_helper'
20
+
21
+ describe Dbee::Model::Columns::Undefined do
22
+ let(:config) { { name: :some_column } }
23
+
24
+ subject { described_class.make(config) }
25
+
26
+ specify 'equality compares attributes' do
27
+ column1 = described_class.make(config)
28
+ column2 = described_class.make(config)
29
+
30
+ expect(column1).to eq(column2)
31
+ expect(column1).to eql(column2)
32
+ end
33
+
34
+ specify '#coerce returns value' do
35
+ value = 'abc123'
36
+ expect(subject.coerce(value)).to eq(value)
37
+ end
38
+ end
@@ -10,14 +10,14 @@
10
10
  require 'spec_helper'
11
11
 
12
12
  describe Dbee::Model::Constraints do
13
- CONFIG = { name: :a }.freeze
13
+ CONSTRAINT_CONFIG = { name: :a }.freeze
14
14
 
15
- FACTORIES = {
16
- Dbee::Model::Constraints::Reference => CONFIG.merge(parent: :b, type: :reference),
17
- Dbee::Model::Constraints::Static => CONFIG.merge(value: :b, type: :static)
15
+ CONSTRAINT_FACTORIES = {
16
+ Dbee::Model::Constraints::Reference => CONSTRAINT_CONFIG.merge(parent: :b, type: :reference),
17
+ Dbee::Model::Constraints::Static => CONSTRAINT_CONFIG.merge(value: :b, type: :static)
18
18
  }.freeze
19
19
 
20
- FACTORIES.each_pair do |constant, config|
20
+ CONSTRAINT_FACTORIES.each_pair do |constant, config|
21
21
  it "should instantiate #{constant} objects" do
22
22
  expect(described_class.make(config)).to be_a(constant)
23
23
  end
@@ -55,6 +55,28 @@ describe Dbee::Model do
55
55
  end
56
56
  end
57
57
 
58
+ describe '#column' do
59
+ let(:yaml_entities) { yaml_fixture('models.yaml') }
60
+
61
+ let(:entity_hash) { yaml_entities['Theaters, Members, and Movies'] }
62
+
63
+ subject { described_class.make(entity_hash) }
64
+
65
+ specify 'returns column instance if it exists' do
66
+ expected = Dbee::Model::Columns::Boolean.make(name: 'active', nullable: false)
67
+ expect(subject.column('active')).to eq(expected)
68
+
69
+ expected = Dbee::Model::Columns::Boolean.make(name: 'inspected', nullable: true)
70
+ expect(subject.column('inspected')).to eq(expected)
71
+ end
72
+
73
+ specify 'returns unknown column instance if it does not exist' do
74
+ expected = Dbee::Model::Columns::Boolean.make(name: 'doesnt_exist')
75
+
76
+ expect(subject.column('doesnt_exist')).to eq(expected)
77
+ end
78
+ end
79
+
58
80
  describe '#ancestors' do
59
81
  let(:yaml_entities) { yaml_fixture('models.yaml') }
60
82
 
@@ -10,22 +10,24 @@
10
10
  require 'spec_helper'
11
11
 
12
12
  describe Dbee::Query::Filters do
13
- CONFIG = { key_path: 'a.b.c', value: :d }.freeze
13
+ FILTERS_CONFIG = { key_path: 'a.b.c', value: :d }.freeze
14
14
 
15
- FACTORIES = {
16
- Dbee::Query::Filters::Contains => CONFIG.merge(type: :contains),
17
- Dbee::Query::Filters::Equals => CONFIG.merge(type: :equals),
18
- Dbee::Query::Filters::GreaterThanOrEqualTo => CONFIG.merge(type: :greater_than_or_equal_to),
19
- Dbee::Query::Filters::GreaterThan => CONFIG.merge(type: :greater_than),
20
- Dbee::Query::Filters::LessThanOrEqualTo => CONFIG.merge(type: :less_than_or_equal_to),
21
- Dbee::Query::Filters::LessThan => CONFIG.merge(type: :less_than),
22
- Dbee::Query::Filters::NotContain => CONFIG.merge(type: :not_contain),
23
- Dbee::Query::Filters::NotEquals => CONFIG.merge(type: :not_equals),
24
- Dbee::Query::Filters::NotStartWith => CONFIG.merge(type: :not_start_with),
25
- Dbee::Query::Filters::StartsWith => CONFIG.merge(type: :starts_with)
15
+ FILTER_FACTORIES = {
16
+ Dbee::Query::Filters::Contains => FILTERS_CONFIG.merge(type: :contains),
17
+ Dbee::Query::Filters::Equals => FILTERS_CONFIG.merge(type: :equals),
18
+ Dbee::Query::Filters::GreaterThanOrEqualTo => FILTERS_CONFIG.merge(
19
+ type: :greater_than_or_equal_to
20
+ ),
21
+ Dbee::Query::Filters::GreaterThan => FILTERS_CONFIG.merge(type: :greater_than),
22
+ Dbee::Query::Filters::LessThanOrEqualTo => FILTERS_CONFIG.merge(type: :less_than_or_equal_to),
23
+ Dbee::Query::Filters::LessThan => FILTERS_CONFIG.merge(type: :less_than),
24
+ Dbee::Query::Filters::NotContain => FILTERS_CONFIG.merge(type: :not_contain),
25
+ Dbee::Query::Filters::NotEquals => FILTERS_CONFIG.merge(type: :not_equals),
26
+ Dbee::Query::Filters::NotStartWith => FILTERS_CONFIG.merge(type: :not_start_with),
27
+ Dbee::Query::Filters::StartsWith => FILTERS_CONFIG.merge(type: :starts_with)
26
28
  }.freeze
27
29
 
28
- FACTORIES.each_pair do |constant, config|
30
+ FILTER_FACTORIES.each_pair do |constant, config|
29
31
  it "should instantiate #{constant} objects" do
30
32
  expect(described_class.make(config)).to be_a(constant)
31
33
  end
@@ -49,9 +49,12 @@ module Models
49
49
  end
50
50
 
51
51
  class TheatersBase < Dbee::Base
52
+ boolean_column :active, nullable: false
52
53
  end
53
54
 
54
55
  class Theaters < TheatersBase
56
+ boolean_column :inspected
57
+
55
58
  association :members, model: Members, constraints: [
56
59
  { type: :reference, name: :tid, parent: :id },
57
60
  { type: :reference, name: :partition, parent: :partition }
@@ -108,6 +111,8 @@ module ReadmeDataModels
108
111
  end
109
112
 
110
113
  class Practices < Dbee::Base
114
+ boolean_column :active, nullable: false
115
+
111
116
  association :patients, model: Patients, constraints: {
112
117
  type: :reference, name: :practice_id, parent: :id
113
118
  }
@@ -1,6 +1,12 @@
1
1
  Theaters, Members, and Movies:
2
2
  name: theaters
3
3
  table: theaters
4
+ columns:
5
+ - name: active
6
+ type: boolean
7
+ nullable: false
8
+ - name: inspected
9
+ type: boolean # this one is nullable
4
10
  models:
5
11
  - name: members
6
12
  table: members
@@ -60,6 +66,10 @@ Theaters, Members, and Movies:
60
66
  value: comedy
61
67
  Readme:
62
68
  name: practices
69
+ columns:
70
+ - name: active
71
+ type: boolean
72
+ nullable: false
63
73
  models:
64
74
  - name: patients
65
75
  constraints:
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: 1.0.0.pre.alpha
4
+ version: 1.0.0.pre.alpha.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-19 00:00:00.000000000 Z
11
+ date: 2019-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -156,6 +156,9 @@ files:
156
156
  - lib/dbee.rb
157
157
  - lib/dbee/base.rb
158
158
  - lib/dbee/model.rb
159
+ - lib/dbee/model/columns.rb
160
+ - lib/dbee/model/columns/boolean.rb
161
+ - lib/dbee/model/columns/undefined.rb
159
162
  - lib/dbee/model/constraints.rb
160
163
  - lib/dbee/model/constraints/base.rb
161
164
  - lib/dbee/model/constraints/reference.rb
@@ -180,6 +183,8 @@ files:
180
183
  - lib/dbee/query/sorter.rb
181
184
  - lib/dbee/version.rb
182
185
  - spec/dbee/base_spec.rb
186
+ - spec/dbee/model/columns/boolean_spec.rb
187
+ - spec/dbee/model/columns/undefined_spec.rb
183
188
  - spec/dbee/model/constraints/base_spec.rb
184
189
  - spec/dbee/model/constraints/reference_spec.rb
185
190
  - spec/dbee/model/constraints/static_spec.rb
@@ -221,6 +226,8 @@ specification_version: 4
221
226
  summary: Adhoc Reporting SQL Generator
222
227
  test_files:
223
228
  - spec/dbee/base_spec.rb
229
+ - spec/dbee/model/columns/boolean_spec.rb
230
+ - spec/dbee/model/columns/undefined_spec.rb
224
231
  - spec/dbee/model/constraints/base_spec.rb
225
232
  - spec/dbee/model/constraints/reference_spec.rb
226
233
  - spec/dbee/model/constraints/static_spec.rb