Skip to content

Commit 3a3340b

Browse files
authored
fix(multidb): fix issue with multiple connection detection (#578)
1 parent 047b0f4 commit 3a3340b

File tree

8 files changed

+136
-11
lines changed

8 files changed

+136
-11
lines changed

app/services/forest_liana/base_getter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ def optimize_record_loading(resource, records)
3434
instance_dependent_associations = instance_dependent_associations(resource)
3535

3636
preload_loads = @includes.select do |name|
37-
targetModelConnection = resource.reflect_on_association(name).inverse_of&.active_record&.connection
37+
targetModelConnection = resource.reflect_on_association(name).klass.connection
3838
targetModelDatabase = targetModelConnection.current_database if targetModelConnection.respond_to? :current_database
3939
resourceConnection = resource.connection
40-
resourceDatabase = resourceConnection if resourceConnection.respond_to? :current_database
40+
resourceDatabase = resourceConnection.current_database if resourceConnection.respond_to? :current_database
4141

4242
targetModelDatabase != resourceDatabase
4343
end + instance_dependent_associations
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class Manufacturer < ApplicationRecord
2+
has_many :products
3+
end

spec/dummy/app/models/product.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
class Product < ApplicationRecord
2+
belongs_to :manufacturer
3+
belongs_to :driver, optional: true
4+
25
validates :uri, presence: true, format: { with: URI::DEFAULT_PARSER.make_regexp }
36
end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class CreateManufacturers < ActiveRecord::Migration[6.0]
2+
def change
3+
create_table :manufacturers do |t|
4+
t.string :name
5+
end
6+
end
7+
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class AddColumnsToProducts < ActiveRecord::Migration[6.0]
2+
def change
3+
change_table :products do |table|
4+
table.string :name
5+
table.belongs_to(:manufacturer)
6+
table.belongs_to(:driver)
7+
end
8+
end
9+
end

spec/dummy/db/schema.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema.define(version: 2021_05_26_084712) do
13+
ActiveRecord::Schema.define(version: 2022_07_27_114930) do
1414

1515
create_table "isle", force: :cascade do |t|
1616
t.string "name"
@@ -27,13 +27,22 @@
2727
t.index ["island_id"], name: "index_locations_on_island_id"
2828
end
2929

30+
create_table "manufacturers", force: :cascade do |t|
31+
t.string "name"
32+
end
33+
3034
create_table "owners", force: :cascade do |t|
3135
t.string "name"
3236
t.datetime "hired_at"
3337
end
3438

3539
create_table "products", force: :cascade do |t|
3640
t.string "uri"
41+
t.string "name"
42+
t.integer "manufacturer_id"
43+
t.integer "driver_id"
44+
t.index ["driver_id"], name: "index_products_on_driver_id"
45+
t.index ["manufacturer_id"], name: "index_products_on_manufacturer_id"
3746
end
3847

3948
create_table "references", force: :cascade do |t|

spec/lib/forest_liana/bootstrapper_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ module ForestLiana
2525
[
2626
Island,
2727
Location,
28+
Manufacturer,
2829
Owner,
2930
Product,
3031
Reference,

spec/services/forest_liana/resources_getter_spec.rb

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ module ForestLiana
44
let(:pageSize) { 10 }
55
let(:pageNumber) { 1 }
66
let(:sort) { 'id' }
7-
let(:fields) { }
8-
let(:filters) { }
9-
let(:scopes) { { } }
7+
let(:fields) {}
8+
let(:filters) {}
9+
let(:scopes) { {} }
1010
let(:rendering_id) { 13 }
1111
let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
1212

@@ -22,7 +22,21 @@ def init_scopes
2222
allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return(scopes)
2323
end
2424

25+
def clean_database
26+
[
27+
Driver,
28+
Island,
29+
Location,
30+
Manufacturer,
31+
Product,
32+
Tree,
33+
User,
34+
].each(&:destroy_all)
35+
end
36+
2537
before(:each) do
38+
clean_database
39+
2640
users = ['Michel', 'Robert', 'Vince', 'Sandro', 'Olesya', 'Romain', 'Valentin', 'Jason', 'Arnaud', 'Jeff', 'Steve', 'Marc', 'Xavier', 'Paul', 'Mickael', 'Mike', 'Maxime', 'Gertrude', 'Monique', 'Mia', 'Rachid', 'Edouard', 'Sacha', 'Caro', 'Amand', 'Nathan', 'Noémie', 'Robin', 'Gaelle', 'Isabelle']
2741
.map { |name| User.create(name: name) }
2842

@@ -50,15 +64,94 @@ def init_scopes
5064
{ :coordinates => '32154', :island => islands[4] }
5165
].map { |location| Location.create(coordinates: location[:coordinates], island: location[:island]) }
5266

67+
manufacturers = ['Orange', 'Pear'].map { |name| Manufacturer.create!(name: 'name') }
68+
69+
drivers = ['Baby driver', 'Taxi driver'].map { |firstname| Driver.create!(firstname: firstname) }
70+
71+
products = [
72+
{ name: 'Valencia', uri: 'https://valencia.com', manufacturer: manufacturers[0], driver: drivers[0] },
73+
{ name: 'Blood', uri: 'https://blood.com', manufacturer: manufacturers[0], driver: drivers[1] },
74+
{ name: 'Conference', uri: 'https://conference.com', manufacturer: manufacturers[1], driver: drivers[0] },
75+
{ name: 'Concorde', uri: 'https://concorde.com', manufacturer: manufacturers[1], driver: drivers[1] }
76+
].map {|attributes| Product.create!(attributes) }
77+
5378
reference = Reference.create()
5479
init_scopes
5580
end
5681

57-
after(:each) do
58-
User.destroy_all
59-
Island.destroy_all
60-
Location.destroy_all
61-
Tree.destroy_all
82+
describe 'records eager loading' do
83+
let(:resource) { Product }
84+
let(:fields) { { resource.name => 'id,name,manufacturer', 'manufacturer' => 'name' } }
85+
86+
shared_context 'resource current_database' do
87+
before do
88+
connection = resource.connection
89+
90+
def connection.current_database
91+
'db/test.sqlite3'
92+
end
93+
end
94+
95+
after do
96+
resource.connection.singleton_class.remove_method(:current_database)
97+
end
98+
end
99+
100+
shared_examples 'left outer join' do
101+
it 'should perform a left outer join with the association' do
102+
expect(getter.perform.to_sql).to match(/LEFT OUTER JOIN "manufacturers"/)
103+
end
104+
end
105+
106+
shared_examples 'records' do
107+
it 'should get only the expected records' do
108+
getter.perform
109+
110+
records = getter.records
111+
112+
count = getter.count
113+
114+
expect(records.count).to eq 4
115+
expect(count).to eq 4
116+
expect(records.map(&:name)).to match_array(%w[Valencia Blood Conference Concorde])
117+
end
118+
end
119+
120+
context 'when the connections do not support current_database' do
121+
include_examples 'left outer join'
122+
include_examples 'records'
123+
end
124+
125+
context 'when the included association uses a different database connection' do
126+
let(:fields) { { resource.name => 'id,name,driver', 'driver' => 'firstname' } }
127+
128+
before do
129+
association_connection = resource.reflect_on_association(:driver).klass.connection
130+
131+
def association_connection.current_database
132+
'db/different_test.sqlite3'
133+
end
134+
end
135+
136+
after do
137+
resource.reflect_on_association(:driver).klass.connection.singleton_class.remove_method(:current_database)
138+
end
139+
140+
include_context 'resource current_database'
141+
142+
include_examples 'records'
143+
144+
it 'does not perform a left outer join with the association' do
145+
expect(getter.perform.to_sql).not_to match(/LEFT OUTER JOIN "drivers"/)
146+
end
147+
end
148+
149+
context 'when the included association uses the same database connection' do
150+
include_context 'resource current_database'
151+
152+
include_examples 'left outer join'
153+
include_examples 'records'
154+
end
62155
end
63156

64157
describe 'when there are more records than the page size' do

0 commit comments

Comments
 (0)