switchman 3.1.3 → 3.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54ae135ce532aa5578592027f6ce46cf3aedecdf0a6fd097ae3597752f436bae
4
- data.tar.gz: 02d88f28e64e487c6841940a383afd92a56378ea7c2e4b1156252c0bcf0fa71f
3
+ metadata.gz: 20c8d947a29c73c09af7d1c880ef03aff2185c927d30954bb304b4592a7b4051
4
+ data.tar.gz: 5973474196cc2c8f2957932a65261998de24a6be3653cedeff374c1fe1fa925f
5
5
  SHA512:
6
- metadata.gz: 383075584faafb39abc64be4f6e77a99c4ca3dfd5acc1c57bae885ba71c8d13ce2cb0f89d9332fd8387f5100886a5a0ffbb6f6d53e382b0e54412aea6b72cf06
7
- data.tar.gz: 875421e2c515a671ed8503fd07b55d22e16f098ddde635b5530a3ab4801c9bebd06a5e4e75d7a547b1e84e5628288dac9aefc0c6f9a23cedad80b1f8389bb5de
6
+ metadata.gz: 10f59abb9c44a3b6e8ec3e87419862f5959ec8086117172d6fc044911c0efb3d96ec320fc04630e482200fbf99da4a7a8d7a291137bbf9ce019f1e7a54f5eeb0
7
+ data.tar.gz: 72fc286e4f143bf9d8344aa6e4a0405161e476b23eada4fd956f2657a1911c4e93acad649e76cb17e444821060085110d12c2cfe0a5f115bf9b7ddc598fb17ea
@@ -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}"
@@ -25,7 +25,7 @@ module Switchman
25
25
  # we can make some assumptions about the shard source
26
26
  # (e.g. infer from the primary key or use the current shard)
27
27
 
28
- def execute(*args)
28
+ def execute(*args, &block)
29
29
  params, connection = args
30
30
  klass = @klass
31
31
  target_shard = nil
@@ -40,7 +40,7 @@ module Switchman
40
40
 
41
41
  target_shard.activate(klass.connection_class_for_self) do
42
42
  sql = qualified_query_builder(target_shard, klass).sql_for(bind_values, connection)
43
- klass.find_by_sql(sql, bind_values)
43
+ klass.find_by_sql(sql, bind_values, &block)
44
44
  end
45
45
  end
46
46
 
@@ -66,7 +66,11 @@ module Switchman
66
66
 
67
67
  def primary_value_index
68
68
  primary_ba_index = @bound_attributes.index do |ba|
69
- ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.primary
69
+ if ba.value.is_a?(::ActiveRecord::StatementCache::Substitute)
70
+ ba.is_a?(::ActiveRecord::Relation::QueryAttribute) && ba.value.primary
71
+ else
72
+ false
73
+ end
70
74
  end
71
75
  @indexes.index(primary_ba_index) if primary_ba_index
72
76
  end
@@ -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.3'
4
+ VERSION = '3.2.1'
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.3
4
+ version: 3.2.1
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-08-03 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