Skip to content

Commit

Permalink
Merge branch 'plucky'
Browse files Browse the repository at this point in the history
  • Loading branch information
jnunemaker committed May 18, 2010
2 parents f7f935c + 389638d commit 16ac32d
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 290 deletions.
1 change: 1 addition & 0 deletions Rakefile
Expand Up @@ -13,6 +13,7 @@ Jeweler::Tasks.new do |gem|
gem.version = MongoMapper::Version

gem.add_dependency('activesupport', '>= 2.3.4')
gem.add_dependency('plucky', '0.1')
gem.add_dependency('mongo', '1.0')
gem.add_dependency('jnunemaker-validatable', '1.8.4')

Expand Down
2 changes: 2 additions & 0 deletions lib/mongo_mapper.rb
Expand Up @@ -2,11 +2,13 @@
# gem 'activesupport', '>= 2.3.4'
# gem 'mongo', '1.0'
# gem 'jnunemaker-validatable', '1.8.4'
# gem 'plucky', '0.1'
require 'set'
require 'uri'
require 'mongo'
require 'validatable'
require 'active_support/all'
require 'plucky'

module MongoMapper
# generic MM error
Expand Down
76 changes: 23 additions & 53 deletions lib/mongo_mapper/document.rb
Expand Up @@ -45,34 +45,31 @@ def ensure_index(spec, options={})
end

def find(*args)
assert_no_first_last_or_all(args)
options = args.extract_options!
return nil if args.size == 0

if args.first.is_a?(Array) || args.size > 1
find_some(args, options)
else
find_one(options.merge({:_id => args[0]}))
query = query(options).update(:_id => args[0])
find_one(query.to_hash)
end
end

def find!(*args)
assert_no_first_last_or_all(args)
options = args.extract_options!
raise DocumentNotFound, "Couldn't find without an ID" if args.size == 0

if args.first.is_a?(Array) || args.size > 1
find_some!(args, options)
else
find_one(options.merge({:_id => args[0]})) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
query = query(options).update(:_id => args[0])
find_one(query.to_hash) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
end
end

def find_each(options={})
criteria, options = to_query(options)
collection.find(criteria, options).each do |doc|
yield load(doc)
end
query(options).find().each { |doc| yield load(doc) }
end

def find_by_id(id)
Expand All @@ -93,15 +90,15 @@ def first(options={})

def last(options={})
raise ':order option must be provided when using last' if options[:order].blank?
find_one(options.merge(:order => invert_order_clause(options[:order])))
find_one(query(options).reverse.to_hash)
end

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

def count(options={})
collection.find(to_criteria(options)).count
query(options).count
end

def exists?(options={})
Expand All @@ -126,11 +123,11 @@ def update(*args)
end

def delete(*ids)
collection.remove(to_criteria(:_id => ids.flatten))
query(:_id => ids.flatten).remove
end

def delete_all(options={})
collection.remove(to_criteria(options))
query(options).remove
end

def destroy(*ids)
Expand All @@ -153,6 +150,11 @@ def single_collection_inherited_superclass?
superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
end

# @api private for now
def query(options={})
Query.new(self, options)
end

private
def initialize_each(*docs)
instances = []
Expand All @@ -165,15 +167,9 @@ def initialize_each(*docs)
instances.size == 1 ? instances[0] : instances
end

def assert_no_first_last_or_all(args)
if args[0] == :first || args[0] == :last || args[0] == :all
raise ArgumentError, "#{self}.find(:#{args}) is no longer supported, use #{self}.#{args} instead."
end
end

def find_some(ids, options={})
ids = ids.flatten.compact.uniq
find_many(options.merge(:_id => ids)).compact
query = query(options).update(:_id => ids.flatten.compact.uniq)
find_many(query.to_hash).compact
end

def find_some!(ids, options={})
Expand All @@ -189,40 +185,22 @@ def find_some!(ids, options={})

# All query methods that load documents pass through find_one or find_many
def find_one(options={})
criteria, options = to_query(options)
if doc = collection.find_one(criteria, options)
load(doc)
end
load(query(options).first)
end

# All query methods that load documents pass through find_one or find_many
def find_many(options)
criteria, options = to_query(options)
collection.find(criteria, options).to_a.map do |doc|
load(doc)
end
end

def invert_order_clause(order)
order.split(',').map do |order_segment|
if order_segment =~ /\sasc/i
order_segment.sub /\sasc/i, ' desc'
elsif order_segment =~ /\sdesc/i
order_segment.sub /\sdesc/i, ' asc'
else
"#{order_segment.strip} desc"
end
end.join(',')
query(options).all().map { |doc| load(doc) }
end

def update_single(id, attrs)
if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
end

doc = find(id)
doc.update_attributes(attrs)
doc
find(id).tap do |doc|
doc.update_attributes(attrs)
end
end

def update_multiple(docs)
Expand All @@ -234,14 +212,6 @@ def update_multiple(docs)
docs.each_pair { |id, attrs| instances << update(id, attrs) }
instances
end

def to_criteria(options={})
Query.new(self, options).criteria
end

def to_query(options={})
Query.new(self, options).to_a
end
end

module InstanceMethods
Expand Down Expand Up @@ -274,9 +244,9 @@ def destroyed?
end

def reload
if attrs = collection.find_one({:_id => _id})
if doc = self.class.query(:_id => id).first
self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
self.attributes = attrs
self.attributes = doc
self
else
raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
Expand Down
11 changes: 6 additions & 5 deletions lib/mongo_mapper/plugins/identity_map.rb
Expand Up @@ -28,25 +28,26 @@ def identity_map=(v)
end

def find_one(options={})
criteria, query_options = to_query(options)

query = query(options)
criteria = query.criteria.to_hash

if simple_find?(criteria) && identity_map.key?(criteria[:_id])
identity_map[criteria[:_id]]
else
super.tap do |document|
remove_documents_from_map(document) if selecting_fields?(query_options)
remove_documents_from_map(document) if selecting_fields?(query.options)
end
end
end

def find_many(options)
criteria, query_options = to_query(options)
super.tap do |documents|
remove_documents_from_map(documents) if selecting_fields?(query_options)
remove_documents_from_map(documents) if selecting_fields?(query(options).options)
end
end

def load(attrs)
return nil if attrs.nil?
document = identity_map[attrs['_id']]

if document.nil? || identity_map_off?
Expand Down
8 changes: 6 additions & 2 deletions lib/mongo_mapper/plugins/keys.rb
Expand Up @@ -36,9 +36,12 @@ def using_object_id?
object_id_key?(:_id)
end

def object_id_keys
keys.keys.select { |key| keys[key].type == ObjectId }.map(&:to_sym)
end

def object_id_key?(name)
key = keys[name.to_s]
key && key.type == ObjectId
object_id_keys.include?(name.to_sym)
end

def to_mongo(instance)
Expand All @@ -53,6 +56,7 @@ def from_mongo(value)

# load is overridden in identity map to ensure same objects are loaded
def load(attrs)
return nil if attrs.nil?
begin
klass = attrs['_type'].present? ? attrs['_type'].constantize : self
klass.new(attrs, true)
Expand Down
4 changes: 2 additions & 2 deletions lib/mongo_mapper/plugins/modifiers.rb
Expand Up @@ -29,7 +29,7 @@ def unset(*args)
criteria = {:id => ids}
end

criteria = to_criteria(criteria)
criteria = query(criteria).criteria.to_hash
modifiers = keys.inject({}) { |hash, key| hash[key] = 1; hash }
collection.update(criteria, {'$unset' => modifiers}, :multi => true)
end
Expand Down Expand Up @@ -68,7 +68,7 @@ def modifier_update(modifier, args)
def criteria_and_keys_from_args(args)
keys = args.pop
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
[to_criteria(criteria), keys]
[query(criteria).criteria.to_hash, keys]
end
end

Expand Down

0 comments on commit 16ac32d

Please sign in to comment.