switchman 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb62453808b659106e48a2279bdabeb2901c97187eaf8ae6cd612d460096f6d0
4
- data.tar.gz: 5cf42b899e7a63f73bf5604247a8e2b2cd4a998bd7f4f0986180e451e66d3cc0
3
+ metadata.gz: 39d8ce1bd79211b12278263fda3f0a88adc841051bd1e4f52e8d01ccd371978f
4
+ data.tar.gz: b126fe1b7b700fb424351d901c58b66f9719892deab08a2242de6cf6c5645b77
5
5
  SHA512:
6
- metadata.gz: 69d3bb8a559d81a5cb5ef81c7c19395c3eab13a9a53a0bd920ea715b822cde6256a2464f317a6f719c04c8f9baf99b751b6abb07ae6edda40055cd53b32c5a30
7
- data.tar.gz: e16d69bb4d2ec76fbe198a8d0d68e4217f3b2a261eff1fcde61b82357374f5c1b029e28f9ec852c090196461d2f45d162bc0c420182ccf0d3b7a4869f4ff5263
6
+ metadata.gz: 266b29135322d76e811feb72414a5c3a1621afe07e65175672092ddefd21296b73fa3fe3ce1b6ce0d34b2e5d1a071b186f0b859b44398ff65e3a19cc3e747830
7
+ data.tar.gz: e26ecce87b654d3dd8ae8caa3111b9cbbc89896ce00cca467ba4bd66527ddf76c2e0db1c4ebff30cd133dbcefc1580f4f6b2dc745ab795813cf85848893badca
@@ -83,16 +83,62 @@ module Switchman
83
83
 
84
84
  module Preloader
85
85
  module Association
86
- module LoaderQuery
87
- def load_records_in_batch(loaders)
88
- # While in theory loading multiple associations that end up being effectively the same would be nice
89
- # it's not very switchman compatible, so just don't bother trying to use that logic
90
- # raw_records = records_for(loaders)
86
+ # significant changes:
87
+ # * associate shards with records
88
+ # * look on all appropriate shards when loading records
89
+ module LoaderRecords
90
+ def populate_keys_to_load_and_already_loaded_records
91
+ @sharded_keys_to_load = {}
91
92
 
92
93
  loaders.each do |loader|
93
- loader.load_records(nil)
94
- loader.run
94
+ multishard = loader.send(:reflection).options[:multishard]
95
+ belongs_to = loader.send(:reflection).macro == :belongs_to
96
+ loader.owners_by_key.each do |key, owners|
97
+ if (loaded_owner = owners.find { |owner| loader.loaded?(owner) })
98
+ already_loaded_records_by_key[key] = loader.target_for(loaded_owner)
99
+ else
100
+ shard_set = @sharded_keys_to_load[key] ||= Set.new
101
+ owner_key_name = loader.send(:owner_key_name)
102
+ owners.each do |owner|
103
+ if multishard && owner.respond_to?(:associated_shards)
104
+ shard_set.merge(owner.associated_shards.map(&:id))
105
+ elsif belongs_to && owner.class.sharded_column?(owner_key_name)
106
+ shard_set.add(Shard.shard_for(owner[owner_key_name], owner.shard).id)
107
+ elsif belongs_to
108
+ shard_set.add(Shard.current.id)
109
+ else
110
+ shard_set.add(owner.shard.id)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ @sharded_keys_to_load.delete_if { |key, _shards| already_loaded_records_by_key.include?(key) }
118
+ end
119
+
120
+ def load_records
121
+ ret = []
122
+
123
+ shards_with_keys = @sharded_keys_to_load.each_with_object({}) do |(key, shards), h|
124
+ shards.each { |shard| (h[shard] ||= []) << key }
125
+ end
126
+
127
+ shards_with_keys.each do |shard, keys|
128
+ Shard.lookup(shard).activate do
129
+ scope_was = loader_query.scope
130
+ begin
131
+ loader_query.instance_variable_set(:@scope, loader_query.scope.shard(Shard.current(loader_query.scope.model.connection_class_for_self)))
132
+ ret += loader_query.load_records_for_keys(keys) do |record|
133
+ loaders.each { |l| l.set_inverse(record) }
134
+ end
135
+ ensure
136
+ loader_query.instance_variable_set(:@scope, scope_was)
137
+ end
138
+ end
95
139
  end
140
+
141
+ ret
96
142
  end
97
143
  end
98
144
 
@@ -110,6 +156,26 @@ module Switchman
110
156
  end
111
157
  end
112
158
 
159
+ # Disabling to keep closer to rails original
160
+ # rubocop:disable Naming/AccessorMethodName, Style/GuardClause
161
+ # significant changes:
162
+ # * globalize the key to lookup
163
+ def set_inverse(record)
164
+ global_key = if model.connection_class_for_self == UnshardedRecord
165
+ convert_key(record[association_key_name])
166
+ else
167
+ Shard.global_id_for(record[association_key_name], record.shard)
168
+ end
169
+
170
+ if (owners = owners_by_key[convert_key(global_key)])
171
+ # Processing only the first owner
172
+ # because the record is modified but not an owner
173
+ association = owners.first.association(reflection.name)
174
+ association.set_inverse_instance(record)
175
+ end
176
+ end
177
+ # rubocop:enable Naming/AccessorMethodName, Style/GuardClause
178
+
113
179
  # significant changes:
114
180
  # * partition_by_shard the records_for call
115
181
  # * re-globalize the fetched owner id before looking up in the map
@@ -120,7 +186,9 @@ module Switchman
120
186
  # #compare_by_identity makes such owners different hash keys
121
187
  @records_by_owner = {}.compare_by_identity
122
188
 
123
- if ::Rails.version < '7.0' && owner_keys.empty?
189
+ if ::Rails.version >= '7.0'
190
+ raw_records ||= loader_query.records_for([self])
191
+ elsif owner_keys.empty?
124
192
  raw_records ||= []
125
193
  else
126
194
  # determine the shard to search for each owner
@@ -162,7 +230,7 @@ module Switchman
162
230
  record.shard)
163
231
  end
164
232
 
165
- owners_by_key[convert_key(owner_key)].each do |owner|
233
+ owners_by_key[convert_key(owner_key)]&.each do |owner|
166
234
  entries = (@records_by_owner[owner] ||= [])
167
235
 
168
236
  if reflection.collection? || entries.empty?
@@ -99,7 +99,7 @@ module Switchman
99
99
  if reflection.options[:polymorphic]
100
100
  # a polymorphic association has to be discovered at runtime. This code ends up being something like
101
101
  # context_type.&.constantize&.connection_class_for_self
102
- "read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self"
102
+ "begin;read_attribute(:#{reflection.foreign_type})&.constantize&.connection_class_for_self;rescue NameError;::ActiveRecord::Base;end"
103
103
  else
104
104
  # otherwise we can just return a symbol for the statically known type of the association
105
105
  "::#{reflection.klass.connection_class_for_self.name}"
@@ -22,16 +22,20 @@ module Switchman
22
22
  @integral_id
23
23
  end
24
24
 
25
- def transaction(**)
26
- if self != ::ActiveRecord::Base && current_scope
27
- current_scope.activate do
28
- db = Shard.current(connection_class_for_self).database_server
29
- db.unguard { super }
25
+ %w[transaction insert_all upsert_all].each do |method|
26
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
27
+ def #{method}(*, **)
28
+ if self != ::ActiveRecord::Base && current_scope
29
+ current_scope.activate do
30
+ db = Shard.current(connection_class_for_self).database_server
31
+ db.unguard { super }
32
+ end
33
+ else
34
+ db = Shard.current(connection_class_for_self).database_server
35
+ db.unguard { super }
36
+ end
30
37
  end
31
- else
32
- db = Shard.current(connection_class_for_self).database_server
33
- db.unguard { super }
34
- end
38
+ RUBY
35
39
  end
36
40
 
37
41
  def reset_column_information
@@ -138,7 +142,7 @@ module Switchman
138
142
  else
139
143
  Shard.current(self.class.connection_class_for_self)
140
144
  end
141
- readonly! if shadow_record?
145
+ readonly! if shadow_record? && !Switchman.config[:writable_shadow_records]
142
146
  super
143
147
  end
144
148
 
@@ -50,7 +50,7 @@ module Switchman
50
50
  ::ActiveRecord::Associations::CollectionProxy.include(ActiveRecord::Associations::CollectionProxy)
51
51
 
52
52
  ::ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecord::Associations::Preloader::Association)
53
- ::ActiveRecord::Associations::Preloader::Association::LoaderQuery.prepend(ActiveRecord::Associations::Preloader::Association::LoaderQuery) unless ::Rails.version < '7.0'
53
+ ::ActiveRecord::Associations::Preloader::Association::LoaderRecords.prepend(ActiveRecord::Associations::Preloader::Association::LoaderRecords) unless ::Rails.version < '7.0'
54
54
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::AbstractAdapter)
55
55
  ::ActiveRecord::ConnectionAdapters::ConnectionPool.prepend(ActiveRecord::ConnectionPool)
56
56
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.prepend(ActiveRecord::QueryCache)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- VERSION = '3.1.2'
4
+ VERSION = '3.2.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2022-07-19 00:00:00.000000000 Z
13
+ date: 2022-11-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord