lib/baza_models/autoloader.rb
class BazaModels::Autoloader
def initialize(args)
@models = args.fetch(:models)
@model_class = @models.first.class
@autoloads = args.fetch(:autoloads)
@db = args.fetch(:db)
@debug = args[:debug]
debug "Autoloading #{@autoloads} on #{@model_class.name} with ID's: #{@models.map(&:id)}" if @debug
end
def autoload
autoload_argument(@autoloads)
end
private
def debug(msg)
print "#{msg}\n" if @debug
end
def model_ids
@model_ids ||= @models.map(&:id)
end
def autoload_argument(autoload)
if autoload.is_a?(Hash)
autoload_hash(autoload)
elsif autoload.is_a?(Array)
autoload_array(autoload)
elsif autoload.is_a?(Symbol)
autoload_symbol(autoload)
else
raise "Didn't know what to do with autoload: #{autoload} (#{autoload.class.name})"
end
end
def autoload_array(autoload)
autoload.each do |autoload_i|
autoload_argument(autoload_i)
end
end
def autoload_hash(autoload)
autoload.each do |autoload_key, autoload_value|
result = autoload_symbol(autoload_key)
next if result.fetch(:models).empty?
autoloader = BazaModels::Autoloader.new(
models: result.fetch(:models),
autoloads: autoload_value,
db: @db,
debug: @debug
)
autoloader.autoload
end
end
def autoload_symbol(autoload)
relation = @model_class.relationships.fetch(autoload)
if relation.fetch(:type) == :has_many
autoload_has_many(autoload, relation)
elsif relation.fetch(:type) == :belongs_to
autoload_belongs_to(autoload, relation)
elsif relation.fetch(:type) == :has_one
autoload_has_one(autoload, relation)
else
raise "Unknown relation type: #{relation.fetch(:type)}"
end
end
def autoload_belongs_to(autoload_name, relation)
result = {models: []}
model_id_mappings = {}
model_ids = []
@models.each do |model|
key = model.data.fetch(relation.fetch(:foreign_key))
next if model_id_mappings.key?(key)
model_ids << key
model_id_mappings[key] = model.id
end
@db.select(relation.fetch(:table_name), id: model_ids) do |model_data|
model = StringCases.constantize(relation.fetch(:class_name)).new(model_data, init: true)
orig_model_id = model_id_mappings.fetch(model_data.fetch(:id))
orig_model = @models.detect { |array_model| array_model.id == orig_model_id }
orig_model.autoloads[autoload_name] ||= model
result.fetch(:models) << model
end
result
end
def autoload_has_many(autoload_name, relation)
result = {models: []}
@db.select(relation.fetch(:table_name), relation.fetch(:foreign_key) => model_ids) do |model_data|
model = StringCases.constantize(relation.fetch(:class_name)).new(model_data, init: true)
orig_model_id = model_data.fetch(relation.fetch(:foreign_key).to_sym)
orig_model = @models.detect { |array_model| array_model.id == orig_model_id }
orig_model.autoloads[autoload_name] ||= []
orig_model.autoloads[autoload_name] << model
result.fetch(:models) << model
end
result
end
def autoload_has_one(autoload_name, relation)
result = {models: []}
@db.select(relation.fetch(:table_name), relation.fetch(:foreign_key) => model_ids) do |model_data|
model = StringCases.constantize(relation.fetch(:class_name)).new(model_data, init: true)
orig_model_id = model_data.fetch(relation.fetch(:foreign_key))
orig_model = @models.detect { |array_model| array_model.id == orig_model_id }
raise "Already autoloaded?" if orig_model.autoloads.key?(autoload_name)
orig_model.autoloads[autoload_name] = model
result.fetch(:models) << model
end
result
end
end