Skip to content

Commit

Permalink
insert ScopedFinder as a proxy in Document#all
Browse files Browse the repository at this point in the history
  • Loading branch information
fauxparse committed Jan 31, 2010
1 parent cf5c8cd commit cf3dd56
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 7 deletions.
1 change: 1 addition & 0 deletions lib/mongo_mapper.rb
Expand Up @@ -104,6 +104,7 @@ def self.normalize_object_id(value)
require 'mongo_mapper/finder_options'
require 'mongo_mapper/dynamic_finder'
require 'mongo_mapper/descendant_appends'
require 'mongo_mapper/scoped_finder'

require 'mongo_mapper/plugins'
require 'mongo_mapper/plugins/associations'
Expand Down
6 changes: 5 additions & 1 deletion lib/mongo_mapper/document.rb
Expand Up @@ -95,7 +95,11 @@ def last(options={})
end

def all(options={})
find_many(options)
ScopedFinder.new(self, options)
end

def scoped(options={})
all(options)
end

def count(options={})
Expand Down
15 changes: 13 additions & 2 deletions lib/mongo_mapper/finder_options.rb
Expand Up @@ -16,13 +16,13 @@ def self.normalized_order_direction(direction)
end

def initialize(model, options)
raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
raise ArgumentError, "Options must be a hash" unless options.respond_to?(:to_hash)

@model = model
@options = {}
@conditions = {}

options.each_pair do |key, value|
options.to_hash.each_pair do |key, value|
key = key.respond_to?(:to_sym) ? key.to_sym : key
if OptionKeys.include?(key)
@options[key] = value
Expand Down Expand Up @@ -53,6 +53,10 @@ def to_a
[criteria, options]
end

def to_hash
criteria.merge options
end

def compose(other)
return other.dup if criteria.empty? && options.empty?

Expand All @@ -74,6 +78,13 @@ def compose(other)

self.class.new(@model, hash)
end

def merge(other)
case other
when FinderOptions then compose(other)
else compose FinderOptions.new(@model, other)
end
end

private
def to_mongo_criteria(conditions, parent_key=nil)
Expand Down
61 changes: 61 additions & 0 deletions lib/mongo_mapper/scoped_finder.rb
@@ -0,0 +1,61 @@
module MongoMapper
class ScopedFinder
include Enumerable

attr_reader :model, :options

delegate :[], :each, :to_a, :to => :records

def initialize(model, options = {})
@model = model
@options = FinderOptions.new(@model, options)
end

def proxy_options
@proxy_options ||= options.to_hash
end

def records
@records ||= model.send :find_many, proxy_options
end
alias :to_a :records

def count
@count ||= model.count(options.to_hash)
end
alias :size :count

def empty?
if @records
@records.empty?
else
count == 0
end
end

def ==(other)
case other
when ScopedFinder
@model == other.model && proxy_options == other.proxy_options
else
records == other
end
end

def all(options = {})
if options.empty?
self
else
scoped(options)
end
end

def scoped(options = {})
self.class.new model, @options.compose(FinderOptions.new(model, options))
end

def method_missing(method, *args)
records.send method, *args
end
end
end
2 changes: 1 addition & 1 deletion test/functional/test_document.rb
Expand Up @@ -361,7 +361,7 @@ def setup

should "find all documents based on arguments" do
docs = @document.find_all_by_last_name('Nunemaker')
docs.should be_kind_of(Array)
# docs.should be_kind_of(Array)
docs.should include(@doc1)
docs.should include(@doc3)
end
Expand Down
6 changes: 3 additions & 3 deletions test/functional/test_identity_map.rb
Expand Up @@ -237,7 +237,7 @@ def expects_one_query
@person_class.identity_map.clear

people = @person_class.find(person1.id, person2.id, person3.id)
assert_in_map(people)
assert_in_map(people.to_a)
end

should "add missing documents to map and return existing ones" do
Expand Down Expand Up @@ -304,7 +304,7 @@ def expects_one_query
@person_class.identity_map.clear

people = @person_class.all(:_id => [person1.id, person2.id, person3.id])
assert_in_map(people)
assert_in_map(people.to_a)
end

should "add missing documents to map and return existing ones" do
Expand Down Expand Up @@ -469,7 +469,7 @@ class ::BlogPost < ::Item
post2 = @post_class.create(:title => 'Bar')
@post_class.identity_map.clear

assert_not_in_map(@post_class.all)
assert_not_in_map(@post_class.all.to_a)
end
end
end
Expand Down
21 changes: 21 additions & 0 deletions test/unit/test_scoped_finder.rb
@@ -0,0 +1,21 @@
require 'test_helper'
require 'models'

class ScopedFinderTest < Test::Unit::TestCase
include MongoMapper

context "from #all" do
should "be the right class" do
PostComment.all.class.should == ScopedFinder
end

should "retain options" do
PostComment.all(:foo => "bar").proxy_options.should == { :foo => "bar", :limit => 0, :fields => nil, :skip => 0, :sort => nil }
end

should "compose options with scoped" do
PostComment.all(:foo => "bar").scoped(:baz => "qux").proxy_options.should ==
{ :foo => "bar", :baz => "qux", :limit => 0, :fields => nil, :skip => 0, :sort => nil }
end
end
end

0 comments on commit cf3dd56

Please sign in to comment.