module ETL #:nodoc:
module Transform #:nodoc:
# Transform which looks up the value and replaces it with a foriegn key reference
class ForeignKeyLookupTransform < ETL::Transform::Transform
# The resolver to use if the foreign key is not found in the collection
attr_accessor :resolver
# Initialize the foreign key lookup transform.
#
# Configuration options:
# *:collection: A Hash of natural keys mapped to surrogate keys. If this is not specified then
# an empty Hash will be used. This Hash will be used to cache values that have been resolved already
# for future use.
# *:resolver: Object or Class which implements the method resolve(value)
def initialize(control, configuration={})
super
@collection = (configuration[:collection] || {})
@resolver = configuration[:resolver]
@resolver = @resolver.new if @resolver.is_a?(Class)
end
# Transform the value by resolving it to a foriegn key
def transform(value)
fk = @collection[value]
unless fk
raise ResolverError, "Foreign key for #{value} not found and no resolver specified" unless resolver
raise ResolverError, "Resolver does not appear to respond to resolve method" unless resolver.respond_to?(:resolve)
fk = resolver.resolve(value)
raise ResolverError, "Unable to resolve #{value} to foreign key" unless fk
@collection[value] = fk
end
fk
end
end
# Alias class name for the ForeignKeyLookupTransform.
class FkLookupTransform < ForeignKeyLookupTransform; end
end
end
# Resolver which resolves using ActiveRecord.
class ActiveRecordResolver
# The ActiveRecord class to use
attr_accessor :ar_class
# The find method to use (as a symbol)
attr_accessor :find_method
# Initialize the resolver. The ar_class argument should extend from ActiveRecord::Base. The find_method argument
# must be a symbol for the finder method used. For example:
#
# ActiveRecordResolver.new(Person, :find_by_name)
#
# Note that the find method defined must only take a single argument.
def initialize(ar_class, find_method)
@ar_class = ar_class
@find_method = find_method
end
# Resolve the value
def resolve(value)
rec = ar_class.__send__(find_method, value)
rec.nil? ? nil : rec.id
end
end