Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Dramatically speed up MongoMapper::Plugins::Keys#load_from_database a…

…nd keys in general.
  • Loading branch information...
commit 868cd7daf8d1d51e016626b0cdcfac81911799cf 1 parent fb517ee
@jonpollock jonpollock authored
View
17 lib/mongo_mapper/plugins/associations.rb
@@ -65,6 +65,7 @@ def embedded_associations
end
def build_proxy(association)
+ instance_variable_set :"@_association_#{association.name}", nil
proxy = association.proxy_class.new(self, association)
self.instance_variable_set(association.ivar, proxy)
@@ -72,10 +73,20 @@ def build_proxy(association)
end
def get_proxy(association)
- unless proxy = self.instance_variable_get(association.ivar)
- proxy = build_proxy(association)
+ value_from_db = instance_variable_get(:"@_association_#{association.name}")
+ if value_from_db
+ instance_variable_set :"@_association_#{association.name}", nil
+ unless proxy = self.instance_variable_get(association.ivar)
+ proxy = build_proxy(association)
+ end
+ association.embeddable? ? proxy.load_from_database(value_from_db) : proxy.replace(value_from_db)
+ proxy
+ else
+ unless proxy = self.instance_variable_get(association.ivar)
+ proxy = build_proxy(association)
+ end
+ proxy
end
- proxy
end
def save_to_collection(options={})
View
26 lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb
@@ -3,7 +3,16 @@ module MongoMapper
module Plugins
module Associations
class ManyEmbeddedPolymorphicProxy < EmbeddedCollection
+ def load_from_database(values)
+ @_from_db = true
+ @_values = values.map do |v|
+ v.respond_to?(:attributes) ? v.attributes.merge(association.type_key_name => v.class.name) : v
+ end
+ reset
+ end
+
def replace(values)
+ @_from_db = false
@_values = values.map do |v|
v.respond_to?(:attributes) ? v.attributes.merge(association.type_key_name => v.class.name) : v
end
@@ -12,10 +21,19 @@ def replace(values)
protected
def find_target
- (@_values || []).map do |hash|
- child = polymorphic_class(hash).load(hash)
- assign_references(child)
- child
+ if !@_from_db
+ (@_values || []).map do |hash|
+ child = polymorphic_class(hash).new(hash)
+ assign_references(child)
+ child
+ end
+ else
+ @_from_db = false
+ (@_values || []).map do |hash|
+ child = polymorphic_class(hash).load(hash)
+ assign_references(child)
+ child
+ end
end
end
View
24 lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb
@@ -3,7 +3,16 @@ module MongoMapper
module Plugins
module Associations
class ManyEmbeddedProxy < EmbeddedCollection
+ def load_from_database(values)
+ @_from_db = true
+ @_values = (values || []).map do |v|
+ v.respond_to?(:attributes) ? v.attributes : v
+ end
+ reset
+ end
+
def replace(values)
+ @_from_db = false
@_values = (values || []).map do |v|
v.respond_to?(:attributes) ? v.attributes : v
end
@@ -12,9 +21,18 @@ def replace(values)
private
def find_target
- (@_values || []).map do |attrs|
- klass.load(attrs).tap do |child|
- assign_references(child)
+ if !@_from_db
+ (@_values || []).map do |attrs|
+ klass.new(attrs).tap do |child|
+ assign_references(child)
+ end
+ end
+ else
+ @_from_db = false
+ (@_values || []).map do |attrs|
+ klass.load(attrs).tap do |child|
+ assign_references(child)
+ end
end
end
end
View
26 lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb
@@ -3,17 +3,33 @@ module MongoMapper
module Plugins
module Associations
class OneEmbeddedPolymorphicProxy < OneEmbeddedProxy
+ def load_from_database(value)
+ @_from_db = true
+ @value = value.respond_to?(:attributes) ? value.attributes.merge(association.type_key_name => value.class.name) : value
+ reset
+ end
+
def replace(value)
+ @_from_db = false
@value = value.respond_to?(:attributes) ? value.attributes.merge(association.type_key_name => value.class.name) : value
reset
end
-
+
protected
def find_target
- if @value
- child = polymorphic_class(@value).load(@value)
- assign_references(child)
- child
+ if !@_from_db
+ if @value
+ child = polymorphic_class(@value).new(@value)
+ assign_references(child)
+ child
+ end
+ else
+ @_from_db = false
+ if @value
+ child = polymorphic_class(@value).load(@value)
+ assign_references(child)
+ child
+ end
end
end
View
13 lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb
@@ -12,6 +12,19 @@ def build(attributes={})
def replace(doc)
if doc.respond_to?(:attributes)
+ @target = klass.new(doc.attributes)
+ elsif doc.nil?
+ @target = nil
+ else
+ @target = klass.new(doc)
+ end
+ assign_references(@target)
+ loaded
+ @target
+ end
+
+ def load_from_database(doc)
+ if doc.respond_to?(:attributes)
@target = klass.load(doc.attributes)
else
@target = klass.load(doc)
View
1  lib/mongo_mapper/plugins/clone.rb
@@ -8,6 +8,7 @@ def initialize_copy(other)
@_new = true
@_destroyed = false
@_id = nil
+ remove_instance_variable(:"@_read__id") if instance_variable_defined? (:"@_read__id")
associations.each do |name, association|
instance_variable_set(association.ivar, nil)
end
View
90 lib/mongo_mapper/plugins/keys.rb
@@ -13,6 +13,9 @@ module Keys
module ClassMethods
def inherited(descendant)
+ descendant.instance_variable_set(:"@key_names", key_names.dup)
+ descendant.instance_variable_set(:"@object_id_keys", object_id_keys.dup)
+ descendant.instance_variable_set(:"@date_keys", date_keys.dup)
descendant.instance_variable_set(:@keys, keys.dup)
super
end
@@ -21,6 +24,18 @@ def keys
@keys ||= {}
end
+ def key_names
+ @key_names ||= []
+ end
+
+ def object_id_keys
+ @object_id_keys ||= []
+ end
+
+ def date_keys
+ @date_keys ||= []
+ end
+
def key(*args)
Key.new(*args).tap do |key|
keys[key.name] = key
@@ -28,11 +43,14 @@ def key(*args)
create_key_in_descendants(*args)
create_indexes_for(key)
create_validations_for(key)
+ key_names << key.name
+ object_id_keys << key.name.to_sym if key.type == ObjectId
+ date_keys << key.name if key.type == Date
end
end
def key?(key)
- keys.keys.include?(key.to_s)
+ keys.has_key?(key.to_s)
end
def using_object_id?
@@ -198,7 +216,7 @@ def attributes
end
embedded_associations.each do |association|
- if documents = instance_variable_get(association.ivar)
+ if documents = get_proxy(association)
if association.is_a?(Associations::OneAssociation)
attrs[association.name] = documents.to_mongo
else
@@ -231,7 +249,7 @@ def update_attribute(name, value)
end
def id
- _id
+ self[:_id]
end
def id=(value)
@@ -256,7 +274,22 @@ def keys
end
def key_names
- keys.keys
+ self.class.key_names
+ end
+
+ def date_keys
+ self.class.date_keys
+ end
+
+ def has_attribute?(name)
+ attr_name = name.chomp('=');
+ return true if keys.has_key? attr_name
+ associations.each_value do |assoc|
+ if assoc.embeddable?
+ return true if assoc.name == attr_name
+ end
+ end
+ false
end
def non_embedded_keys
@@ -270,11 +303,30 @@ def embedded_keys
private
def load_from_database(attrs)
return if attrs.blank?
- attrs.each do |key, value|
- if respond_to?(:"#{key}=") && !self.class.key?(key)
- self.send(:"#{key}=", value)
+ attr_keys = attrs.keys
+ model_keys = attr_keys & key_names
+ convert_to_date_keys = model_keys & date_keys
+ model_keys -= convert_to_date_keys
+ other_keys = attr_keys - key_names
+
+ model_keys.each do |key|
+ write_key_from_database(key, attrs[key])
+ end
+
+ convert_to_date_keys.each do |key|
+ write_key_from_database(key, Date.from_mongo(attrs[key]))
+ end
+
+ other_keys.each do |key, value|
+ if associations.has_key?(key.to_sym)
+ write_association_key_from_database(key, attrs[key])
else
- self[key] = value
+ if respond_to?(:"#{key}=")
+ self.send(:"#{key}=", attrs[key]) if respond_to?(:"#{key}=")
+ else
+ # so, add the attribute to the model anyway.
+ self[key] = attrs[key]
+ end
end
end
end
@@ -290,10 +342,13 @@ def set_parent_document(key, value)
end
def read_key(key_name)
+ read_value = instance_variable_get(:"@_read_#{key_name}")
+ return read_value if read_value
if key = keys[key_name.to_s]
value = key.get(instance_variable_get(:"@#{key_name}"))
set_parent_document(key, value)
instance_variable_set(:"@#{key_name}", value)
+ instance_variable_set(:"@_read_#{key_name}", value)
end
end
@@ -305,7 +360,24 @@ def write_key(name, value)
key = keys[name.to_s]
set_parent_document(key, value)
instance_variable_set :"@#{name}_before_type_cast", value
- instance_variable_set :"@#{name}", key.set(value)
+
+ # instance_variable_set :"@#{name}", key.set(value)
+ read_value = key.set(value)
+ instance_variable_set :"@#{name}", read_value
+ if key.type == Date
+ instance_variable_set(:"@_read_#{name}", Date.from_mongo(read_value))
+ else
+ instance_variable_set(:"@_read_#{name}", key.get(read_value))
+ end
+ end
+
+ def write_key_from_database(key, value)
+ instance_variable_set :"@#{key}", value
+ instance_variable_set :"@#{key}_before_type_cast", value
+ end
+
+ def write_association_key_from_database(key, value)
+ instance_variable_set :"@_association_#{key}", value
end
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.