dbee-active_record 2.1.2 → 2.2.0

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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +6 -0
  5. data/Guardfile +2 -1
  6. data/dbee-active_record.gemspec +6 -2
  7. data/lib/dbee/providers/active_record_provider.rb +3 -3
  8. data/lib/dbee/providers/active_record_provider/expression_builder.rb +61 -51
  9. data/lib/dbee/providers/active_record_provider/version.rb +1 -1
  10. data/spec/dbee/providers/active_record_provider/expression_builder_spec.rb +13 -40
  11. data/spec/dbee/providers/active_record_provider_spec.rb +15 -15
  12. data/spec/fixtures/active_record_snapshots/five_table_query.yaml +1 -0
  13. data/spec/fixtures/active_record_snapshots/multiple_same_table_query_with_static_constraints.yaml +1 -0
  14. data/spec/fixtures/active_record_snapshots/one_table_empty_query.yaml +1 -0
  15. data/spec/fixtures/active_record_snapshots/one_table_query.yaml +1 -0
  16. data/spec/fixtures/active_record_snapshots/one_table_query_with_ascending_sort.yaml +1 -0
  17. data/spec/fixtures/active_record_snapshots/one_table_query_with_descending_sort.yaml +1 -0
  18. data/spec/fixtures/active_record_snapshots/one_table_query_with_filters.yaml +1 -0
  19. data/spec/fixtures/active_record_snapshots/one_table_query_with_limit.yaml +1 -0
  20. data/spec/fixtures/active_record_snapshots/one_table_query_with_multiple_sorts.yaml +1 -0
  21. data/spec/fixtures/active_record_snapshots/partitioner_example_1_query.yaml +1 -0
  22. data/spec/fixtures/active_record_snapshots/partitioner_example_2_query.yaml +1 -0
  23. data/spec/fixtures/active_record_snapshots/reverse_polymorphic_query.yaml +1 -0
  24. data/spec/fixtures/active_record_snapshots/two_table_query.yaml +1 -0
  25. data/spec/fixtures/active_record_snapshots/two_table_query_with_aggregation.yaml +1 -0
  26. data/spec/fixtures/active_record_snapshots/two_table_query_with_pivoting.yaml +1 -0
  27. data/spec/fixtures/models.yaml +110 -102
  28. data/spec/spec_helper.rb +8 -1
  29. metadata +51 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ec480363c33c49f4dd4cd5de9023b6ddad2f3d8b39ee90b4a67bc282a2b35f3
4
- data.tar.gz: 6db9e48a3bb04e73ae91f01c63640b36db530f04a06245462b4e4d72e2f083c0
3
+ metadata.gz: a9ad362290b7ac95e9ad1c466868f81bad354df55b9772742c9bf6591f9f762d
4
+ data.tar.gz: 0ff078fc8e40af83f984729f3320856af95cf95b3562f97bc17b0b8787342a12
5
5
  SHA512:
6
- metadata.gz: 694720a4ff3a557ebdf03cf94bb38010e9c52eacbf188c26f4b3e6e6c7adbd08353e31aae214797bbc79e7493f9d53f178b866b017e4c5feba13a23d253b1449
7
- data.tar.gz: 7ba4120f8e7ddc71b2f7d2783c854f9f6ac5b1935260fb7c769d96f1e0ac900ffa8cbb2b3233dd7ccd4d3e7b38d4c702dc9a142a29fd45a2258b0e27ad69ad42
6
+ metadata.gz: 93b68e1d07bfe82c469d1169d7e94fa2dece7a7f32fc01adcf895356bdfa285d7d1352b1a37e3bd7b50e1023551160988b4dc7a49c97d904b1b4c37d77d1e676
7
+ data.tar.gz: 44aa0eda58e8d5f50f9d99d1b44a81ade7781ba9cad9cf35b47e6b3dcab2f2699c69898e774b33c3a00c535b4927481b3bb62411856f607ff78b24e34dd320a5
data/.rubocop.yml CHANGED
@@ -11,7 +11,7 @@ Metrics/AbcSize:
11
11
  - spec/db_helper.rb
12
12
 
13
13
  Metrics/BlockLength:
14
- ExcludedMethods:
14
+ IgnoredMethods:
15
15
  - let
16
16
  - it
17
17
  - describe
data/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  env:
2
2
  global:
3
3
  - CC_TEST_REPORTER_ID=036a8fd92cf0c323c9704c041015837d14889e47de936bab18287626ff3372c1
4
+ - DISABLE_RSPEC_FOCUS=true
4
5
  language: ruby
5
6
  services:
6
7
  - mysql
@@ -8,7 +9,7 @@ rvm:
8
9
  # Build on the latest stable of all supported Rubies (https://www.ruby-lang.org/en/downloads/):
9
10
  - 2.5.8
10
11
  - 2.6.6
11
- - 2.7.1
12
+ - 2.7.2
12
13
  env:
13
14
  - AR_VERSION=5
14
15
  - AR_VERSION=6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # 2.2.0 (March 11th, 2021)
2
+
3
+ ### Additions:
4
+
5
+ * Support for graph based models.
6
+
1
7
  # 2.1.2 (October 15th, 2020)
2
8
 
3
9
  * Improved test coverage for Where maker
data/Guardfile CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- guard :rspec, cmd: 'DISABLE_SIMPLECOV=true bundle exec rspec --format=documentation' do
3
+ command = 'DISABLE_SIMPLECOV=true bundle exec rspec --format=documentation --order=defined'
4
+ guard :rspec, cmd: command do
4
5
  require 'guard/rspec/dsl'
5
6
  dsl = Guard::RSpec::Dsl.new(self)
6
7
 
@@ -42,7 +42,7 @@ Gem::Specification.new do |s|
42
42
  end
43
43
 
44
44
  s.add_dependency('activerecord', activerecord_version)
45
- s.add_dependency('dbee', '~>2', '>=2.1.1')
45
+ s.add_dependency('dbee', '~>3')
46
46
 
47
47
  s.add_development_dependency('guard-rspec', '~>4.7')
48
48
  s.add_development_dependency('mysql2', '~>0.5')
@@ -50,8 +50,12 @@ Gem::Specification.new do |s|
50
50
  s.add_development_dependency('pry-byebug')
51
51
  s.add_development_dependency('rake', '~> 13')
52
52
  s.add_development_dependency('rspec', '~> 3.8')
53
- s.add_development_dependency('rubocop', '~>0.90.0')
53
+ s.add_development_dependency('rubocop', '~> 1')
54
+ s.add_development_dependency('rubocop-rake')
55
+ s.add_development_dependency('rubocop-rspec')
54
56
  s.add_development_dependency('simplecov', '~>0.19.0')
55
57
  s.add_development_dependency('simplecov-console', '~>0.7.0')
56
58
  s.add_development_dependency('sqlite3', '~>1')
59
+ # Helpful to spot differences in longer SQL queries:
60
+ s.add_development_dependency('super_diff', '~>0.6')
57
61
  end
@@ -35,12 +35,12 @@ module Dbee
35
35
  @column_alias_maker = alias_maker(column_prefix)
36
36
  end
37
37
 
38
- def sql(model, query)
38
+ def sql(schema, query)
39
39
  ExpressionBuilder.new(
40
- model,
40
+ schema,
41
41
  table_alias_maker,
42
42
  column_alias_maker
43
- ).add(query).to_sql
43
+ ).to_sql(query)
44
44
  end
45
45
 
46
46
  private
@@ -12,48 +12,21 @@ require_relative 'maker'
12
12
  module Dbee
13
13
  module Providers
14
14
  class ActiveRecordProvider
15
- # This class can generate an Arel expression tree.
15
+ # This class can generate an Arel expression tree given a Dbee::Schema
16
+ # and Dbee::Query.
16
17
  class ExpressionBuilder < Maker # :nodoc: all
17
18
  class MissingConstraintError < StandardError; end
18
19
 
19
- def initialize(model, table_alias_maker, column_alias_maker)
20
+ def initialize(schema, table_alias_maker, column_alias_maker)
20
21
  super(column_alias_maker)
21
22
 
22
- @model = model
23
+ @schema = schema
23
24
  @table_alias_maker = table_alias_maker
24
-
25
- clear
26
- end
27
-
28
- def clear
29
- @requires_group_by = false
30
- @group_by_columns = []
31
- @base_table = make_table(model.table, model.name)
32
- @select_all = true
33
-
34
- build(base_table)
35
-
36
- add_partitioners(base_table, model.partitioners)
37
- end
38
-
39
- def add(query)
40
- return self unless query
41
-
42
- query.fields.each { |field| add_field(field) }
43
- query.sorters.each { |sorter| add_sorter(sorter) }
44
- query.filters.each { |filter| add_filter(filter) }
45
-
46
- add_limit(query.limit)
47
-
48
- self
49
25
  end
50
26
 
51
- def to_sql
52
- if requires_group_by
53
- @requires_group_by = false
54
- statement.group(group_by_columns) unless group_by_columns.empty?
55
- @group_by_columns = []
56
- end
27
+ def to_sql(query)
28
+ reset_query_state
29
+ build_query(query)
57
30
 
58
31
  return statement.project(select_maker.star(base_table)).to_sql if select_all
59
32
 
@@ -63,19 +36,46 @@ module Dbee
63
36
  private
64
37
 
65
38
  attr_reader :base_table,
39
+ :key_paths_to_arel_columns,
40
+ :from_model,
66
41
  :statement,
67
- :model,
68
42
  :table_alias_maker,
69
43
  :requires_group_by,
70
44
  :group_by_columns,
71
- :select_all
45
+ :schema,
46
+ :select_all,
47
+ :tables
48
+
49
+ def reset_query_state
50
+ @base_table = nil
51
+ @key_paths_to_arel_columns = {}
52
+ @from_model = nil
53
+ @group_by_columns = []
54
+ @requires_group_by = false
55
+ @select_all = true
56
+ @tables = {}
57
+ end
72
58
 
73
- def tables
74
- @tables ||= {}
59
+ def build_query(query)
60
+ establish_query_base(query)
61
+ process_fields_sorters_and_filters(query)
62
+
63
+ add_partitioners(base_table, from_model.partitioners)
64
+ add_limit(query.limit)
65
+
66
+ statement.group(group_by_columns) if requires_group_by && !group_by_columns.empty?
75
67
  end
76
68
 
77
- def key_paths_to_arel_columns
78
- @key_paths_to_arel_columns ||= {}
69
+ def establish_query_base(query)
70
+ @from_model = schema.model_for_name!(query.from)
71
+ @base_table = make_table(from_model.table, @from_model.name)
72
+ build(base_table)
73
+ end
74
+
75
+ def process_fields_sorters_and_filters(query)
76
+ query.fields.each { |field| add_field(field) }
77
+ query.sorters.each { |sorter| add_sorter(sorter) }
78
+ query.filters.each { |filter| add_filter(filter) }
79
79
  end
80
80
 
81
81
  def add_filter(filter)
@@ -151,33 +151,43 @@ module Dbee
151
151
  self
152
152
  end
153
153
 
154
- def table(name, model, previous_table)
155
- table = make_table(model.table, name)
154
+ def table(ancestor_names, relationship, model, previous_table)
155
+ table = make_table(model.table, ancestor_names)
156
156
 
157
- on = constraint_maker.make(model.constraints, table, previous_table)
157
+ on = constraint_maker.make(relationship.constraints, table, previous_table)
158
158
 
159
- raise MissingConstraintError, "for: #{name}" unless on
159
+ raise MissingConstraintError, "for: #{ancestor_names}" unless on
160
160
 
161
161
  build(statement.join(table, ::Arel::Nodes::OuterJoin))
162
162
  build(statement.on(on))
163
163
 
164
164
  add_partitioners(table, model.partitioners)
165
165
 
166
- tables[name] = table
166
+ tables[ancestor_names] = table
167
167
  end
168
168
 
169
- def traverse_ancestors(ancestors)
170
- ancestors.each_pair.inject(base_table) do |memo, (name, model)|
171
- tables.key?(name) ? tables[name] : table(name, model, memo)
169
+ # Travel the query path returning the table at the end of the path.
170
+ #
171
+ # Side effect: intermediate tables are created along the way and are
172
+ # added to the "tables" hash keyed by path.
173
+ def traverse_query_path(expanded_query_path)
174
+ visited_path = []
175
+
176
+ expanded_query_path.inject(base_table) do |prev_model, (relationship, next_model)|
177
+ visited_path += [relationship.name]
178
+ if tables.key?(visited_path)
179
+ tables[visited_path]
180
+ else
181
+ table(visited_path, relationship, next_model, prev_model)
182
+ end
172
183
  end
173
184
  end
174
185
 
175
186
  def add_key_path(key_path)
176
187
  return key_paths_to_arel_columns[key_path] if key_paths_to_arel_columns.key?(key_path)
177
188
 
178
- ancestors = model.ancestors!(key_path.ancestor_names)
179
-
180
- table = traverse_ancestors(ancestors)
189
+ expanded_query_path = schema.expand_query_path(from_model, key_path)
190
+ table = traverse_query_path(expanded_query_path)
181
191
 
182
192
  arel_column = table[key_path.column_name]
183
193
 
@@ -10,7 +10,7 @@
10
10
  module Dbee
11
11
  module Providers
12
12
  class ActiveRecordProvider
13
- VERSION = '2.1.2'
13
+ VERSION = '2.2.0'
14
14
  end
15
15
  end
16
16
  end
@@ -11,11 +11,14 @@ require 'spec_helper'
11
11
  require 'db_helper'
12
12
 
13
13
  describe Dbee::Providers::ActiveRecordProvider::ExpressionBuilder do
14
- let(:model) { Dbee::Model.make(models['Patients']) }
14
+ let(:schema) { Dbee::Schema.new(models['Patients']) }
15
15
  let(:alias_maker) { Dbee::Providers::ActiveRecordProvider::SafeAliasMaker.new }
16
16
 
17
+ let(:empty_query) { Dbee::Query.make(from: :patients) }
18
+
17
19
  let(:id_and_average_query) do
18
20
  Dbee::Query.make(
21
+ from: :patients,
19
22
  fields: [
20
23
  {
21
24
  key_path: :id,
@@ -43,6 +46,7 @@ describe Dbee::Providers::ActiveRecordProvider::ExpressionBuilder do
43
46
 
44
47
  let(:first_and_count_query) do
45
48
  Dbee::Query.make(
49
+ from: :patients,
46
50
  fields: [
47
51
  {
48
52
  key_path: :first,
@@ -57,60 +61,29 @@ describe Dbee::Providers::ActiveRecordProvider::ExpressionBuilder do
57
61
  )
58
62
  end
59
63
 
60
- subject { described_class.new(model, alias_maker, alias_maker) }
64
+ subject { described_class.new(schema, alias_maker, alias_maker) }
61
65
 
62
66
  before(:all) do
63
67
  connect_to_db(:sqlite)
64
68
  end
65
69
 
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
70
  describe '#to_sql' do
91
71
  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('*')
72
+ expect(subject.to_sql(empty_query)).to include('*')
73
+ expect(subject.to_sql(id_and_average_query)).not_to include('*')
97
74
  end
98
75
 
99
76
  context 'with aggregation' do
100
77
  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
78
+ first_sql = subject.to_sql(id_and_average_query)
79
+ second_sql = subject.to_sql(id_and_average_query)
105
80
 
106
81
  expect(first_sql).to eq(second_sql)
107
82
 
108
- subject.add(first_and_count_query)
109
-
110
- first_sql = subject.to_sql
111
- second_sql = subject.to_sql
83
+ third_sql = subject.to_sql(first_and_count_query)
84
+ fourth_sql = subject.to_sql(first_and_count_query)
112
85
 
113
- expect(first_sql).to eq(second_sql)
86
+ expect(third_sql).to eq(fourth_sql)
114
87
  end
115
88
  end
116
89
  end
@@ -17,14 +17,13 @@ describe Dbee::Providers::ActiveRecordProvider do
17
17
  end
18
18
 
19
19
  it 'errors when joining tables with no constraints' do
20
- model_hash = {
21
- name: :users,
22
- models: [
23
- { name: :logins }
24
- ]
20
+ schema_hash = {
21
+ users: { relationships: { logins: nil } },
22
+ logins: nil
25
23
  }
26
24
 
27
25
  query_hash = {
26
+ from: :users,
28
27
  fields: [
29
28
  { key_path: 'id' },
30
29
  { key_path: 'logins.id' }
@@ -32,11 +31,11 @@ describe Dbee::Providers::ActiveRecordProvider do
32
31
  }
33
32
 
34
33
  query = Dbee::Query.make(query_hash)
35
- model = Dbee::Model.make(model_hash)
34
+ schema = Dbee::Schema.new(schema_hash)
36
35
 
37
36
  error_class = Dbee::Providers::ActiveRecordProvider::ExpressionBuilder::MissingConstraintError
38
37
 
39
- expect { described_class.new.sql(model, query) }.to raise_error(error_class)
38
+ expect { described_class.new.sql(schema, query) }.to raise_error(error_class)
40
39
  end
41
40
  end
42
41
 
@@ -55,12 +54,13 @@ describe Dbee::Providers::ActiveRecordProvider do
55
54
  yaml_fixture_files('active_record_snapshots').each_pair do |filename, snapshot|
56
55
  specify File.basename(filename) do
57
56
  model_name = snapshot['model_name']
57
+
58
58
  query = Dbee::Query.make(snapshot['query'])
59
- model = Dbee::Model.make(models[model_name])
59
+ schema = Dbee::Schema.new(models[model_name])
60
60
 
61
61
  expected_5_sql = snapshot[key].to_s.chomp.tr("\n", ' ')
62
62
  expected_6_sql = expected_5_sql.gsub(' ', ' ').gsub("'t'", '1').gsub("'f'", '0')
63
- actual_sql = described_class.new(readable: readable).sql(model, query)
63
+ actual_sql = described_class.new(readable: readable).sql(schema, query)
64
64
 
65
65
  error_msg = <<~ERROR_MSG
66
66
  Expected 5 SQL: #{expected_5_sql}
@@ -93,9 +93,9 @@ describe Dbee::Providers::ActiveRecordProvider do
93
93
  specify File.basename(filename) do
94
94
  model_name = snapshot['model_name']
95
95
  query = Dbee::Query.make(snapshot['query'])
96
- model = Dbee::Model.make(models[model_name])
96
+ schema = Dbee::Schema.new(models[model_name])
97
97
 
98
- sql = described_class.new(readable: readable).sql(model, query)
98
+ sql = described_class.new(readable: readable).sql(schema, query)
99
99
 
100
100
  expect { ActiveRecord::Base.connection.execute(sql) }.to_not raise_error
101
101
  end
@@ -126,10 +126,10 @@ describe Dbee::Providers::ActiveRecordProvider do
126
126
 
127
127
  let(:snapshot) { yaml_file_read(*snapshot_path) }
128
128
  let(:query) { Dbee::Query.make(snapshot['query']) }
129
- let(:model) { Dbee::Model.make(models['Patients']) }
129
+ let(:schema) { Dbee::Schema.new(models['Patients']) }
130
130
 
131
131
  it 'pivots table rows into columns' do
132
- sql = described_class.new.sql(model, query)
132
+ sql = described_class.new.sql(schema, query)
133
133
 
134
134
  results = ActiveRecord::Base.connection.execute(sql)
135
135
 
@@ -171,10 +171,10 @@ describe Dbee::Providers::ActiveRecordProvider do
171
171
 
172
172
  let(:snapshot) { yaml_file_read(*snapshot_path) }
173
173
  let(:query) { Dbee::Query.make(snapshot['query']) }
174
- let(:model) { Dbee::Model.make(models['Patients']) }
174
+ let(:schema) { Dbee::Schema.new(models['Patients']) }
175
175
 
176
176
  it 'executes correct SQL aggregate functions' do
177
- sql = described_class.new.sql(model, query)
177
+ sql = described_class.new.sql(schema, query)
178
178
  results = ActiveRecord::Base.connection.execute(sql)
179
179
 
180
180
  expect(results[0]).to include(
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: members.demos.phone_numbers.phone_number
5
6
  display: PHONE NUMBER
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Patients
2
2
  query:
3
+ from: patients
3
4
  sqlite_readable: |+
4
5
  SELECT "patients".* FROM "patients" "patients"
5
6
  sqlite_not_readable: |+
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  display: 'ID #'
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  display: 'ID #'
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Partitioner Example 1
2
2
  query:
3
+ from: dogs
3
4
  fields:
4
5
  - key_path: id
5
6
  sqlite_readable: |+
@@ -1,5 +1,6 @@
1
1
  model_name: Partitioner Example 2
2
2
  query:
3
+ from: owners
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: dogs.id
@@ -1,5 +1,6 @@
1
1
  model_name: Reverse Polymorphic Example
2
2
  query:
3
+ from: animals
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: type
@@ -1,5 +1,6 @@
1
1
  model_name: Theaters, Members, and Movies
2
2
  query:
3
+ from: theaters
3
4
  fields:
4
5
  - key_path: id
5
6
  - key_path: name
@@ -1,5 +1,6 @@
1
1
  model_name: Patients
2
2
  query:
3
+ from: patients
3
4
  fields:
4
5
  - key_path: id
5
6
  display: 'ID #'
@@ -1,5 +1,6 @@
1
1
  model_name: Patients
2
2
  query:
3
+ from: patients
3
4
  fields:
4
5
  - key_path: id
5
6
  display: 'ID #'
@@ -1,125 +1,133 @@
1
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
2
+ theaters:
3
+ relationships:
4
+ members:
5
+ constraints:
6
+ - type: reference
7
+ parent: id
8
+ name: tid
9
+ - type: reference
10
+ parent: partition
11
+ name: partition
12
+ members:
13
+ relationships:
14
+ demos:
15
+ model: demographics
16
+ constraints:
17
+ - type: reference
18
+ parent: id
19
+ name: member_id
20
+ movies:
21
+ constraints:
22
+ - type: reference
23
+ parent: id
24
+ name: member_id
25
+ favorite_comic_movies:
26
+ model: movies
27
+ constraints:
28
+ - type: reference
29
+ parent: id
30
+ name: member_id
31
+ - type: static
32
+ name: genre
33
+ value: comic
34
+ favorite_mystery_movies:
35
+ model: movies
36
+ constraints:
37
+ - type: reference
38
+ parent: id
39
+ name: member_id
40
+ - type: static
41
+ name: genre
42
+ value: mystery
43
+ favorite_comedy_movies:
44
+ model: movies
45
+ constraints:
46
+ - type: reference
47
+ parent: id
48
+ name: member_id
49
+ - type: static
50
+ name: genre
51
+ value: comedy
52
+ demographics:
53
+ table: demographics
54
+ relationships:
55
+ phone_numbers:
56
+ constraints:
57
+ - type: reference
58
+ parent: id
59
+ name: demographic_id
60
+ phone_numbers:
61
+ movies:
62
+
61
63
  Reverse Polymorphic Example:
62
64
  # In this example, an animal has a toy, but that toy is either a dog or cat toy, depending on
63
65
  # the type of the animal. So for this to work in this direction, static constraints pointed
64
66
  # at the parent (animals) is needed.
65
- name: animals
66
- models:
67
- - name: dog_toy
68
- table: dog_toys
67
+ animals:
68
+ relationships:
69
+ dog_toy:
70
+ model: dog_toys
69
71
  constraints:
70
72
  - parent: toy_id
71
73
  name: id
72
74
  - type: static
73
75
  parent: type
74
76
  value: Dog
75
- - name: cat_toy
76
- table: cat_toys
77
+ cat_toy:
78
+ model: cat_toys
77
79
  constraints:
78
80
  - parent: toy_id
79
81
  name: id
80
82
  - type: static
81
83
  parent: type
82
84
  value: Cat
85
+ dog_toys:
86
+ cat_toys:
83
87
 
84
88
  Partitioner Example 1:
85
- name: dogs
86
- table: animals
87
- partitioners:
88
- - name: type
89
- value: Dog
90
- - name: deleted
91
- value: false
89
+ dogs:
90
+ table: animals
91
+ partitioners:
92
+ - name: type
93
+ value: Dog
94
+ - name: deleted
95
+ value: false
92
96
 
93
97
  Partitioner Example 2:
94
- name: owners
95
- models:
96
- - name: dogs
97
- table: animals
98
- constraints:
99
- - name: owner_id
100
- parent: id
101
- partitioners:
102
- - name: type
103
- value: Dog
104
- - name: deleted
105
- value: false
98
+ owners:
99
+ relationships:
100
+ dogs:
101
+ constraints:
102
+ - name: owner_id
103
+ parent: id
104
+ dogs:
105
+ table: animals
106
+ partitioners:
107
+ - name: type
108
+ value: Dog
109
+ - name: deleted
110
+ value: false
106
111
 
107
112
  Patients:
108
- name: patients
109
- models:
110
- - name: patient_payments
111
- constraints:
112
- - type: reference
113
- parent: id
114
- name: patient_id
115
- - name: patient_field_values
116
- constraints:
117
- - type: reference
118
- parent: id
119
- name: patient_id
120
- models:
121
- - name: fields
122
- constraints:
123
- - type: reference
124
- parent: field_id
125
- name: id
113
+ patients:
114
+ relationships:
115
+ patient_payments:
116
+ constraints:
117
+ - type: reference
118
+ parent: id
119
+ name: patient_id
120
+ patient_field_values:
121
+ constraints:
122
+ - type: reference
123
+ parent: id
124
+ name: patient_id
125
+ patient_field_values:
126
+ relationships:
127
+ fields:
128
+ constraints:
129
+ - type: reference
130
+ parent: field_id
131
+ name: id
132
+ patient_payments:
133
+ fields:
data/spec/spec_helper.rb CHANGED
@@ -7,8 +7,15 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require 'yaml'
11
10
  require 'pry'
11
+ require 'super_diff/rspec'
12
+ require 'yaml'
13
+
14
+ RSpec.configure do |config|
15
+ # Allow for disabling auto focus mode in certain environments like CI to
16
+ # prevent false positives when only a subset of the suite passes.
17
+ config.filter_run_when_matching :focus unless ENV['DISABLE_RSPEC_FOCUS'] == 'true'
18
+ end
12
19
 
13
20
  unless ENV['DISABLE_SIMPLECOV'] == 'true'
14
21
  require 'simplecov'
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbee-active_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  - Craig Kattner
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-10-15 00:00:00.000000000 Z
12
+ date: 2021-03-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -37,20 +37,14 @@ dependencies:
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '2'
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- version: 2.1.1
40
+ version: '3'
44
41
  type: :runtime
45
42
  prerelease: false
46
43
  version_requirements: !ruby/object:Gem::Requirement
47
44
  requirements:
48
45
  - - "~>"
49
46
  - !ruby/object:Gem::Version
50
- version: '2'
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: 2.1.1
47
+ version: '3'
54
48
  - !ruby/object:Gem::Dependency
55
49
  name: guard-rspec
56
50
  requirement: !ruby/object:Gem::Requirement
@@ -141,14 +135,42 @@ dependencies:
141
135
  requirements:
142
136
  - - "~>"
143
137
  - !ruby/object:Gem::Version
144
- version: 0.90.0
138
+ version: '1'
145
139
  type: :development
146
140
  prerelease: false
147
141
  version_requirements: !ruby/object:Gem::Requirement
148
142
  requirements:
149
143
  - - "~>"
150
144
  - !ruby/object:Gem::Version
151
- version: 0.90.0
145
+ version: '1'
146
+ - !ruby/object:Gem::Dependency
147
+ name: rubocop-rake
148
+ requirement: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ type: :development
154
+ prerelease: false
155
+ version_requirements: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ - !ruby/object:Gem::Dependency
161
+ name: rubocop-rspec
162
+ requirement: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
152
174
  - !ruby/object:Gem::Dependency
153
175
  name: simplecov
154
176
  requirement: !ruby/object:Gem::Requirement
@@ -191,6 +213,20 @@ dependencies:
191
213
  - - "~>"
192
214
  - !ruby/object:Gem::Version
193
215
  version: '1'
216
+ - !ruby/object:Gem::Dependency
217
+ name: super_diff
218
+ requirement: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - "~>"
221
+ - !ruby/object:Gem::Version
222
+ version: '0.6'
223
+ type: :development
224
+ prerelease: false
225
+ version_requirements: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - "~>"
228
+ - !ruby/object:Gem::Version
229
+ version: '0.6'
194
230
  description: " By default Dbee ships with no underlying SQL generator. This library
195
231
  will plug in ActiveRecord into Dbee and Dbee will use it for SQL generation.\n"
196
232
  email:
@@ -256,7 +292,7 @@ metadata:
256
292
  documentation_uri: https://www.rubydoc.info/gems/dbee-active_record
257
293
  homepage_uri: https://github.com/bluemarblepayroll/dbee-active_record
258
294
  source_code_uri: https://github.com/bluemarblepayroll/dbee-active_record
259
- post_install_message:
295
+ post_install_message:
260
296
  rdoc_options: []
261
297
  require_paths:
262
298
  - lib
@@ -272,7 +308,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
308
  version: '0'
273
309
  requirements: []
274
310
  rubygems_version: 3.0.3
275
- signing_key:
311
+ signing_key:
276
312
  specification_version: 4
277
313
  summary: Plugs in ActiveRecord so Dbee can use Arel for SQL generation.
278
314
  test_files: