dbee-active_record 2.1.2 → 2.2.0

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