lib/api_resource/finders.rb in api_resource-0.6.16 vs lib/api_resource/finders.rb in api_resource-0.6.17
- old
+ new
@@ -27,46 +27,117 @@
# => 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)
+ # Conditions sometimes call find, passing themselves as the last arg.
+ if arguments.last.is_a?(ApiResource::Conditions::AbstractCondition)
+ cond = arguments.slice!(arguments.length - 1)
+ else
+ cond = nil
+ end
+ # Support options being passed in as a hash.
+ options = arguments.extract_options! || {}
+
+ # Remaining arguments are the scope.
+ scope = arguments
+
# 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 we have a condition or options to process...
+ if cond || options.present?
+
+ # Convert options hash to scope condition.
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)
+ options = ApiResource::Conditions::ScopeCondition.new(opts, self)
+ end
+
+ # Combine all combinations of conditions and options
+ if cond
+ if options
+ final_cond = cond.merge!(options)
+ else
+ final_cond = cond
end
- elsif options.is_a?(ApiResource::Conditions::AbstractCondition)
+ elsif options
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)
+
+ # If we have one argument, it's either a word argument
+ # like first, last, or all, or its a number.
+ if Array.wrap(scope).size == 1
+ scope = scope.first if scope.is_a?(Array)
+
+ # Create the finder with the conditions, then call the scope.
+ # e.g. Class.scope(1).first
+ if [:all, :first, :last].include?(scope)
+ fnd = ApiResource::Finders::ResourceFinder.new(self, final_cond)
+ fnd.send(scope)
+
+ # If we have no conditions or they are only prefixes or
+ # includes,and only one argument (not a word) then we
+ # only have a single item to find.
+ # e.g. Class.includes.find(1)
+ elsif final_cond.blank_conditions? || final_cond.conditions.include?(:foreign_key_id)
+ scope = scope.first if scope.is_a?(Array)
+ final_cond = final_cond.merge!(ApiResource::Conditions::ScopeCondition.new({:id => scope}, self))
+
+ ApiResource::Finders::SingleFinder.new(self, final_cond).load
+ else
+
+ # Otherwise we are chaining a find onto
+ # the end of a set of conditions.
+ # e.g. Class.scope(1).find(1)
+ fnd = final_cond.merge!(ApiResource::Conditions::ScopeCondition.new({:find => {:ids => scope}}, self))
+ fnd.send(:all)
+ end
+
+ else
+
+ # We are searching for multiple ids.
+ # e.g. Class.scope(1).find(1,2)
+ fnd = final_cond.merge!(ApiResource::Conditions::ScopeCondition.new({:find => {:ids => scope}}, self))
+ fnd.send(:all)
+ end
+
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)
+
+ # No conditions
+ if Array.wrap(scope).size == 1
+ scope = scope.first if scope.is_a?(Array)
+
+ # We are calling first, last, or all on the class itself.
+ # e.g. Class.first
+ if [:all, :first, :last].include?(scope)
+ final_cond = ApiResource::Conditions::ScopeCondition.new({scope => true}, self)
+
+ fnd = ApiResource::Finders::ResourceFinder.new(self, final_cond)
+ fnd.send(scope)
+ else
+
+ # We are performing a simple find of a single object
+ # e.g. Class.find(1)
+ scope = scope.first if scope.is_a?(Array)
+ final_cond = ApiResource::Conditions::ScopeCondition.new({:id => scope}, self)
+
+ ApiResource::Finders::SingleFinder.new(self, final_cond).load
+ end
+
+ else
+ # We are performing a find on multiple objects
+ # e.g. Class.find(1,2)
+ ApiResource::Conditions::ScopeCondition.new({:find => {:ids => scope}}, self)
+ fnd.send(:all)
+
end
- ApiResource::Finders::SingleFinder.new(self, final_cond).load
+
end
+
end
end
# A convenience wrapper for <tt>find(:first, *args)</tt>. You can pass
\ No newline at end of file