Skip to content

Commit

Permalink
Completely converted from String _ids to Mongo::ObjectID _ids. Still …
Browse files Browse the repository at this point in the history
…some failing tests for custom ids which are next.
  • Loading branch information
jnunemaker committed Nov 15, 2009
1 parent 4ca393e commit 8d46911
Show file tree
Hide file tree
Showing 28 changed files with 317 additions and 250 deletions.
25 changes: 22 additions & 3 deletions lib/mongo_mapper.rb
Expand Up @@ -20,23 +20,28 @@ def initialize(document)
end
end

# @api public
def self.connection
@@connection ||= Mongo::Connection.new
end


# @api public
def self.connection=(new_connection)
@@connection = new_connection
end

# @api public
def self.logger
connection.logger
end


# @api public
def self.database=(name)
@@database = nil
@@database_name = name
end


# @api public
def self.database
if @@database_name.blank?
raise 'You forgot to set the default database name: MongoMapper.database = "foobar"'
Expand All @@ -45,21 +50,25 @@ def self.database
@@database ||= MongoMapper.connection.db(@@database_name)
end

# @api private
def self.ensured_indexes
@@ensured_indexes ||= []
end

# @api private
def self.ensure_index(klass, keys, options={})
ensured_indexes << {:klass => klass, :keys => keys, :options => options}
end

# @api public
def self.ensure_indexes!
ensured_indexes.each do |index|
unique = index[:options].delete(:unique)
index[:klass].collection.create_index(index[:keys], unique)
end
end

# @api private
module Finders
def dynamic_find(finder, args)
attributes = {}
Expand All @@ -83,6 +92,16 @@ def dynamic_find(finder, args)
end
end
end

# @api private
def self.use_time_zone?
Time.respond_to?(:zone) && Time.zone ? true : false
end

# @api private
def self.time_class
use_time_zone? ? Time.zone : Time
end
end

require 'mongo_mapper/support'
Expand Down
Expand Up @@ -4,7 +4,7 @@ class BelongsToPolymorphicProxy < Proxy
def replace(doc)
if doc
doc.save if doc.new?
id, type = doc.id, doc.class.name
id, type = doc._id, doc.class.name
end

@owner.send("#{@association.foreign_key}=", id)
Expand Down
2 changes: 1 addition & 1 deletion lib/mongo_mapper/associations/belongs_to_proxy.rb
Expand Up @@ -4,7 +4,7 @@ class BelongsToProxy < Proxy
def replace(doc)
if doc
doc.save if doc.new?
id = doc.id
id = doc._id
end

@owner.send("#{@association.foreign_key}=", id)
Expand Down
4 changes: 2 additions & 2 deletions lib/mongo_mapper/associations/many_documents_as_proxy.rb
Expand Up @@ -3,13 +3,13 @@ module Associations
class ManyDocumentsAsProxy < ManyDocumentsProxy
protected
def scoped_conditions
{as_type_name => @owner.class.name, as_id_name => @owner.id}
{as_type_name => @owner.class.name, as_id_name => @owner._id}
end

def apply_scope(doc)
ensure_owner_saved
doc.send("#{as_type_name}=", @owner.class.name)
doc.send("#{as_id_name}=", @owner.id)
doc.send("#{as_id_name}=", @owner._id)
doc
end

Expand Down
4 changes: 2 additions & 2 deletions lib/mongo_mapper/associations/many_documents_proxy.rb
Expand Up @@ -98,7 +98,7 @@ def method_missing(method, *args)

protected
def scoped_conditions
{self.foreign_key => @owner.id}
{self.foreign_key => @owner._id}
end

def scoped_options(options)
Expand All @@ -115,7 +115,7 @@ def ensure_owner_saved

def apply_scope(doc)
ensure_owner_saved
doc.send("#{self.foreign_key}=", @owner.id)
doc.send("#{self.foreign_key}=", @owner._id)
doc
end

Expand Down
3 changes: 2 additions & 1 deletion lib/mongo_mapper/associations/many_embedded_proxy.rb
Expand Up @@ -13,9 +13,10 @@ def build(attributes={})
doc
end

# TODO: test that both string and oid version work
def find(id)
load_target
@target.detect { |item| item.id == id }
@target.detect { |item| item.id == id || item._id == id }
end

def <<(*docs)
Expand Down
6 changes: 3 additions & 3 deletions lib/mongo_mapper/document.rb
Expand Up @@ -442,12 +442,12 @@ def save!

def destroy
return false if frozen?
self.class.delete(id) unless new?
self.class.delete(_id) unless new?
freeze
end

def reload
self.class.find(id)
self.class.find(_id)
end

private
Expand All @@ -463,7 +463,7 @@ def create

def assign_id
if read_attribute(:_id).blank?
write_attribute(:_id, Mongo::ObjectID.new.to_s)
write_attribute :_id, Mongo::ObjectID.new
end
end

Expand Down
18 changes: 14 additions & 4 deletions lib/mongo_mapper/embedded_document.rb
Expand Up @@ -16,7 +16,7 @@ def self.included(model)

extend Validations::Macros

key :_id, String
key :_id, Mongo::ObjectID
attr_accessor :_root_document
end
end
Expand Down Expand Up @@ -61,6 +61,11 @@ def key(*args)

key
end

def object_id_key?(name)
key = keys[name.to_s]
key && key.type == Mongo::ObjectID
end

def embeddable?
!self.ancestors.include?(Document)
Expand Down Expand Up @@ -193,7 +198,7 @@ def initialize(attrs={})

if self.class.embeddable?
if read_attribute(:_id).blank?
write_attribute :_id, Mongo::ObjectID.new.to_s
write_attribute :_id, Mongo::ObjectID.new
@new_document = true
else
@new_document = false
Expand Down Expand Up @@ -275,15 +280,20 @@ def []=(name, value)
end

def ==(other)
other.is_a?(self.class) && id == other.id
other.is_a?(self.class) && _id == other._id
end

def id
read_attribute(:_id)
read_attribute(:_id).to_s
end

def id=(value)
@using_custom_id = true

if self.class.object_id_key?(:_id)
value = value.is_a?(String) ? Mongo::ObjectID.from_string(value) : value
end

write_attribute :_id, value
end

Expand Down
28 changes: 17 additions & 11 deletions lib/mongo_mapper/finder_options.rb
Expand Up @@ -8,17 +8,7 @@ module MongoMapper
# useful for understanding how MongoMapper handles the parsing of finder
# conditions and options.
#
# @private
class FinderOperator
def initialize(field, operator)
@field, @operator = field, operator
end

def to_criteria(value)
{@field => {@operator => value}}
end
end

# @private
class FinderOptions
OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]

Expand Down Expand Up @@ -72,10 +62,16 @@ def to_mongo_criteria(conditions, parent_key=nil)

conditions.each_pair do |field, value|
field = normalized_field(field)

if @model.object_id_key?(field) && value.is_a?(String)
value = Mongo::ObjectID.from_string(value)
end

if field.is_a?(FinderOperator)
criteria.merge!(field.to_criteria(value))
next
end

case value
when Array
operator_present = field.to_s =~ /^\$/
Expand Down Expand Up @@ -128,4 +124,14 @@ def to_mongo_sort_piece(str)
[field, direction]
end
end

class FinderOperator
def initialize(field, operator)
@field, @operator = field, operator
end

def to_criteria(value)
{@field => {@operator => value}}
end
end
end
20 changes: 4 additions & 16 deletions lib/mongo_mapper/support.rb
Expand Up @@ -138,33 +138,21 @@ class Symbol
end
end

class Time
class Time
def self.to_mongo(value)
if value.nil? || value == ''
nil
else
to_utc_time(value)
time = MongoMapper.time_class.parse(value.to_s)
time && time.utc
end
end

def self.from_mongo(value)
if Time.respond_to?(:zone) && Time.zone && value.present?
if MongoMapper.use_time_zone? && value.present?
value.in_time_zone(Time.zone)
else
value
end
end

def self.to_utc_time(value)
to_local_time(value).try(:utc)
end

# make sure we have a time and that it is local
def self.to_local_time(value)
if Time.respond_to?(:zone) && Time.zone
Time.zone.parse(value.to_s)
else
Time.parse(value.to_s)
end
end
end
2 changes: 1 addition & 1 deletion lib/mongo_mapper/validations.rb
Expand Up @@ -15,7 +15,7 @@ def valid?(instance)
return true if allow_blank && value.blank?
base_conditions = case_sensitive ? {self.attribute => value} : {}
doc = instance.class.first(base_conditions.merge(scope_conditions(instance)).merge(where_conditions(instance)))
doc.nil? || instance.id == doc.id
doc.nil? || instance._id == doc._id
end

def message(instance)
Expand Down
20 changes: 10 additions & 10 deletions test/functional/associations/test_belongs_to_polymorphic_proxy.rb
Expand Up @@ -19,11 +19,11 @@ def setup
status.target = project
status.save.should be_true

from_db = Status.find(status.id)
from_db.target.nil?.should be_false
from_db.target_id.should == project.id
from_db.target_type.should == "Project"
from_db.target.name.should == "mongomapper"
status = status.reload
status.target.nil?.should be_false
status.target_id.should == project._id
status.target_type.should == "Project"
status.target.name.should == "mongomapper"
end

should "unset the association" do
Expand All @@ -32,11 +32,11 @@ def setup
status.target = project
status.save.should be_true

from_db = Status.find(status.id)
from_db.target = nil
from_db.target_type.nil?.should be_true
from_db.target_id.nil?.should be_true
from_db.target.nil?.should be_true
status = status.reload
status.target = nil
status.target_type.nil?.should be_true
status.target_id.nil?.should be_true
status.target.nil?.should be_true
end

context "association id set but document not found" do
Expand Down
3 changes: 2 additions & 1 deletion test/functional/associations/test_belongs_to_proxy.rb
Expand Up @@ -42,6 +42,7 @@ def setup
end

should "return nil if id set but document not found" do
@comment_class.new(:name => 'Foo', :post_id => '1234').post.nil?.should be_true
id = Mongo::ObjectID.new
@comment_class.new(:name => 'Foo', :post_id => id).post.nil?.should be_true
end
end

0 comments on commit 8d46911

Please sign in to comment.