lib/mongodoc/document.rb in mongodoc-0.1.2 vs lib/mongodoc/document.rb in mongodoc-0.2.0

- old
+ new

@@ -1,31 +1,47 @@ require 'mongodoc/bson' require 'mongodoc/query' require 'mongodoc/attributes' require 'mongodoc/criteria' +require 'mongodoc/finders' +require 'mongodoc/named_scope' module MongoDoc class DocumentInvalidError < RuntimeError; end class NotADocumentError < RuntimeError; end - class Document - extend MongoDoc::Attributes - include Validatable + module Document - attr_accessor :_id - alias :id :_id - alias :to_param :_id + def self.included(klass) + klass.class_eval do + include Attributes + extend ClassMethods + extend Finders + extend NamedScope + include Validatable + alias :id :_id + alias :to_param :_id + end + end + def initialize(attrs = {}) self.attributes = attrs end def ==(other) return false unless self.class === other self.class._attributes.all? {|var| self.send(var) == other.send(var)} end + def attributes + self.class._attributes.inject({}) do |hash, attr| + hash[attr] = send(attr) + hash + end + end + def attributes=(attrs) attrs.each do |key, value| send("#{key}=", value) end end @@ -37,11 +53,11 @@ def save(validate = true) return _root.save(validate) if _root return _save(false) unless validate and not valid? false end - + def save! return _root.save! if _root raise DocumentInvalidError unless valid? _save(true) end @@ -54,22 +70,32 @@ end end end def update_attributes(attrs) + strict = attrs.delete(:__strict__) self.attributes = attrs - return _propose_update_attributes(self, path_to_root(attrs), false) if valid? - false + return false unless valid? + if strict + _strict_update_attributes(_path_to_root(self, attrs), false) + else + _naive_update_attributes(_path_to_root(self, attrs), false) + end end def update_attributes!(attrs) + strict = attrs.delete(:__strict__) self.attributes = attrs raise DocumentInvalidError unless valid? - _propose_update_attributes(self, path_to_root(attrs), true) + if strict + _strict_update_attributes(_path_to_root(self, attrs), true) + else + _naive_update_attributes(_path_to_root(self, attrs), true) + end end - class << self + module ClassMethods def bson_create(bson_hash, options = {}) new.tap do |obj| bson_hash.each do |name, value| obj.send("#{name}=", MongoDoc::BSON.decode(value, options)) end @@ -82,57 +108,95 @@ def collection_name self.to_s.tableize.gsub('/', '.') end - def count - collection.count - end - def create(attrs = {}) instance = new(attrs) _create(instance, false) if instance.valid? instance end - + def create!(attrs = {}) instance = new(attrs) raise MongoDoc::DocumentInvalidError unless instance.valid? _create(instance, true) instance end - def criteria - Criteria.new(self) - end + protected - def find_one(id) - MongoDoc::BSON.decode(collection.find_one(id)) + def _create(instance, safe) + instance.send(:notify_before_save_observers) + instance._id = collection.insert(instance, :safe => safe) + instance.send(:notify_save_success_observers) + instance._id + rescue Mongo::MongoDBError => e + instance.send(:notify_save_failed_observers) + raise e end end protected def _collection self.class.collection end - - def _propose_update_attributes(src, attrs, safe) - return _parent.send(:_propose_update_attributes, src, attrs, safe) if _parent - _update_attributes(attrs, safe) + + def _naive_update_attributes(attrs, safe) + return _root.send(:_naive_update_attributes, attrs, safe) if _root + _collection.update({'_id' => self._id}, MongoDoc::Query.set_modifier(attrs), :safe => safe) end + def _strict_update_attributes(attrs, safe, selector = {}) + return _root.send(:_strict_update_attributes, attrs, safe, _selector_path_to_root('_id' => _id)) if _root + _collection.update({'_id' => _id}.merge(selector), MongoDoc::Query.set_modifier(attrs), :safe => safe) + end + def _save(safe) + notify_before_save_observers self._id = _collection.save(self, :safe => safe) + notify_save_success_observers + self._id + rescue Mongo::MongoDBError => e + notify_save_failed_observers + raise e end - def _update_attributes(attrs, safe) - _collection.update({'_id' => self._id}, MongoDoc::Query.set_modifier(attrs), :safe => safe) + def before_save_callback(root) + self._id = Mongo::ObjectID.new if new_record? end - class << self - def _create(instance, safe) - instance._id = collection.insert(instance, :safe => safe) - end + def save_failed_callback(root) + self._id = nil end + + def save_success_callback(root) + root.unregister_save_observer(self) + end + + def save_observers + @save_observers ||= [] + end + + def register_save_observer(child) + save_observers << child + end + + def unregister_save_observer(child) + save_observers.delete(child) + end + + def notify_before_save_observers + save_observers.each {|obs| obs.before_save_callback(self) } + end + + def notify_save_success_observers + save_observers.each {|obs| obs.save_success_callback(self) } + end + + def notify_save_failed_observers + save_observers.each {|obs| obs.save_failed_callback(self) } + end + end end