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