forest_liana 9.20.1 → 9.20.3
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 +4 -4
- data/app/services/forest_liana/base_getter.rb +2 -4
- data/app/services/forest_liana/schema_adapter.rb +5 -1
- data/lib/forest_liana/version.rb +1 -1
- data/spec/services/forest_liana/resources_getter_spec.rb +21 -43
- data/test/services/forest_liana/schema_adapter_test.rb +56 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be12c6b12347b9f674f52eb7f52b41294717436fae76926129d02b6194d6a116
|
|
4
|
+
data.tar.gz: 3a2d7c0a34e7cadbfc40d70b4385d23ffe703de619f9c28b49a10af86a23a8f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c32654d08132350f85a8313b7ef296838782d72e367509c4283990fb7fda261e453629e0b44f268ece649ae2889ec67dea07c31a6b4b3f2f799178367c016d4
|
|
7
|
+
data.tar.gz: 205dad627f2752573f9f8e9c9a17e8e5a1ec3ad2260bad68a041b38d783060ee5f399950928a8b7f6ea8bf3b450d23878ec5fac7247d7c5e067b323348b4acf0
|
|
@@ -51,10 +51,8 @@ module ForestLiana
|
|
|
51
51
|
def separate_database?(resource, association)
|
|
52
52
|
return false if SchemaUtils.polymorphic?(association)
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
resource_connection = resource.connection
|
|
57
|
-
resource_database = resource_connection.current_database if resource_connection.respond_to? :current_database
|
|
54
|
+
target_model_database = association.klass.connection.pool.db_config.database
|
|
55
|
+
resource_database = resource.connection.pool.db_config.database
|
|
58
56
|
|
|
59
57
|
target_model_database != resource_database
|
|
60
58
|
end
|
|
@@ -266,6 +266,9 @@ module ForestLiana
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
collection.fields = collection.fields.reject do |field|
|
|
269
|
+
# NOTICE: A primary key column must survive; a type column is never one.
|
|
270
|
+
next false if field[:is_primary_key]
|
|
271
|
+
|
|
269
272
|
field[:field] == association.foreign_key || field[:field] == association.foreign_type
|
|
270
273
|
end
|
|
271
274
|
# NOTICE: Delete the association if the targeted model is excluded.
|
|
@@ -274,7 +277,8 @@ module ForestLiana
|
|
|
274
277
|
x[:field] == association.foreign_key
|
|
275
278
|
end
|
|
276
279
|
|
|
277
|
-
|
|
280
|
+
# NOTICE: A primary key column must survive, even as an excluded association's FK.
|
|
281
|
+
collection.fields.delete(field) if field && !field[:is_primary_key]
|
|
278
282
|
# NOTICE: The foreign key exists, so it's a belongsTo relationship.
|
|
279
283
|
elsif (field = column_association(collection, association)) &&
|
|
280
284
|
[:has_one, :belongs_to].include?(association.macro)
|
data/lib/forest_liana/version.rb
CHANGED
|
@@ -83,26 +83,6 @@ module ForestLiana
|
|
|
83
83
|
let(:resource) { Product }
|
|
84
84
|
let(:fields) { { resource.name => 'id,name,manufacturer', 'manufacturer' => 'name' } }
|
|
85
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
86
|
shared_examples 'records' do
|
|
107
87
|
it 'should get only the expected records' do
|
|
108
88
|
getter.perform
|
|
@@ -117,40 +97,38 @@ module ForestLiana
|
|
|
117
97
|
end
|
|
118
98
|
end
|
|
119
99
|
|
|
120
|
-
context 'when the
|
|
121
|
-
|
|
100
|
+
context 'when the included association is in the same database' do
|
|
101
|
+
it 'performs a left outer join with the association' do
|
|
102
|
+
expect(getter.perform.to_sql).to match(/LEFT OUTER JOIN "manufacturers"/)
|
|
103
|
+
end
|
|
104
|
+
|
|
122
105
|
include_examples 'records'
|
|
123
106
|
end
|
|
124
107
|
|
|
125
|
-
context 'when the included association
|
|
108
|
+
context 'when the included association is in a different database' do
|
|
126
109
|
let(:fields) { { resource.name => 'id,name,driver', 'driver' => 'firstname' } }
|
|
127
110
|
|
|
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
111
|
it 'does not perform a left outer join with the association' do
|
|
145
112
|
expect(getter.perform.to_sql).not_to match(/LEFT OUTER JOIN "drivers"/)
|
|
146
113
|
end
|
|
114
|
+
|
|
115
|
+
include_examples 'records'
|
|
147
116
|
end
|
|
148
117
|
|
|
149
|
-
|
|
150
|
-
|
|
118
|
+
it 'resolves the database without issuing a SQL query' do
|
|
119
|
+
getter
|
|
151
120
|
|
|
152
|
-
|
|
153
|
-
|
|
121
|
+
queries = []
|
|
122
|
+
subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |*, payload|
|
|
123
|
+
queries << payload[:sql] unless payload[:name] == 'SCHEMA' || payload[:cached]
|
|
124
|
+
end
|
|
125
|
+
begin
|
|
126
|
+
getter.send(:separate_database?, Product, Product.reflect_on_association(:manufacturer))
|
|
127
|
+
ensure
|
|
128
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
expect(queries).to be_empty
|
|
154
132
|
end
|
|
155
133
|
end
|
|
156
134
|
|
|
@@ -86,6 +86,62 @@ module ForestLiana
|
|
|
86
86
|
ForestLiana.apimap << original if original
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
test 'a primary key column that is also the foreign key of an excluded association is kept' do
|
|
90
|
+
excluded_models = ForestLiana.excluded_models
|
|
91
|
+
name = ForestLiana.name_for(BelongsToField)
|
|
92
|
+
original = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
93
|
+
ForestLiana.apimap.delete(original) if original
|
|
94
|
+
ForestLiana.excluded_models = [ForestLiana.name_for(HasOneField)]
|
|
95
|
+
BelongsToField.define_singleton_method(:primary_key) { 'has_one_field_id' }
|
|
96
|
+
|
|
97
|
+
schema = SchemaAdapter.new(BelongsToField).perform
|
|
98
|
+
field = schema.fields.find { |f| f[:field] == 'has_one_field_id' }
|
|
99
|
+
|
|
100
|
+
refute_nil field, 'the primary key column must not be deleted'
|
|
101
|
+
assert_equal true, field[:is_primary_key]
|
|
102
|
+
ensure
|
|
103
|
+
BelongsToField.singleton_class.send(:remove_method, :primary_key)
|
|
104
|
+
ForestLiana.excluded_models = excluded_models
|
|
105
|
+
rebuilt = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
106
|
+
ForestLiana.apimap.delete(rebuilt) if rebuilt
|
|
107
|
+
ForestLiana.apimap << original if original
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
test 'an ordinary foreign key of an excluded association is still deleted' do
|
|
111
|
+
excluded_models = ForestLiana.excluded_models
|
|
112
|
+
name = ForestLiana.name_for(BelongsToField)
|
|
113
|
+
original = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
114
|
+
ForestLiana.apimap.delete(original) if original
|
|
115
|
+
ForestLiana.excluded_models = [ForestLiana.name_for(HasOneField)]
|
|
116
|
+
|
|
117
|
+
schema = SchemaAdapter.new(BelongsToField).perform
|
|
118
|
+
|
|
119
|
+
assert_nil schema.fields.find { |f| f[:field] == 'has_one_field_id' }
|
|
120
|
+
ensure
|
|
121
|
+
ForestLiana.excluded_models = excluded_models
|
|
122
|
+
rebuilt = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
123
|
+
ForestLiana.apimap.delete(rebuilt) if rebuilt
|
|
124
|
+
ForestLiana.apimap << original if original
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
test 'a primary key column that is also a polymorphic foreign key is kept' do
|
|
128
|
+
name = ForestLiana.name_for(PolymorphicField)
|
|
129
|
+
original = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
130
|
+
ForestLiana.apimap.delete(original) if original
|
|
131
|
+
PolymorphicField.define_singleton_method(:primary_key) { 'has_one_field_id' }
|
|
132
|
+
|
|
133
|
+
schema = SchemaAdapter.new(PolymorphicField).perform
|
|
134
|
+
field = schema.fields.find { |f| f[:field] == 'has_one_field_id' }
|
|
135
|
+
|
|
136
|
+
refute_nil field, 'the primary key column must not be rejected'
|
|
137
|
+
assert_equal true, field[:is_primary_key]
|
|
138
|
+
ensure
|
|
139
|
+
PolymorphicField.singleton_class.send(:remove_method, :primary_key)
|
|
140
|
+
rebuilt = ForestLiana.apimap.find { |c| c.name.to_s == name }
|
|
141
|
+
ForestLiana.apimap.delete(rebuilt) if rebuilt
|
|
142
|
+
ForestLiana.apimap << original if original
|
|
143
|
+
end
|
|
144
|
+
|
|
89
145
|
test 'belongsTo relationship' do
|
|
90
146
|
schema = SchemaAdapter.new(BelongsToField).perform
|
|
91
147
|
fields = schema.fields.select do |field|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forest_liana
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 9.20.
|
|
4
|
+
version: 9.20.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sandro Munda
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|