module Switchman::ActiveRecord::AttributeMethods::ClassMethods
Public Instance Methods
sharded_column?(column_name)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 18 def sharded_column?(column_name) column_name = column_name.to_s @sharded_column_values ||= {} unless @sharded_column_values.key?(column_name) @sharded_column_values[column_name] = (column_name == primary_key && sharded_primary_key?) || sharded_foreign_key?(column_name) end @sharded_column_values[column_name] end
sharded_foreign_key?(column_name)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 11 def sharded_foreign_key?(column_name) reflection = reflection_for_integer_attribute(column_name.to_s) return false unless reflection reflection.options[:polymorphic] || reflection.klass.sharded_primary_key? end
sharded_primary_key?()
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 7 def sharded_primary_key? !(self <= UnshardedRecord) && integral_id? end
Protected Instance Methods
connection_classes_code_for_reflection(reflection)
click to toggle source
see also Base#connection_classes_for_reflection
the difference being this will output static strings for the common cases, making them more performant
# File lib/switchman/active_record/attribute_methods.rb, line 66 def connection_classes_code_for_reflection(reflection) if reflection if reflection.options[:polymorphic] # a polymorphic association has to be discovered at runtime. This code ends up being something like # context_type.&.constantize&.connection_classes "read_attribute(:#{reflection.foreign_type})&.constantize&.connection_classes" else # otherwise we can just return a symbol for the statically known type of the association "::#{reflection.klass.connection_classes.name}" end else "::#{connection_classes.name}" end end
define_method_global_attribute(attr_name, owner:)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 39 def define_method_global_attribute(attr_name, owner:) if sharded_column?(attr_name) owner << <<-RUBY def global_#{attr_name} ::Switchman::Shard.global_id_for(original_#{attr_name}, shard) end RUBY else define_method_unsharded_column(attr_name, 'global', owner) end end
define_method_local_attribute(attr_name, owner:)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 51 def define_method_local_attribute(attr_name, owner:) if sharded_column?(attr_name) owner << <<-RUBY def local_#{attr_name} ::Switchman::Shard.local_id_for(original_#{attr_name}).first end RUBY else define_method_unsharded_column(attr_name, 'local', owner) end end
define_method_original_attribute(attr_name, owner:)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 93 def define_method_original_attribute(attr_name, owner:) if sharded_column?(attr_name) reflection = reflection_for_integer_attribute(attr_name) if attr_name == 'id' return if method_defined?(:original_id) owner = CodeGenerator.new(self, __LINE__ + 4) end owner << <<-RUBY # rename the original method to original_* alias_method 'original_#{attr_name}', '#{attr_name}' # and replace with one that transposes the id def #{attr_name} ::Switchman::Shard.relative_id_for(original_#{attr_name}, shard, ::Switchman::Shard.current(#{connection_classes_code_for_reflection(reflection)})) end alias_method 'original_#{attr_name}=', '#{attr_name}=' def #{attr_name}=(new_value) self.original_#{attr_name} = ::Switchman::Shard.relative_id_for(new_value, ::Switchman::Shard.current(#{connection_classes_code_for_reflection(reflection)}), shard) end RUBY else define_method_unsharded_column(attr_name, 'global', owner) end end
define_method_unsharded_column(attr_name, prefix, owner)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 120 def define_method_unsharded_column(attr_name, prefix, owner) return if columns_hash["#{prefix}_#{attr_name}"] owner << <<-RUBY def #{prefix}_#{attr_name} raise NoMethodError, "undefined method `#{prefix}_#{attr_name}'; are you missing an association?" end RUBY end
reflection_for_integer_attribute(attr_name)
click to toggle source
# File lib/switchman/active_record/attribute_methods.rb, line 30 def reflection_for_integer_attribute(attr_name) attr_name = attr_name.to_s columns_hash[attr_name] && columns_hash[attr_name].type == :integer && reflections.find { |_, r| r.belongs_to? && r.foreign_key.to_s == attr_name }&.last rescue ::ActiveRecord::StatementInvalid # this is for when models are referenced in initializers before migrations have been run raise if connection.open_transactions.positive? end