torque-postgresql 3.2.2 → 3.3.1
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/lib/torque/postgresql/adapter/database_statements.rb +3 -3
- data/lib/torque/postgresql/adapter/schema_creation.rb +1 -1
- data/lib/torque/postgresql/adapter/schema_statements.rb +6 -0
- data/lib/torque/postgresql/associations/preloader/loader_query.rb +7 -7
- data/lib/torque/postgresql/config.rb +5 -2
- data/lib/torque/postgresql/reflection/association_reflection.rb +1 -1
- data/lib/torque/postgresql/schema_cache/bound_schema_reflection.rb +25 -0
- data/lib/torque/postgresql/schema_cache/inheritance.rb +117 -0
- data/lib/torque/postgresql/schema_cache/schema_reflection.rb +25 -0
- data/lib/torque/postgresql/schema_cache.rb +33 -105
- data/lib/torque/postgresql/version.rb +1 -1
- data/spec/tests/has_many_spec.rb +41 -0
- data/spec/tests/schema_spec.rb +2 -2
- data/spec/tests/table_inheritance_spec.rb +30 -11
- metadata +11 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8dfe147f5a65e1626923bff250d8c057c73e2fc2c2f2ea6812d67537da32e38
|
4
|
+
data.tar.gz: 3205fea618ea9da4d9aeccf3b5d48e3dff72a4a670e181c78c9b9a0b9896cfbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce88617dcacc292754245e9fff7f7dba62ec672a5b7b4760fff2ff2b28b4b25be7e8413b92bf509f5f9f9c4d0b096559b7ec46de4fdce5294181c363f34367fb
|
7
|
+
data.tar.gz: 6c3e8e96edd6b906bd2f0038869f9f15596fad7f22745c5bd63c08b623a55cf97f6185877206dac54a7e93e81ce5d7644bfeb048e7e2db1780bb7cadc7843159
|
@@ -176,11 +176,11 @@ module Torque
|
|
176
176
|
# Build the query for allowed schemas
|
177
177
|
def user_defined_schemas_sql
|
178
178
|
conditions = []
|
179
|
-
conditions << <<-SQL if schemas_blacklist.any?
|
180
|
-
nspname NOT LIKE
|
179
|
+
conditions << <<-SQL.squish if schemas_blacklist.any?
|
180
|
+
nspname NOT LIKE ALL (ARRAY['#{schemas_blacklist.join("', '")}'])
|
181
181
|
SQL
|
182
182
|
|
183
|
-
conditions << <<-SQL if schemas_whitelist.any?
|
183
|
+
conditions << <<-SQL.squish if schemas_whitelist.any?
|
184
184
|
nspname LIKE ANY (ARRAY['#{schemas_whitelist.join("', '")}'])
|
185
185
|
SQL
|
186
186
|
|
@@ -122,6 +122,12 @@ module Torque
|
|
122
122
|
super.sub('SELECT c.relname FROM', "SELECT n.nspname || '.' || c.relname FROM")
|
123
123
|
end
|
124
124
|
|
125
|
+
# Add schema and inherits as one of the valid options for table
|
126
|
+
# definition
|
127
|
+
def valid_table_definition_options
|
128
|
+
super + [:schema, :inherits]
|
129
|
+
end
|
130
|
+
|
125
131
|
private
|
126
132
|
|
127
133
|
# Remove the schema from the sequence name
|
@@ -11,20 +11,20 @@ module Torque
|
|
11
11
|
|
12
12
|
def load_records_for_keys(keys, &block)
|
13
13
|
condition = query_condition_for(keys)
|
14
|
+
return super if condition.nil?
|
15
|
+
|
14
16
|
scope.where(condition).load(&block)
|
15
17
|
end
|
16
18
|
|
17
19
|
def query_condition_for(keys)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
{ association_key_name => keys }
|
23
|
-
end
|
20
|
+
return unless connected_through_array?
|
21
|
+
|
22
|
+
value = scope.cast_for_condition(foreign_column, keys.to_a)
|
23
|
+
scope.table[association_key_name].overlaps(value)
|
24
24
|
end
|
25
25
|
|
26
26
|
def connected_through_array?
|
27
|
-
foreign_column.array?
|
27
|
+
!association_key_name.is_a?(Array) && foreign_column.array?
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -4,6 +4,9 @@ module Torque
|
|
4
4
|
module PostgreSQL
|
5
5
|
include ActiveSupport::Configurable
|
6
6
|
|
7
|
+
# Stores a version check for compatibility purposes
|
8
|
+
AR710 = (ActiveRecord.gem_version >= Gem::Version.new('7.1.0'))
|
9
|
+
|
7
10
|
# Use the same logger as the Active Record one
|
8
11
|
def self.logger
|
9
12
|
ActiveRecord::Base.logger
|
@@ -17,8 +20,8 @@ module Torque
|
|
17
20
|
send("#{name}=", klass)
|
18
21
|
end
|
19
22
|
|
20
|
-
# Set if any information that requires querying and searching or
|
21
|
-
# information
|
23
|
+
# Set if any information that requires querying and searching or collecting
|
24
|
+
# information should be eager loaded. This automatically changes when rails
|
22
25
|
# same configuration is set to true
|
23
26
|
config.eager_load = false
|
24
27
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Torque
|
4
|
+
module PostgreSQL
|
5
|
+
module BoundSchemaReflection
|
6
|
+
def add_model_name(table_name, model)
|
7
|
+
@schema_reflection.add_model_name(@connection, table_name, model)
|
8
|
+
end
|
9
|
+
|
10
|
+
def dependencies(table_name)
|
11
|
+
@schema_reflection.dependencies(@connection, table_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def associations(table_name)
|
15
|
+
@schema_reflection.associations(@connection, table_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def lookup_model(table_name, scoped_class = '')
|
19
|
+
@schema_reflection.lookup_model(@connection, table_name, scoped_class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveRecord::ConnectionAdapters::BoundSchemaReflection.prepend BoundSchemaReflection
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Torque
|
4
|
+
module PostgreSQL
|
5
|
+
module SchemaCache
|
6
|
+
module Inheritance
|
7
|
+
|
8
|
+
# Try to find a model based on a given table
|
9
|
+
def lookup_model(table_name, scoped_class = '', source_to_model:)
|
10
|
+
scoped_class = scoped_class.name if scoped_class.is_a?(Class)
|
11
|
+
return source_to_model[table_name] if source_to_model.key?(table_name)
|
12
|
+
|
13
|
+
# Get all the possible scopes
|
14
|
+
scopes = scoped_class.scan(/(?:::)?[A-Z][a-z]+/)
|
15
|
+
scopes.unshift('Object::')
|
16
|
+
|
17
|
+
# Check if the table name comes with a schema
|
18
|
+
if table_name.include?('.')
|
19
|
+
schema, table_name = table_name.split('.')
|
20
|
+
scopes.insert(1, schema.camelize) if schema != 'public'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Consider the maximum namespaced possible model name
|
24
|
+
max_name = table_name.tr('_', '/').camelize.split(/(::)/)
|
25
|
+
max_name[-1] = max_name[-1].singularize
|
26
|
+
|
27
|
+
# Test all the possible names against all the possible scopes
|
28
|
+
until scopes.size == 0
|
29
|
+
scope = scopes.join.chomp('::').safe_constantize
|
30
|
+
model = find_model(max_name, table_name, scope) unless scope.nil?
|
31
|
+
return source_to_model[table_name] = model unless model.nil?
|
32
|
+
scopes.pop
|
33
|
+
end
|
34
|
+
|
35
|
+
# If this part is reach, no model name was found
|
36
|
+
raise LookupError.new(<<~MSG.squish)
|
37
|
+
Unable to find a valid model that is associated with the
|
38
|
+
'#{table_name}' table. Please, check if they correctly inherit from
|
39
|
+
ActiveRecord::Base
|
40
|
+
MSG
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# Find a model by a given max namespaced class name that matches the
|
46
|
+
# given table name
|
47
|
+
def find_model(max_name, table_name, scope = Object)
|
48
|
+
pieces = max_name.is_a?(::Array) ? max_name : max_name.split(/(::)/)
|
49
|
+
ns_places = (1..(max_name.size - 1)).step(2).to_a
|
50
|
+
|
51
|
+
# Generate all possible combinations
|
52
|
+
conditions = []
|
53
|
+
range = Torque::PostgreSQL.config.inheritance.inverse_lookup \
|
54
|
+
? 0.upto(ns_places.size) \
|
55
|
+
: ns_places.size.downto(0)
|
56
|
+
range.each do |size|
|
57
|
+
conditions.concat(ns_places.combination(size).to_a)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Now iterate over
|
61
|
+
while (condition = conditions.shift)
|
62
|
+
ns_places.each do |i|
|
63
|
+
pieces[i] = condition.include?(i) ? '::' : ''
|
64
|
+
end
|
65
|
+
|
66
|
+
candidate = pieces.join
|
67
|
+
candidate.prepend("#{scope.name}::") unless scope === Object
|
68
|
+
|
69
|
+
klass = candidate.safe_constantize
|
70
|
+
next if klass.nil?
|
71
|
+
|
72
|
+
# Check if the class match the table name
|
73
|
+
return klass if klass < ::ActiveRecord::Base &&
|
74
|
+
klass.table_name == table_name
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Calculates the inverted dependency (association), where even indirect
|
79
|
+
# inheritance comes up in the list
|
80
|
+
def generate_associations(inheritance_dependencies)
|
81
|
+
return {} if inheritance_dependencies.empty?
|
82
|
+
|
83
|
+
result = Hash.new{ |h, k| h[k] = [] }
|
84
|
+
masters = inheritance_dependencies.values.flatten.uniq
|
85
|
+
|
86
|
+
# Add direct associations
|
87
|
+
masters.map do |master|
|
88
|
+
inheritance_dependencies.each do |(dependent, associations)|
|
89
|
+
result[master] << dependent if associations.include?(master)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Add indirect associations
|
94
|
+
result.each do |master, children|
|
95
|
+
children.each do |child|
|
96
|
+
children.concat(result[child]).uniq! if result.key?(child)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Remove the default proc that would create new entries
|
101
|
+
result.default_proc = nil
|
102
|
+
result
|
103
|
+
end
|
104
|
+
|
105
|
+
# Parse the Torque config into the proper hash of irregular models.
|
106
|
+
# This is smart enough to only load necessary models
|
107
|
+
def prepare_irregular_models(data_sources)
|
108
|
+
entries = Torque::PostgreSQL.config.irregular_models
|
109
|
+
entries.slice(*data_sources).each_with_object({}) do |(table, model), hash|
|
110
|
+
hash[table] = model.is_a?(Class) ? model : model.constantize
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Torque
|
4
|
+
module PostgreSQL
|
5
|
+
module SchemaReflection
|
6
|
+
def add_model_name(connection, table_name, model)
|
7
|
+
cache(connection).add_model_name(connection, table_name, model)
|
8
|
+
end
|
9
|
+
|
10
|
+
def dependencies(connection, table_name)
|
11
|
+
cache(connection).dependencies(connection, table_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def associations(connection, table_name)
|
15
|
+
cache(connection).associations(connection, table_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def lookup_model(connection, table_name, scoped_class)
|
19
|
+
cache(connection).lookup_model(table_name, scoped_class)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ActiveRecord::ConnectionAdapters::SchemaReflection.prepend SchemaReflection
|
24
|
+
end
|
25
|
+
end
|
@@ -1,11 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'torque/postgresql/schema_cache/inheritance'
|
4
|
+
|
5
|
+
if Torque::PostgreSQL::AR710
|
6
|
+
require 'torque/postgresql/schema_cache/schema_reflection'
|
7
|
+
require 'torque/postgresql/schema_cache/bound_schema_reflection'
|
8
|
+
end
|
9
|
+
|
3
10
|
module Torque
|
4
11
|
module PostgreSQL
|
5
12
|
LookupError = Class.new(ArgumentError)
|
6
13
|
|
7
14
|
# :TODO: Create the +add+ to load inheritance info
|
8
15
|
module SchemaCache
|
16
|
+
include Torque::PostgreSQL::SchemaCache::Inheritance
|
9
17
|
|
10
18
|
def initialize(*) # :nodoc:
|
11
19
|
super
|
@@ -37,7 +45,7 @@ module Torque
|
|
37
45
|
@inheritance_associations = coder['inheritance_associations']
|
38
46
|
end
|
39
47
|
|
40
|
-
def add(table_name, *) # :nodoc:
|
48
|
+
def add(connection_or_table_name, table_name = connection_or_table_name, *) # :nodoc:
|
41
49
|
super
|
42
50
|
|
43
51
|
# Reset inheritance information when a table is added
|
@@ -64,8 +72,8 @@ module Torque
|
|
64
72
|
].map(&:size).inject(:+)
|
65
73
|
end
|
66
74
|
|
67
|
-
def clear_data_source_cache!(name) # :nodoc:
|
68
|
-
super
|
75
|
+
def clear_data_source_cache!(connection_or_name, name = connection_or_name) # :nodoc:
|
76
|
+
Torque::PostgreSQL::AR710 ? super : super(name)
|
69
77
|
@data_sources_model_names.delete name
|
70
78
|
@inheritance_dependencies.delete name
|
71
79
|
@inheritance_associations.delete name
|
@@ -89,94 +97,37 @@ module Torque
|
|
89
97
|
end
|
90
98
|
|
91
99
|
# A way to manually add models name so it doesn't need the lookup method
|
92
|
-
def add_model_name(
|
93
|
-
|
94
|
-
|
100
|
+
def add_model_name(*args)
|
101
|
+
model, *source = args.reverse
|
102
|
+
return unless data_source_exists?(*source.reverse) && model.is_a?(Class)
|
103
|
+
|
104
|
+
@data_sources_model_names[source.first] = model
|
95
105
|
end
|
96
106
|
|
97
107
|
# Get all the tables that the given one inherits from
|
98
|
-
def dependencies(table_name)
|
99
|
-
reload_inheritance_data!
|
108
|
+
def dependencies(conn, table_name = conn)
|
109
|
+
reload_inheritance_data!(conn == table_name ? connection : conn)
|
100
110
|
@inheritance_dependencies[table_name]
|
101
111
|
end
|
102
112
|
|
103
113
|
# Get the list of all tables that are associated (direct or indirect
|
104
114
|
# inheritance) with the provided one
|
105
|
-
def associations(table_name)
|
106
|
-
reload_inheritance_data!
|
115
|
+
def associations(conn, table_name = conn)
|
116
|
+
reload_inheritance_data!(conn == table_name ? connection : conn)
|
107
117
|
@inheritance_associations[table_name]
|
108
118
|
end
|
109
119
|
|
110
|
-
#
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
if @data_sources_model_names.key?(table_name)
|
115
|
-
|
116
|
-
# Get all the possible scopes
|
117
|
-
scopes = scoped_class.scan(/(?:::)?[A-Z][a-z]+/)
|
118
|
-
scopes.unshift('Object::')
|
119
|
-
|
120
|
-
# Check if the table name comes with a schema
|
121
|
-
if table_name.include?('.')
|
122
|
-
schema, table_name = table_name.split('.')
|
123
|
-
scopes.insert(1, schema.camelize) if schema != 'public'
|
124
|
-
end
|
125
|
-
|
126
|
-
# Consider the maximum namespaced possible model name
|
127
|
-
max_name = table_name.tr('_', '/').camelize.split(/(::)/)
|
128
|
-
max_name[-1] = max_name[-1].singularize
|
129
|
-
|
130
|
-
# Test all the possible names against all the possible scopes
|
131
|
-
until scopes.size == 0
|
132
|
-
scope = scopes.join.chomp('::').safe_constantize
|
133
|
-
model = find_model(max_name, table_name, scope) unless scope.nil?
|
134
|
-
return @data_sources_model_names[table_name] = model unless model.nil?
|
135
|
-
scopes.pop
|
136
|
-
end
|
137
|
-
|
138
|
-
# If this part is reach, no model name was found
|
139
|
-
raise LookupError.new(<<~MSG.squish)
|
140
|
-
Unable to find a valid model that is associated with the '#{table_name}' table.
|
141
|
-
Please, check if they correctly inherit from ActiveRecord::Base
|
142
|
-
MSG
|
120
|
+
# Override the inheritance implementation to pass over the proper cache of
|
121
|
+
# the existing association between data sources and model names
|
122
|
+
def lookup_model(*args, **xargs)
|
123
|
+
super(*args, **xargs, source_to_model: @data_sources_model_names)
|
143
124
|
end
|
144
125
|
|
145
126
|
private
|
146
127
|
|
147
|
-
# Find a model by a given max namespaced class name thath matches the
|
148
|
-
# given table name
|
149
|
-
def find_model(max_name, table_name, scope = Object)
|
150
|
-
pieces = max_name.is_a?(::Array) ? max_name : max_name.split(/(::)/)
|
151
|
-
ns_places = (1..(max_name.size - 1)).step(2).to_a
|
152
|
-
|
153
|
-
# Generate all possible combinarions
|
154
|
-
conditions = []
|
155
|
-
range = Torque::PostgreSQL.config.inheritance.inverse_lookup \
|
156
|
-
? 0.upto(ns_places.size) \
|
157
|
-
: ns_places.size.downto(0)
|
158
|
-
range.each do |size|
|
159
|
-
conditions.concat(ns_places.combination(size).to_a)
|
160
|
-
end
|
161
|
-
|
162
|
-
# Now iterate over
|
163
|
-
while (condition = conditions.shift)
|
164
|
-
ns_places.each{ |i| pieces[i] = condition.include?(i) ? '::' : '' }
|
165
|
-
|
166
|
-
candidate = pieces.join
|
167
|
-
candidate.prepend("#{scope.name}::") unless scope === Object
|
168
|
-
|
169
|
-
klass = candidate.safe_constantize
|
170
|
-
next if klass.nil?
|
171
|
-
|
172
|
-
# Check if the class match the table name
|
173
|
-
return klass if klass < ::ActiveRecord::Base && klass.table_name == table_name
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
128
|
# Reload information about tables inheritance and dependencies, uses a
|
178
|
-
# cache to not perform additional
|
179
|
-
def reload_inheritance_data!
|
129
|
+
# cache to not perform additional checks
|
130
|
+
def reload_inheritance_data!(connection)
|
180
131
|
return if @inheritance_loaded
|
181
132
|
@inheritance_dependencies = connection.inherited_tables
|
182
133
|
@inheritance_associations = generate_associations
|
@@ -186,38 +137,15 @@ module Torque
|
|
186
137
|
# Calculates the inverted dependency (association), where even indirect
|
187
138
|
# inheritance comes up in the list
|
188
139
|
def generate_associations
|
189
|
-
|
190
|
-
|
191
|
-
result = Hash.new{ |h, k| h[k] = [] }
|
192
|
-
masters = @inheritance_dependencies.values.flatten.uniq
|
193
|
-
|
194
|
-
# Add direct associations
|
195
|
-
masters.map do |master|
|
196
|
-
@inheritance_dependencies.each do |(dependent, associations)|
|
197
|
-
result[master] << dependent if associations.include?(master)
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
# Add indirect associations
|
202
|
-
result.each do |master, children|
|
203
|
-
children.each do |child|
|
204
|
-
children.concat(result[child]).uniq! if result.key?(child)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
# Remove the default proc that would create new entries
|
209
|
-
result.default_proc = nil
|
210
|
-
result
|
140
|
+
super(@inheritance_dependencies)
|
211
141
|
end
|
212
142
|
|
213
|
-
# Use this method to also load any irregular model name
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
[table_name, (model_name.is_a?(Class) ? model_name : model_name.constantize)]
|
220
|
-
end.to_h
|
143
|
+
# Use this method to also load any irregular model name
|
144
|
+
def prepare_data_sources(connection = nil)
|
145
|
+
Torque::PostgreSQL::AR710 ? super : super()
|
146
|
+
|
147
|
+
sources = connection.present? ? tables_to_cache(connection) : @data_sources.keys
|
148
|
+
@data_sources_model_names = prepare_irregular_models(sources)
|
221
149
|
end
|
222
150
|
|
223
151
|
end
|
data/spec/tests/has_many_spec.rb
CHANGED
@@ -201,6 +201,47 @@ RSpec.describe 'HasMany' do
|
|
201
201
|
expect(query.to_sql).to match(/INNER JOIN "texts"/)
|
202
202
|
expect { query.load }.not_to raise_error
|
203
203
|
end
|
204
|
+
|
205
|
+
context 'with query constraint' do
|
206
|
+
let(:activity) { Activity.create! }
|
207
|
+
|
208
|
+
before do
|
209
|
+
skip('Only Rails 7.1 onwards') unless Post.respond_to?(:query_constraints)
|
210
|
+
|
211
|
+
Post.query_constraints :author_id, :id
|
212
|
+
Activity.query_constraints :author_id, :id
|
213
|
+
Activity.has_many :posts
|
214
|
+
end
|
215
|
+
|
216
|
+
after do
|
217
|
+
Post.instance_variable_set(:@has_query_constraints, false)
|
218
|
+
Post.instance_variable_set(:@query_constraints_list, nil)
|
219
|
+
Post.instance_variable_set(:@_query_constraints_list, nil)
|
220
|
+
Activity.instance_variable_set(:@has_query_constraints, false)
|
221
|
+
Activity.instance_variable_set(:@query_constraints_list, nil)
|
222
|
+
Activity.instance_variable_set(:@_query_constraints_list, nil)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'properly preload records' do
|
226
|
+
FactoryBot.create_list(:post, 5, activity: activity)
|
227
|
+
entries = Activity.all.includes(:posts).load
|
228
|
+
|
229
|
+
expect(entries.size).to be_eql(1)
|
230
|
+
expect(entries.first.posts).to be_loaded
|
231
|
+
expect(entries.first.posts.size).to be_eql(5)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'properly preload records using preloader' do
|
235
|
+
FactoryBot.create_list(:post, 5, activity: activity)
|
236
|
+
entries = ActiveRecord::Associations::Preloader.new(
|
237
|
+
records: Activity.all,
|
238
|
+
associations: [:posts],
|
239
|
+
).call.first.records_by_owner
|
240
|
+
|
241
|
+
expect(entries.size).to be_eql(1)
|
242
|
+
expect(entries.values.first.size).to be_eql(5)
|
243
|
+
end
|
244
|
+
end
|
204
245
|
end
|
205
246
|
|
206
247
|
context 'on array' do
|
data/spec/tests/schema_spec.rb
CHANGED
@@ -4,8 +4,8 @@ RSpec.describe 'Schema' do
|
|
4
4
|
let(:connection) { ActiveRecord::Base.connection }
|
5
5
|
|
6
6
|
before do
|
7
|
-
connection.instance_variable_set(:@
|
8
|
-
connection.instance_variable_set(:@
|
7
|
+
connection.instance_variable_set(:@schemas_blacklist, nil)
|
8
|
+
connection.instance_variable_set(:@schemas_whitelist, nil)
|
9
9
|
end
|
10
10
|
|
11
11
|
context 'on migration' do
|
@@ -104,7 +104,12 @@ RSpec.describe 'TableInheritance' do
|
|
104
104
|
end
|
105
105
|
|
106
106
|
context 'on schema cache' do
|
107
|
-
|
107
|
+
let(:schema_cache) { ActiveRecord::Base.connection.schema_cache }
|
108
|
+
let(:schema_cache_connection) { schema_cache.instance_variable_get(:@connection) }
|
109
|
+
let(:schema_cache_reflection) { schema_cache.instance_variable_get(:@schema_reflection) }
|
110
|
+
let(:new_schema_cache) { schema_cache_reflection.send(:cache, schema_cache_connection) }
|
111
|
+
|
112
|
+
subject { Torque::PostgreSQL::AR710 ? new_schema_cache : schema_cache }
|
108
113
|
|
109
114
|
it 'correctly defines the associations' do
|
110
115
|
scenario = {
|
@@ -120,6 +125,7 @@ RSpec.describe 'TableInheritance' do
|
|
120
125
|
subject.instance_variable_set(:@inheritance_loaded, true)
|
121
126
|
subject.instance_variable_set(:@inheritance_dependencies, scenario)
|
122
127
|
subject.instance_variable_set(:@inheritance_associations, subject.send(:generate_associations))
|
128
|
+
subject.instance_variable_set(:@data_sources_model_names, {})
|
123
129
|
expect(subject.instance_variable_get(:@inheritance_associations)).to eql({
|
124
130
|
'A' => %w(B D C N M),
|
125
131
|
'B' => %w(C N M),
|
@@ -131,6 +137,8 @@ RSpec.describe 'TableInheritance' do
|
|
131
137
|
end
|
132
138
|
|
133
139
|
context 'on looking up models' do
|
140
|
+
let(:prepare_arguments) { Torque::PostgreSQL::AR710 ? [schema_cache_connection] : nil }
|
141
|
+
|
134
142
|
after(:all) do
|
135
143
|
schema_cache = ActiveRecord::Base.connection.schema_cache
|
136
144
|
schema_cache.instance_variable_set(:@data_sources, {})
|
@@ -138,26 +146,35 @@ RSpec.describe 'TableInheritance' do
|
|
138
146
|
end
|
139
147
|
|
140
148
|
it 'respect irregular names' do
|
141
|
-
Torque::PostgreSQL.config.irregular_models
|
142
|
-
'posts' => 'ActivityPost',
|
143
|
-
}
|
149
|
+
allow(Torque::PostgreSQL.config).to receive(:irregular_models).and_return({
|
150
|
+
'public.posts' => 'ActivityPost',
|
151
|
+
})
|
144
152
|
|
145
|
-
subject.send(:prepare_data_sources)
|
153
|
+
subject.send(:prepare_data_sources, *prepare_arguments)
|
146
154
|
list = subject.instance_variable_get(:@data_sources_model_names)
|
147
|
-
expect(list).to have_key('posts')
|
148
|
-
expect(list['posts']).to eql(ActivityPost)
|
155
|
+
expect(list).to have_key('public.posts')
|
156
|
+
expect(list['public.posts']).to eql(ActivityPost)
|
149
157
|
end
|
150
158
|
|
151
159
|
it 'does not load irregular where the data source is not defined' do
|
152
|
-
Torque::PostgreSQL.config.irregular_models
|
160
|
+
allow(Torque::PostgreSQL.config).to receive(:irregular_models).and_return({
|
153
161
|
'products' => 'Product',
|
154
|
-
}
|
162
|
+
})
|
155
163
|
|
156
|
-
subject.send(:prepare_data_sources)
|
164
|
+
subject.send(:prepare_data_sources, *prepare_arguments)
|
157
165
|
list = subject.instance_variable_get(:@data_sources_model_names)
|
158
166
|
expect(list).to_not have_key('products')
|
159
167
|
end
|
160
168
|
|
169
|
+
it 'works with eager loading' do
|
170
|
+
allow(Torque::PostgreSQL.config).to receive(:eager_load).and_return(true)
|
171
|
+
ActivityPost.reset_table_name
|
172
|
+
|
173
|
+
list = subject.instance_variable_get(:@data_sources_model_names)
|
174
|
+
expect(list).to have_key('activity_posts')
|
175
|
+
expect(list['activity_posts']).to eql(ActivityPost)
|
176
|
+
end
|
177
|
+
|
161
178
|
{
|
162
179
|
'activities' => 'Activity',
|
163
180
|
'activity_posts' => 'ActivityPost',
|
@@ -176,6 +193,8 @@ RSpec.describe 'TableInheritance' do
|
|
176
193
|
let(:child2) { ActivityBook }
|
177
194
|
let(:other) { AuthorJournalist }
|
178
195
|
|
196
|
+
before { ActiveRecord::Base.connection.schema_cache.clear! }
|
197
|
+
|
179
198
|
it 'identifies mergeable attributes' do
|
180
199
|
result_base = %w(id author_id title active kind created_at updated_at description url file post_id)
|
181
200
|
expect(base.inheritance_mergeable_attributes.sort).to eql(result_base.sort)
|
@@ -228,7 +247,7 @@ RSpec.describe 'TableInheritance' do
|
|
228
247
|
expect(other.table_name).to eql('authors')
|
229
248
|
end
|
230
249
|
|
231
|
-
it 'respects the table name prefix and
|
250
|
+
it 'respects the table name prefix and suffix defined on parent module' do
|
232
251
|
mod = Object.const_set('Private', Module.new)
|
233
252
|
mod.define_singleton_method(:table_name_prefix) { 'private.' }
|
234
253
|
mod.define_singleton_method(:table_name_suffix) { '_bundle' }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: torque-postgresql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Silva
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -64,20 +64,14 @@ dependencies:
|
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
68
|
-
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
version: 1.5.3
|
67
|
+
version: '2.0'
|
71
68
|
type: :development
|
72
69
|
prerelease: false
|
73
70
|
version_requirements: !ruby/object:Gem::Requirement
|
74
71
|
requirements:
|
75
72
|
- - "~>"
|
76
73
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
78
|
-
- - ">="
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: 1.5.3
|
74
|
+
version: '2.0'
|
81
75
|
- !ruby/object:Gem::Dependency
|
82
76
|
name: dotenv
|
83
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -233,6 +227,9 @@ files:
|
|
233
227
|
- lib/torque/postgresql/relation/inheritance.rb
|
234
228
|
- lib/torque/postgresql/relation/merger.rb
|
235
229
|
- lib/torque/postgresql/schema_cache.rb
|
230
|
+
- lib/torque/postgresql/schema_cache/bound_schema_reflection.rb
|
231
|
+
- lib/torque/postgresql/schema_cache/inheritance.rb
|
232
|
+
- lib/torque/postgresql/schema_cache/schema_reflection.rb
|
236
233
|
- lib/torque/postgresql/table_name.rb
|
237
234
|
- lib/torque/postgresql/version.rb
|
238
235
|
- spec/en.yml
|
@@ -292,7 +289,8 @@ licenses:
|
|
292
289
|
metadata:
|
293
290
|
source_code_uri: https://github.com/crashtech/torque-postgresql
|
294
291
|
bug_tracker_uri: https://github.com/crashtech/torque-postgresql/issues
|
295
|
-
|
292
|
+
changelog_uri: https://github.com/crashtech/torque-postgresql/releases
|
293
|
+
post_install_message:
|
296
294
|
rdoc_options:
|
297
295
|
- "--title"
|
298
296
|
- Torque PostgreSQL
|
@@ -310,7 +308,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
310
308
|
version: 1.8.11
|
311
309
|
requirements: []
|
312
310
|
rubygems_version: 3.2.15
|
313
|
-
signing_key:
|
311
|
+
signing_key:
|
314
312
|
specification_version: 4
|
315
313
|
summary: ActiveRecord extension to access PostgreSQL advanced resources
|
316
314
|
test_files:
|