From 4f26ebdb8ecc52a8e07c1155237e4e2ed14ead9d Mon Sep 17 00:00:00 2001 From: Durran Jordan Date: Fri, 4 May 2012 20:56:50 +0200 Subject: [PATCH] Allow added, unloaded and loaded as scope names. Fixes #1972. --- CHANGELOG.md | 3 + lib/mongoid/relations/targets/enumerable.rb | 100 +++++++++--------- .../relations/targets/enumerable_spec.rb | 80 +++++++------- 3 files changed, 93 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 193b334515..e4f4357102 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -716,6 +716,9 @@ For instructions on upgrading to newer versions, visit ### Resolved Issues +* \#1972 `added`, `loaded`, and `unloaded` can now be valid scope names on a + document that is part of a 1-n relation. + * \#1952/#1950 `#all_in` behaviour on embedded documents now properly matches root documents when passing an empty array. (Hans Hasselberg) diff --git a/lib/mongoid/relations/targets/enumerable.rb b/lib/mongoid/relations/targets/enumerable.rb index 5c559f22da..fda4588a65 100644 --- a/lib/mongoid/relations/targets/enumerable.rb +++ b/lib/mongoid/relations/targets/enumerable.rb @@ -4,17 +4,17 @@ module Relations module Targets # This class is the wrapper for all relational associations that have a - # target that can be a criteria or array of loaded documents. This + # target that can be a criteria or array of _loaded documents. This # handles both cases or a combination of the two. class Enumerable include ::Enumerable # The three main instance variables are collections of documents. # - # @attribute [rw] added Documents that have been appended. - # @attribute [rw] loaded Persisted documents that have been loaded. - # @attribute [rw] unloaded A criteria representing persisted docs. - attr_accessor :added, :loaded, :unloaded + # @attribute [rw] _added Documents that have been appended. + # @attribute [rw] _loaded Persisted documents that have been _loaded. + # @attribute [rw] _unloaded A criteria representing persisted docs. + attr_accessor :_added, :_loaded, :_unloaded delegate :===, :is_a?, :kind_of?, to: [] @@ -44,7 +44,7 @@ def ==(other) # # @since 2.1.0 def <<(document) - added[document.id] = document + _added[document.id] = document self end alias :push :<< @@ -60,14 +60,14 @@ def <<(document) # doc.unbind # end # - # @return [ Array ] The cleared out added docs. + # @return [ Array ] The cleared out _added docs. # # @since 2.1.0 def clear if block_given? in_memory { |doc| yield(doc) } end - loaded.clear and added.clear + _loaded.clear and _added.clear end # Clones each document in the enumerable. @@ -95,9 +95,9 @@ def clone # # @since 2.1.0 def delete(document) - doc = (loaded.delete(document.id) || added.delete(document.id)) + doc = (_loaded.delete(document.id) || _added.delete(document.id)) unless doc - if unloaded && unloaded.where(_id: document.id).exists? + if _unloaded && _unloaded.where(_id: document.id).exists? yield(document) if block_given? return document end @@ -123,8 +123,8 @@ def delete_if(&block) load_all! deleted = in_memory.select(&block) deleted.each do |doc| - loaded.delete(doc.id) - added.delete(doc.id) + _loaded.delete(doc.id) + _added.delete(doc.id) end self end @@ -132,41 +132,41 @@ def delete_if(&block) # Iterating over this enumerable has to handle a few different # scenarios. # - # If the enumerable has its criteria loaded into memory then it yields - # to all the loaded docs and all the added docs. + # If the enumerable has its criteria _loaded into memory then it yields + # to all the _loaded docs and all the _added docs. # - # If the enumerable has not loaded the criteria then it iterates over + # If the enumerable has not _loaded the criteria then it iterates over # the cursor while loading the documents and then iterates over the - # added docs. + # _added docs. # # @example Iterate over the enumerable. # enumerable.each do |doc| # puts doc # end # - # @return [ true ] That the enumerable is now loaded. + # @return [ true ] That the enumerable is now _loaded. # # @since 2.1.0 def each - if loaded? - loaded.each_pair do |id, doc| + if _loaded? + _loaded.each_pair do |id, doc| yield(doc) end else - unloaded.each do |doc| - document = added.delete(doc.id) || loaded.delete(doc.id) || doc + _unloaded.each do |doc| + document = _added.delete(doc.id) || _loaded.delete(doc.id) || doc yield(document) - loaded[document.id] = document + _loaded[document.id] = document end end - added.each_pair do |id, doc| + _added.each_pair do |id, doc| yield(doc) end @executed = true end # Is the enumerable empty? Will determine if the count is zero based on - # whether or not it is loaded. + # whether or not it is _loaded. # # @example Is the enumerable empty? # enumerable.empty? @@ -175,10 +175,10 @@ def each # # @since 2.1.0 def empty? - if loaded? + if _loaded? in_memory.count == 0 else - unloaded.count + added.count == 0 + _unloaded.count + _added.count == 0 end end @@ -208,10 +208,10 @@ def first # @since 2.1.0 def initialize(target) if target.is_a?(Criteria) - @added, @executed, @loaded, @unloaded = {}, false, {}, target + @_added, @executed, @_loaded, @_unloaded = {}, false, {}, target else - @added, @executed = {}, true - @loaded = target.inject({}) do |_target, doc| + @_added, @executed = {}, true + @_loaded = target.inject({}) do |_target, doc| _target[doc.id] = doc _target end @@ -229,8 +229,8 @@ def initialize(target) # # @since 3.0.0 def include?(doc) - return super unless unloaded - unloaded.where(_id: doc.id).exists? || added.has_key?(doc.id) + return super unless _unloaded + _unloaded.where(_id: doc.id).exists? || _added.has_key?(doc.id) end # Inspection will just inspect the entries for nice array-style @@ -246,8 +246,8 @@ def inspect entries.inspect end - # Return all the documents in the enumerable that have been loaded or - # added. + # Return all the documents in the enumerable that have been _loaded or + # _added. # # @note When passed a block it yields to each document. # @@ -258,7 +258,7 @@ def inspect # # @since 2.1.0 def in_memory - docs = (loaded.values + added.values) + docs = (_loaded.values + _added.values) docs.each { |doc| yield(doc) } if block_given? docs end @@ -281,21 +281,21 @@ def last # @example Load all the documents. # enumerable.load_all! # - # @return [ true ] That the enumerable is loaded. + # @return [ true ] That the enumerable is _loaded. # # @since 2.1.0 alias :load_all! :entries - # Has the enumerable been loaded? This will be true if the criteria has + # Has the enumerable been _loaded? This will be true if the criteria has # been executed or we manually load the entire thing. # - # @example Is the enumerable loaded? - # enumerable.loaded? + # @example Is the enumerable _loaded? + # enumerable._loaded? # - # @return [ true, false ] If the enumerable has been loaded. + # @return [ true, false ] If the enumerable has been _loaded. # # @since 2.1.0 - def loaded? + def _loaded? !!@executed end @@ -308,7 +308,7 @@ def loaded? # # @since 2.1.0 def reset - loaded.clear and added.clear + _loaded.clear and _added.clear @executed = false end @@ -338,11 +338,11 @@ def respond_to?(name, include_private = false) # # @since 2.1.0 def size - count = (unloaded ? unloaded.count : loaded.count) + count = (_unloaded ? _unloaded.count : _loaded.count) if count.zero? - count + added.count + count + _added.count else - count + added.values.count{ |d| d.new_record? } + count + _added.values.count{ |d| d.new_record? } end end alias :length :size @@ -354,7 +354,7 @@ def size # # @param [ Hash ] options Optional parameters. # - # @return [ String ] The entries all loaded as a string. + # @return [ String ] The entries all _loaded as a string. # # @since 2.2.0 def to_json(options = {}) @@ -368,7 +368,7 @@ def to_json(options = {}) # # @param [ Hash ] options Optional parameters. # - # @return [ Hash ] The entries all loaded as a hash. + # @return [ Hash ] The entries all _loaded as a hash. # # @since 2.2.0 def as_json(options = {}) @@ -396,10 +396,10 @@ def method_missing(name, *args, &block) end def matching_document(location) - loaded.try(:values).try(location) || - added[unloaded.try(location).try(:id)] || - unloaded.try(location) || - added.values.try(location) + _loaded.try(:values).try(location) || + _added[_unloaded.try(location).try(:id)] || + _unloaded.try(location) || + _added.values.try(location) end end end diff --git a/spec/mongoid/relations/targets/enumerable_spec.rb b/spec/mongoid/relations/targets/enumerable_spec.rb index 44eafc4c1f..3dc876ae49 100644 --- a/spec/mongoid/relations/targets/enumerable_spec.rb +++ b/spec/mongoid/relations/targets/enumerable_spec.rb @@ -36,7 +36,7 @@ end it "returns the equality check" do - enumerable.loaded.values.should eq([ post ]) + enumerable._loaded.values.should eq([ post ]) end end @@ -86,7 +86,7 @@ before do post.save - enumerable.added[post.id] = post + enumerable._added[post.id] = post end it "returns the equality check" do @@ -130,7 +130,7 @@ end it "adds the document to the added target" do - enumerable.added.should eq({ post.id => post }) + enumerable._added.should eq({ post.id => post }) end it "returns the added documents" do @@ -219,7 +219,7 @@ end before do - enumerable.loaded[post.id] = post + enumerable._loaded[post.id] = post enumerable << post end @@ -230,15 +230,15 @@ end it "clears out the loaded docs" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "clears out the added docs" do - enumerable.added.should be_empty + enumerable._added.should be_empty end it "retains its loaded state" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -303,7 +303,7 @@ end it "deletes the document from the enumerable" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "returns the document" do @@ -334,7 +334,7 @@ end it "removes the document from the added docs" do - enumerable.added.should be_empty + enumerable._added.should be_empty end it "returns the document" do @@ -361,7 +361,7 @@ end it "does not load the document" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "returns the document" do @@ -416,7 +416,7 @@ end it "deletes the document from the enumerable" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "returns the remaining docs" do @@ -447,7 +447,7 @@ end it "removes the document from the added docs" do - enumerable.added.should be_empty + enumerable._added.should be_empty end it "returns the remaining docs" do @@ -474,7 +474,7 @@ end it "does not load the document" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "returns the remaining docs" do @@ -533,11 +533,11 @@ end it "loads each document" do - enumerable.loaded.should eq({ post.id => post }) + enumerable._loaded.should eq({ post.id => post }) end it "becomes loaded" do - enumerable.should be_loaded + enumerable.should be__loaded end end @@ -554,11 +554,11 @@ end it "does not alter the loaded docs" do - enumerable.loaded.should eq({ post.id => post }) + enumerable._loaded.should eq({ post.id => post }) end it "stays loaded" do - enumerable.should be_loaded + enumerable.should be__loaded end end @@ -589,15 +589,15 @@ end it "adds the unloaded to the loaded docs" do - enumerable.loaded.should eq({ post.id => post }) + enumerable._loaded.should eq({ post.id => post }) end it "keeps the appended in the added docs" do - enumerable.added.should eq({ post_two.id => post_two }) + enumerable._added.should eq({ post_two.id => post_two }) end it "stays loaded" do - enumerable.should be_loaded + enumerable.should be__loaded end end @@ -614,11 +614,11 @@ end it "adds the persisted added doc to the loaded" do - enumerable.loaded.should eq({ post.id => post }) + enumerable._loaded.should eq({ post.id => post }) end it "stays loaded" do - enumerable.should be_loaded + enumerable.should be__loaded end end end @@ -691,7 +691,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -720,7 +720,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end end @@ -745,7 +745,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -760,7 +760,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end end @@ -949,11 +949,11 @@ end it "sets the criteria" do - enumerable.unloaded.should eq(criteria) + enumerable._unloaded.should eq(criteria) end it "is not loaded" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -968,11 +968,11 @@ end it "does not set a criteria" do - enumerable.unloaded.should be_nil + enumerable._unloaded.should be_nil end it "is loaded" do - enumerable.should be_loaded + enumerable.should be__loaded end end end @@ -1111,7 +1111,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -1134,7 +1134,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -1149,7 +1149,7 @@ end it "does not load the enumerable" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end end @@ -1281,7 +1281,7 @@ end it "loads all the unloaded documents" do - enumerable.loaded.should eq({ post.id => post }) + enumerable._loaded.should eq({ post.id => post }) end it "returns true" do @@ -1289,7 +1289,7 @@ end it "sets loaded to true" do - enumerable.should be_loaded + enumerable.should be__loaded end end @@ -1320,15 +1320,15 @@ end it "is not loaded" do - enumerable.should_not be_loaded + enumerable.should_not be__loaded end it "clears out the loaded docs" do - enumerable.loaded.should be_empty + enumerable._loaded.should be_empty end it "clears out the added docs" do - enumerable.added.should be_empty + enumerable._added.should be_empty end end @@ -1590,7 +1590,7 @@ before do enumerable << post - enumerable.loaded[post.id] = post + enumerable._loaded[post.id] = post end let!(:uniq) do @@ -1602,7 +1602,7 @@ end it "sets loaded to true" do - enumerable.should be_loaded + enumerable.should be__loaded end end end