dbee-active_record 2.1.0.pre.alpha.1 → 2.1.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: 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