dbee-active_record 2.1.0.pre.alpha.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75d42ea7f3b391ad5014264a4b914339bf7dff8582aebe85c4c3180576ae7648
4
- data.tar.gz: e63553d0dcc906a38b336767dfcf10bcc162807682ae866f4450a80185993b8e
3
+ metadata.gz: e71321e2f9366122dfbcc7bbfa5a18be43693e6d0c7eda44cf06221e646bef33
4
+ data.tar.gz: f59ad369064af84ba7cd387df7b0c072eb38bf6658d7342320e158e5d297c65a
5
5
  SHA512:
6
- metadata.gz: f727e65305615a6e5b2450654ce4bb174674970be4b6855922035dac6bc8378862a003f0c1ec4677433d560dee4f5ca3b9094b57a4be8eae6a7d78720c805910
7
- data.tar.gz: 21d91630d8ba8407550dcdd6d8a7aab9bc7dc52ad39679ed5b673f59263f2761e55505c61b8cafcc2ce09a31fee1571e58e9fffc76b24f1dd7a5d3d62e3b4ef7
6
+ metadata.gz: 6ad043966cba813e731ab4e7d53cf22fc359ec6a2000097b18719d0bf7a317c3521c8785999cfc99f31b5d091724337afad62ff62c02aca19f448d37989eecbc
7
+ data.tar.gz: eb496b07348bbb79a2cd97be2816ea696186ac8068172ca38f521d22343cf3f80f67c71bf99adeb0022f723643dbc579e145641afb814a1772237ff92e35ef82
@@ -1,15 +1,10 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.5
3
+ NewCops: enable
3
4
 
4
5
  Layout/LineLength:
5
6
  Max: 100
6
7
 
7
- Lint/RaiseException:
8
- Enabled: True
9
-
10
- Lint/StructNewOverride:
11
- Enabled: True
12
-
13
8
  Metrics/AbcSize:
14
9
  Max: 16
15
10
  Exclude:
@@ -28,18 +23,9 @@ Metrics/BlockLength:
28
23
  - dbee-active_record.gemspec
29
24
 
30
25
  Metrics/ClassLength:
31
- Max: 125
26
+ Max: 140
32
27
 
33
28
  Metrics/MethodLength:
34
29
  Max: 25
35
30
  Exclude:
36
31
  - spec/db_helper.rb
37
-
38
- Style/HashEachMethods:
39
- Enabled: True
40
-
41
- Style/HashTransformKeys:
42
- Enabled: True
43
-
44
- Style/HashTransformValues:
45
- Enabled: True
@@ -1,9 +1,10 @@
1
- # 2.1.0 (TBD)
1
+ # 2.1.1 (July 15th, 2020)
2
2
 
3
3
  ### Additions:
4
4
 
5
5
  * Implemented Dbee::Query::Field#aggregator
6
6
  * Implemented Dbee::Query::Field#filters
7
+ * Implemented base case when a Dbee::Query contains no fields
7
8
 
8
9
  ### Changes:
9
10
 
@@ -42,15 +42,15 @@ Gem::Specification.new do |s|
42
42
  end
43
43
 
44
44
  s.add_dependency('activerecord', activerecord_version)
45
- s.add_dependency('dbee', '=2.1.0.pre.alpha')
45
+ s.add_dependency('dbee', '~>2', '>=2.1.1')
46
46
 
47
47
  s.add_development_dependency('guard-rspec', '~>4.7')
48
48
  s.add_development_dependency('mysql2', '~>0.5')
49
49
  s.add_development_dependency('pry', '~>0')
50
50
  s.add_development_dependency('rake', '~> 13')
51
51
  s.add_development_dependency('rspec', '~> 3.8')
52
- s.add_development_dependency('rubocop', '~>0.81.0')
53
- s.add_development_dependency('simplecov', '~>0.17.0')
52
+ s.add_development_dependency('rubocop', '~>0.88.0')
53
+ s.add_development_dependency('simplecov', '~>0.18.5')
54
54
  s.add_development_dependency('simplecov-console', '~>0.7.0')
55
55
  s.add_development_dependency('sqlite3', '~>1')
56
56
  end
@@ -7,30 +7,29 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'expression_builder/constraint'
11
- require_relative 'expression_builder/order'
12
- require_relative 'expression_builder/select'
13
- require_relative 'expression_builder/where'
10
+ require_relative 'maker'
14
11
 
15
12
  module Dbee
16
13
  module Providers
17
14
  class ActiveRecordProvider
18
15
  # This class can generate an Arel expression tree.
19
- class ExpressionBuilder
16
+ class ExpressionBuilder < Maker # :nodoc: all
20
17
  class MissingConstraintError < StandardError; end
21
18
 
22
19
  def initialize(model, table_alias_maker, column_alias_maker)
23
- @model = model
24
- @table_alias_maker = table_alias_maker
25
- @column_alias_maker = column_alias_maker
26
- @requires_group_by = false
27
- @group_by_columns = []
20
+ super(column_alias_maker)
21
+
22
+ @model = model
23
+ @table_alias_maker = table_alias_maker
28
24
 
29
25
  clear
30
26
  end
31
27
 
32
28
  def clear
33
- @base_table = make_table(model.table, model.name)
29
+ @requires_group_by = false
30
+ @group_by_columns = []
31
+ @base_table = make_table(model.table, model.name)
32
+ @select_all = true
34
33
 
35
34
  build(base_table)
36
35
 
@@ -38,6 +37,8 @@ module Dbee
38
37
  end
39
38
 
40
39
  def add(query)
40
+ return self unless query
41
+
41
42
  query.fields.each { |field| add_field(field) }
42
43
  query.sorters.each { |sorter| add_sorter(sorter) }
43
44
  query.filters.each { |filter| add_filter(filter) }
@@ -54,6 +55,8 @@ module Dbee
54
55
  @group_by_columns = []
55
56
  end
56
57
 
58
+ return statement.project(select_maker.star(base_table)).to_sql if select_all
59
+
57
60
  statement.to_sql
58
61
  end
59
62
 
@@ -63,9 +66,9 @@ module Dbee
63
66
  :statement,
64
67
  :model,
65
68
  :table_alias_maker,
66
- :column_alias_maker,
67
69
  :requires_group_by,
68
- :group_by_columns
70
+ :group_by_columns,
71
+ :select_all
69
72
 
70
73
  def tables
71
74
  @tables ||= {}
@@ -80,7 +83,7 @@ module Dbee
80
83
 
81
84
  key_path = filter.key_path
82
85
  arel_column = key_paths_to_arel_columns[key_path]
83
- predicate = Where.instance.make(filter, arel_column)
86
+ predicate = where_maker.make(filter, arel_column)
84
87
 
85
88
  build(statement.where(predicate))
86
89
 
@@ -92,7 +95,7 @@ module Dbee
92
95
 
93
96
  key_path = sorter.key_path
94
97
  arel_column = key_paths_to_arel_columns[key_path]
95
- predicate = Order.instance.make(sorter, arel_column)
98
+ predicate = order_maker.make(sorter, arel_column)
96
99
 
97
100
  build(statement.order(predicate))
98
101
 
@@ -108,14 +111,14 @@ module Dbee
108
111
  end
109
112
 
110
113
  def add_field(field)
114
+ @select_all = false
111
115
  arel_value_column = add_key_path(field.key_path)
112
116
  arel_key_columns_to_filters = add_filter_key_paths(field.filters)
113
117
 
114
- predicate = Select.instance.make(
118
+ predicate = select_maker.make(
115
119
  field,
116
120
  arel_key_columns_to_filters,
117
- arel_value_column,
118
- column_alias_maker
121
+ arel_value_column
119
122
  )
120
123
 
121
124
  build(statement.project(predicate))
@@ -151,7 +154,7 @@ module Dbee
151
154
  def table(name, model, previous_table)
152
155
  table = make_table(model.table, name)
153
156
 
154
- on = Constraint.instance.make(model.constraints, table, previous_table)
157
+ on = constraint_maker.make(model.constraints, table, previous_table)
155
158
 
156
159
  raise MissingConstraintError, "for: #{name}" unless on
157
160
 
@@ -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
+ require_relative 'makers/constraint'
11
+ require_relative 'makers/order'
12
+ require_relative 'makers/select'
13
+ require_relative 'makers/where'
14
+
15
+ module Dbee
16
+ module Providers
17
+ class ActiveRecordProvider
18
+ # This class composes all the maker instances into one for use together.
19
+ class Maker # :nodoc: all
20
+ def initialize(column_alias_maker)
21
+ @column_alias_maker = column_alias_maker
22
+ @constraint_maker = Makers::Constraint.instance
23
+ @order_maker = Makers::Order.instance
24
+ @select_maker = Makers::Select.new(column_alias_maker)
25
+ @where_maker = Makers::Where.instance
26
+ end
27
+
28
+ private
29
+
30
+ attr_reader :constraint_maker,
31
+ :order_maker,
32
+ :select_maker,
33
+ :where_maker
34
+ end
35
+ end
36
+ end
37
+ end
@@ -10,7 +10,7 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- class ExpressionBuilder
13
+ module Makers # :nodoc: all
14
14
  # Can derive constraints for Arel table JOIN statements.
15
15
  class Constraint
16
16
  include Singleton
@@ -10,7 +10,7 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- class ExpressionBuilder
13
+ module Makers # :nodoc: all
14
14
  # Derives Arel#order predicates.
15
15
  class Order
16
16
  include Singleton
@@ -10,12 +10,22 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- class ExpressionBuilder
13
+ module Makers # :nodoc: all
14
14
  # Derives Arel#project predicates.
15
15
  class Select
16
- include Singleton
16
+ attr_reader :alias_maker
17
17
 
18
- def make(field, arel_key_nodes_to_filters, arel_value_node, alias_maker)
18
+ def initialize(alias_maker)
19
+ @alias_maker = alias_maker
20
+
21
+ freeze
22
+ end
23
+
24
+ def star(arel_table)
25
+ arel_table[Arel.star]
26
+ end
27
+
28
+ def make(field, arel_key_nodes_to_filters, arel_value_node)
19
29
  column_alias = quote(alias_maker.make(field.display))
20
30
  predicate = expression(field, arel_key_nodes_to_filters, arel_value_node)
21
31
  predicate = aggregate(field, predicate)
@@ -10,7 +10,7 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- class ExpressionBuilder
13
+ module Makers # :nodoc: all
14
14
  # Derives Arel#where predicates.
15
15
  class Where
16
16
  include Singleton
@@ -10,7 +10,7 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- VERSION = '2.1.0-alpha.1'
13
+ VERSION = '2.1.1'
14
14
  end
15
15
  end
16
16
  end
@@ -106,6 +106,8 @@ def load_schema
106
106
  t.timestamps
107
107
  end
108
108
 
109
+ add_index :fields, %i[section key], unique: true
110
+
109
111
  create_table :patients do |t|
110
112
  t.column :first, :string
111
113
  t.column :middle, :string
@@ -114,14 +116,16 @@ def load_schema
114
116
  end
115
117
 
116
118
  create_table :patient_field_values do |t|
117
- t.column :patient_id, :integer
118
- t.column :field_id, :integer
119
+ t.column :patient_id, :integer, foreign_key: true
120
+ t.column :field_id, :integer, foreign_key: true
119
121
  t.column :value, :string
120
122
  t.timestamps
121
123
  end
122
124
 
125
+ add_index :patient_field_values, %i[patient_id field_id], unique: true
126
+
123
127
  create_table :patient_payments do |t|
124
- t.column :patient_id, :integer
128
+ t.column :patient_id, :integer, foreign_key: true
125
129
  t.column :amount, :decimal
126
130
  t.timestamps
127
131
  end
@@ -0,0 +1,117 @@
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 'db_helper'
12
+
13
+ describe Dbee::Providers::ActiveRecordProvider::ExpressionBuilder do
14
+ let(:model) { Dbee::Model.make(models['Patients']) }
15
+ let(:alias_maker) { Dbee::Providers::ActiveRecordProvider::SafeAliasMaker.new }
16
+
17
+ let(:id_and_average_query) do
18
+ Dbee::Query.make(
19
+ fields: [
20
+ {
21
+ key_path: :id,
22
+ display: 'ID #'
23
+ },
24
+ {
25
+ key_path: 'patient_payments.amount',
26
+ display: 'Ave Payment',
27
+ aggregator: :ave
28
+ }
29
+ ],
30
+ sorters: [
31
+ {
32
+ key_path: :id
33
+ }
34
+ ],
35
+ filters: [
36
+ {
37
+ key_path: :id,
38
+ value: 123
39
+ }
40
+ ]
41
+ )
42
+ end
43
+
44
+ let(:first_and_count_query) do
45
+ Dbee::Query.make(
46
+ fields: [
47
+ {
48
+ key_path: :first,
49
+ display: 'First Name'
50
+ },
51
+ {
52
+ key_path: 'patient_payments.amount',
53
+ display: 'Number of Payments',
54
+ aggregator: :count
55
+ }
56
+ ]
57
+ )
58
+ end
59
+
60
+ subject { described_class.new(model, alias_maker, alias_maker) }
61
+
62
+ before(:all) do
63
+ connect_to_db(:sqlite)
64
+ end
65
+
66
+ describe '#clear' do
67
+ it 'provides fluent interface (returns self)' do
68
+ expect(subject.clear).to eq(subject)
69
+ end
70
+
71
+ it 'resets selecting, grouping, sorting, and filtering' do
72
+ subject.add(id_and_average_query)
73
+
74
+ sql = subject.to_sql
75
+
76
+ expect(sql).not_to include('*')
77
+ expect(sql).to include('GROUP')
78
+ expect(sql).to include('WHERE')
79
+ expect(sql).to include('ORDER')
80
+
81
+ sql = subject.clear.to_sql
82
+
83
+ expect(sql).to include('*')
84
+ expect(sql).not_to include('GROUP')
85
+ expect(sql).not_to include('WHERE')
86
+ expect(sql).not_to include('ORDER')
87
+ end
88
+ end
89
+
90
+ describe '#to_sql' do
91
+ specify 'when called with no fields, then called with fields removes star select' do
92
+ expect(subject.to_sql).to include('*')
93
+
94
+ subject.add(id_and_average_query)
95
+
96
+ expect(subject.to_sql).not_to include('*')
97
+ end
98
+
99
+ context 'with aggregation' do
100
+ it 'generates the same sql when called multiple times' do
101
+ subject.add(id_and_average_query)
102
+
103
+ first_sql = subject.to_sql
104
+ second_sql = subject.to_sql
105
+
106
+ expect(first_sql).to eq(second_sql)
107
+
108
+ subject.add(first_and_count_query)
109
+
110
+ first_sql = subject.to_sql
111
+ second_sql = subject.to_sql
112
+
113
+ expect(first_sql).to eq(second_sql)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -11,8 +11,6 @@ require 'spec_helper'
11
11
  require 'db_helper'
12
12
 
13
13
  describe Dbee::Providers::ActiveRecordProvider do
14
- let(:models) { yaml_fixture('models.yaml') }
15
-
16
14
  describe '#sql' do
17
15
  before(:all) do
18
16
  connect_to_db(:sqlite)
@@ -176,8 +174,7 @@ describe Dbee::Providers::ActiveRecordProvider do
176
174
  let(:model) { Dbee::Model.make(models['Patients']) }
177
175
 
178
176
  it 'executes correct SQL aggregate functions' do
179
- sql = described_class.new.sql(model, query)
180
-
177
+ sql = described_class.new.sql(model, query)
181
178
  results = ActiveRecord::Base.connection.execute(sql)
182
179
 
183
180
  expect(results[0]).to include(
@@ -0,0 +1,10 @@
1
+ model_name: Patients
2
+ query:
3
+ sqlite_readable: |+
4
+ SELECT "patients".* FROM "patients" "patients"
5
+ sqlite_not_readable: |+
6
+ SELECT "t0".* FROM "patients" "t0"
7
+ mysql_readable: |+
8
+ SELECT `patients`.* FROM `patients` `patients`
9
+ mysql_not_readable: |+
10
+ SELECT `t0`.* FROM `patients` `t0`
@@ -50,3 +50,7 @@ end
50
50
  def file_read(*filename)
51
51
  File.open(File.join(*filename), 'r:bom|utf-8').read
52
52
  end
53
+
54
+ def models
55
+ yaml_fixture('models.yaml')
56
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbee-active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0.pre.alpha.1
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2020-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -34,16 +34,22 @@ dependencies:
34
34
  name: dbee
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - '='
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '2'
40
+ - - ">="
38
41
  - !ruby/object:Gem::Version
39
- version: 2.1.0.pre.alpha
42
+ version: 2.1.1
40
43
  type: :runtime
41
44
  prerelease: false
42
45
  version_requirements: !ruby/object:Gem::Requirement
43
46
  requirements:
44
- - - '='
47
+ - - "~>"
45
48
  - !ruby/object:Gem::Version
46
- version: 2.1.0.pre.alpha
49
+ version: '2'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.1.1
47
53
  - !ruby/object:Gem::Dependency
48
54
  name: guard-rspec
49
55
  requirement: !ruby/object:Gem::Requirement
@@ -120,28 +126,28 @@ dependencies:
120
126
  requirements:
121
127
  - - "~>"
122
128
  - !ruby/object:Gem::Version
123
- version: 0.81.0
129
+ version: 0.88.0
124
130
  type: :development
125
131
  prerelease: false
126
132
  version_requirements: !ruby/object:Gem::Requirement
127
133
  requirements:
128
134
  - - "~>"
129
135
  - !ruby/object:Gem::Version
130
- version: 0.81.0
136
+ version: 0.88.0
131
137
  - !ruby/object:Gem::Dependency
132
138
  name: simplecov
133
139
  requirement: !ruby/object:Gem::Requirement
134
140
  requirements:
135
141
  - - "~>"
136
142
  - !ruby/object:Gem::Version
137
- version: 0.17.0
143
+ version: 0.18.5
138
144
  type: :development
139
145
  prerelease: false
140
146
  version_requirements: !ruby/object:Gem::Requirement
141
147
  requirements:
142
148
  - - "~>"
143
149
  - !ruby/object:Gem::Version
144
- version: 0.17.0
150
+ version: 0.18.5
145
151
  - !ruby/object:Gem::Dependency
146
152
  name: simplecov-console
147
153
  requirement: !ruby/object:Gem::Requirement
@@ -195,18 +201,21 @@ files:
195
201
  - exe/.gitkeep
196
202
  - lib/dbee/providers/active_record_provider.rb
197
203
  - lib/dbee/providers/active_record_provider/expression_builder.rb
198
- - lib/dbee/providers/active_record_provider/expression_builder/constraint.rb
199
- - lib/dbee/providers/active_record_provider/expression_builder/order.rb
200
- - lib/dbee/providers/active_record_provider/expression_builder/select.rb
201
- - lib/dbee/providers/active_record_provider/expression_builder/where.rb
204
+ - lib/dbee/providers/active_record_provider/maker.rb
205
+ - lib/dbee/providers/active_record_provider/makers/constraint.rb
206
+ - lib/dbee/providers/active_record_provider/makers/order.rb
207
+ - lib/dbee/providers/active_record_provider/makers/select.rb
208
+ - lib/dbee/providers/active_record_provider/makers/where.rb
202
209
  - lib/dbee/providers/active_record_provider/obfuscated_alias_maker.rb
203
210
  - lib/dbee/providers/active_record_provider/safe_alias_maker.rb
204
211
  - lib/dbee/providers/active_record_provider/version.rb
205
212
  - spec/config/database.yaml.ci
206
213
  - spec/db_helper.rb
214
+ - spec/dbee/providers/active_record_provider/expression_builder_spec.rb
207
215
  - spec/dbee/providers/active_record_provider_spec.rb
208
216
  - spec/fixtures/active_record_snapshots/five_table_query.yaml
209
217
  - spec/fixtures/active_record_snapshots/multiple_same_table_query_with_static_constraints.yaml
218
+ - spec/fixtures/active_record_snapshots/one_table_empty_query.yaml
210
219
  - spec/fixtures/active_record_snapshots/one_table_query.yaml
211
220
  - spec/fixtures/active_record_snapshots/one_table_query_with_ascending_sort.yaml
212
221
  - spec/fixtures/active_record_snapshots/one_table_query_with_descending_sort.yaml
@@ -241,9 +250,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
241
250
  version: '2.5'
242
251
  required_rubygems_version: !ruby/object:Gem::Requirement
243
252
  requirements:
244
- - - ">"
253
+ - - ">="
245
254
  - !ruby/object:Gem::Version
246
- version: 1.3.1
255
+ version: '0'
247
256
  requirements: []
248
257
  rubygems_version: 3.0.3
249
258
  signing_key:
@@ -252,9 +261,11 @@ summary: Plugs in ActiveRecord so Dbee can use Arel for SQL generation.
252
261
  test_files:
253
262
  - spec/config/database.yaml.ci
254
263
  - spec/db_helper.rb
264
+ - spec/dbee/providers/active_record_provider/expression_builder_spec.rb
255
265
  - spec/dbee/providers/active_record_provider_spec.rb
256
266
  - spec/fixtures/active_record_snapshots/five_table_query.yaml
257
267
  - spec/fixtures/active_record_snapshots/multiple_same_table_query_with_static_constraints.yaml
268
+ - spec/fixtures/active_record_snapshots/one_table_empty_query.yaml
258
269
  - spec/fixtures/active_record_snapshots/one_table_query.yaml
259
270
  - spec/fixtures/active_record_snapshots/one_table_query_with_ascending_sort.yaml
260
271
  - spec/fixtures/active_record_snapshots/one_table_query_with_descending_sort.yaml