module ApiResource
module Finders
extend ActiveSupport::Concern
extend ActiveSupport::Autoload
autoload :AbstractFinder
autoload :ResourceFinder
autoload :SingleFinder
autoload :SingleObjectAssociationFinder
autoload :MultiObjectAssociationFinder
module ClassMethods
# This decides which finder method to call.
# It accepts arguments of the form "scope", "options={}"
# where options can be standard rails options or :expires_in.
# If :expires_in is set, it caches it for expires_in seconds.
# Need to support the following cases
# => 1) Klass.find(1)
# => 2) Klass.find(:all, :params => {a => b})
# => 3) Klass.find(:first, :params => {a => b})
# => 4) Klass.includes(:assoc).find(1)
# => 5) Klass.active.find(1)
# => 6) Klass.includes(:assoc).find(:all, a => b)
def find(*arguments)
# make sure we have class data before loading
self.load_resource_definition
scope = arguments.slice!(0)
options = arguments.slice!(0) || {}
cond = arguments.slice!(0)
# TODO: Make this into a class attribute properly (if it isn't already)
# this is a little bit of a hack because options can sometimes be a Condition
expiry = (options.is_a?(Hash) ? options.delete(:expires_in) : nil) || ApiResource::Base.ttl || 0
ApiResource.with_ttl(expiry.to_f) do
case scope
when :all, :first, :last
final_cond = ApiResource::Conditions::ScopeCondition.new({}, self)
# we need new conditions here to take into account options, which could
# either be a Condition object or a hash
if options.is_a?(Hash)
opts = options.with_indifferent_access.delete(:params) || options || {}
final_cond = ApiResource::Conditions::ScopeCondition.new(opts, self)
# cond may be nil
unless cond == nil # THIS MUST BE == NOT nil?
final_cond = cond.merge!(final_cond)
end
elsif options.is_a?(ApiResource::Conditions::AbstractCondition)
final_cond = options
end
# now final cond contains all the conditions we should need to pass to the finder
fnd = ApiResource::Finders::ResourceFinder.new(self, final_cond)
fnd.send(scope)
else
# in this case scope is the id we want to find, and options should be a condition object or nil
final_cond = ApiResource::Conditions::ScopeCondition.new({:id => scope}, self)
if options.is_a?(ApiResource::Conditions::AbstractCondition)
final_cond = options.merge!(final_cond)
elsif options.is_a?(Hash)
opts = options.with_indifferent_access.delete(:params) || options || {}
final_cond = ApiResource::Conditions::ScopeCondition.new(opts, self).merge!(final_cond)
end
ApiResource::Finders::SingleFinder.new(self, final_cond).load
end
end
end
# A convenience wrapper for find(:first, *args). You can pass
# in all the same arguments to this method as you can to
# find(:first).
def first(*args)
find(:first, *args)
end
# A convenience wrapper for find(:last, *args). You can pass
# in all the same arguments to this method as you can to
# find(:last).
def last(*args)
find(:last, *args)
end
# This is an alias for find(:all). You can pass in all the same
# arguments to this method as you can to find(:all)
def all(*args)
find(:all, *args)
end
def instantiate_collection(collection)
collection.collect{|record|
instantiate_record(record)
}
end
def instantiate_record(record)
self.load_resource_definition
ret = self.allocate
ret.instance_variable_set(
:@attributes, record.with_indifferent_access
)
ret.instance_variable_set(
:@attributes_cache, HashWithIndifferentAccess.new
)
ret
end
end
end
end