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