dbee 1.0.0.pre.alpha → 1.0.0.pre.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
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