Module: Switchman::ActiveRecord::Associations::Preloader::Association

Defined in:
lib/switchman/active_record/associations.rb

Defined Under Namespace

Modules: LoaderRecords

Instance Method Summary collapse

Instance Method Details

#load_records(raw_records = nil) ⇒ Object

significant changes:

* partition_by_shard the records_for call
* re-globalize the fetched owner id before looking up in the map

TODO: the ignored param currently loads records; we should probably not waste effort double-loading them Change introduced here: github.com/rails/rails/commit/c6c0b2e8af64509b699b782aadfecaa430700ece



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/switchman/active_record/associations.rb', line 203

def load_records(raw_records = nil)
  # owners can be duplicated when a relation has a collection association join
  # #compare_by_identity makes such owners different hash keys
  @records_by_owner = {}.compare_by_identity

  raw_records ||= loader_query.records_for([self])

  @preloaded_records = raw_records.select do |record|
    assignments = false

    owner_key = record[association_key_name]
    if owner_key && record.class.sharded_column?(association_key_name)
      owner_key = Shard.global_id_for(owner_key,
                                      record.shard)
    end

    owners_by_key[convert_key(owner_key)]&.each do |owner|
      entries = (@records_by_owner[owner] ||= [])

      if reflection.collection? || entries.empty?
        entries << record
        assignments = true
      end
    end

    assignments
  end
end

#owners_by_keyObject

significant change: globalize keys on sharded columns



233
234
235
236
237
238
239
240
# File 'lib/switchman/active_record/associations.rb', line 233

def owners_by_key
  @owners_by_key ||= owners.each_with_object({}) do |owner, result|
    key = owner[owner_key_name]
    key = Shard.global_id_for(key, owner.shard) if key && owner.class.sharded_column?(owner_key_name)
    key = convert_key(key)
    (result[key] ||= []) << owner if key
  end
end

#records_for(ids) ⇒ Object

Copypasta from Activerecord but with added global_id_for goodness.



165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/switchman/active_record/associations.rb', line 165

def records_for(ids)
  scope.where(association_key_name => ids).load do |record|
    global_key = if model.connection_class_for_self == UnshardedRecord
                   convert_key(record[association_key_name])
                 else
                   Shard.global_id_for(record[association_key_name], record.shard)
                 end
    owner = owners_by_key[convert_key(global_key)].first
    association = owner.association(reflection.name)
    association.set_inverse_instance(record)
  end
end

#scopeObject

significant change: don’t cache scope (since it could be for different shards)



243
244
245
# File 'lib/switchman/active_record/associations.rb', line 243

def scope
  build_scope
end

#set_inverse(record) ⇒ Object

Disabling to keep closer to rails original rubocop:disable Naming/AccessorMethodName significant changes:

* globalize the key to lookup


182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/switchman/active_record/associations.rb', line 182

def set_inverse(record)
  global_key = if model.connection_class_for_self == UnshardedRecord
                 convert_key(record[association_key_name])
               else
                 Shard.global_id_for(record[association_key_name], record.shard)
               end

  if (owners = owners_by_key[convert_key(global_key)])
    # Processing only the first owner
    # because the record is modified but not an owner
    association = owners.first.association(reflection.name)
    association.set_inverse_instance(record)
  end
end