From 3fe86761d50bd81712e9422b2c32a1aebf83c672 Mon Sep 17 00:00:00 2001 From: johnnyshields Date: Fri, 21 Apr 2023 01:51:32 +0900 Subject: [PATCH 1/6] Fix using exists? with args on relations. Also cleans up method docs which were not accurate. --- .../association/embedded/embeds_many/proxy.rb | 20 +++++++++++++++++-- .../association/referenced/has_many/proxy.rb | 7 +++++-- lib/mongoid/contextual/memory.rb | 9 +++++++-- lib/mongoid/contextual/mongo.rb | 9 +++++++-- lib/mongoid/contextual/none.rb | 11 ++++++---- lib/mongoid/findable.rb | 9 +++++++-- 6 files changed, 51 insertions(+), 14 deletions(-) diff --git a/lib/mongoid/association/embedded/embeds_many/proxy.rb b/lib/mongoid/association/embedded/embeds_many/proxy.rb index 8629fe55ee..b419bef1ac 100644 --- a/lib/mongoid/association/embedded/embeds_many/proxy.rb +++ b/lib/mongoid/association/embedded/embeds_many/proxy.rb @@ -211,9 +211,25 @@ def destroy_all(conditions = {}) # @example Are there persisted documents? # person.posts.exists? # + # @example Is a document with the given id persisted? + # context.exists?(BSON::ObjectId(...)) + # + # @example Are there persisted documents with the given title? + # person.posts.exists?({ title: "50 Ways to Leave Your Lover" }) + # + # @example Always return false. + # person.posts.exists?(false) + # + # @param [ :none | Hash | BSON::ObjectId | nil | false ] id_or_conditions + # May optionally supply search conditions as a hash or an object id. + # Will always return false when given nil or false. The symbol :none is + # the default when argument is not supplied. + # # @return [ true | false ] True is persisted documents exist, false if not. - def exists? - _target.any? { |doc| doc.persisted? } + def exists?(id_or_conditions = :none) + return _target.any?(&:persisted?) if id_or_conditions == :none + + criteria.exists?(id_or_conditions) end # Finds a document in this association through several different diff --git a/lib/mongoid/association/referenced/has_many/proxy.rb b/lib/mongoid/association/referenced/has_many/proxy.rb index fdee24a3fc..93b3236131 100644 --- a/lib/mongoid/association/referenced/has_many/proxy.rb +++ b/lib/mongoid/association/referenced/has_many/proxy.rb @@ -169,9 +169,12 @@ def each # @example Are there persisted documents? # person.posts.exists? # + # @param [ Hash | Object | false ] id_or_conditions an _id to + # search for, a hash of conditions, nil or false. + # # @return [ true | false ] True is persisted documents exist, false if not. - def exists? - criteria.exists? + def exists?(id_or_conditions = :none) + criteria.exists?(id_or_conditions) end # Find the matching document on the association, either based on id or diff --git a/lib/mongoid/contextual/memory.rb b/lib/mongoid/contextual/memory.rb index 0260416e24..7724e3256d 100644 --- a/lib/mongoid/contextual/memory.rb +++ b/lib/mongoid/contextual/memory.rb @@ -113,8 +113,13 @@ def each # @example Do any documents exist for given conditions. # context.exists?(name: "...") # - # @param [ Hash | Object | false ] id_or_conditions an _id to - # search for, a hash of conditions, nil or false. + # @example Always return false. + # context.exists?(false) + # + # @param [ :none | Hash | BSON::ObjectId | nil | false ] id_or_conditions + # May optionally supply search conditions as a hash or an object id. + # Will always return false when given nil or false. The symbol :none is + # the default when argument is not supplied. # # @return [ true | false ] If the count is more than zero. # Always false if passed nil or false. diff --git a/lib/mongoid/contextual/mongo.rb b/lib/mongoid/contextual/mongo.rb index 76dd214d4a..a7a8b8da9d 100644 --- a/lib/mongoid/contextual/mongo.rb +++ b/lib/mongoid/contextual/mongo.rb @@ -170,11 +170,16 @@ def each(&block) # @example Do any documents exist for given conditions. # context.exists?(name: "...") # + # @example Always return false. + # context.exists?(false) + # # @note We don't use count here since Mongo does not use counted # b-tree indexes. # - # @param [ Hash | Object | false ] id_or_conditions an _id to - # search for, a hash of conditions, nil or false. + # @param [ :none | Hash | BSON::ObjectId | nil | false ] id_or_conditions + # May optionally supply search conditions as a hash or an object id. + # Will always return false when given nil or false. The symbol :none is + # the default when argument is not supplied. # # @return [ true | false ] If the count is more than zero. # Always false if passed nil or false. diff --git a/lib/mongoid/contextual/none.rb b/lib/mongoid/contextual/none.rb index ba3fe0ea4c..268833b182 100644 --- a/lib/mongoid/contextual/none.rb +++ b/lib/mongoid/contextual/none.rb @@ -54,7 +54,7 @@ def each end end - # Do any documents exist for the context. + # Do any documents exist for the null context. # # @example Do any documents exist in the null context. # context.exists? @@ -65,11 +65,14 @@ def each # @example Do any documents exist for given conditions. # context.exists?(name: "...") # - # @param [ Hash | Object | false ] id_or_conditions an _id to - # search for, a hash of conditions, nil or false. + # @example Always return false. + # context.exists?(false) + # + # @param [ :none | Hash | BSON::ObjectId | nil | false ] _id_or_conditions + # Not used in null context. # # @return [ false ] Always false. - def exists?(id_or_conditions = :none); false; end + def exists?(_id_or_conditions = :none); false; end # Pluck the field values in null context. # diff --git a/lib/mongoid/findable.rb b/lib/mongoid/findable.rb index 03207b65ac..1e2dc55dbd 100644 --- a/lib/mongoid/findable.rb +++ b/lib/mongoid/findable.rb @@ -108,8 +108,13 @@ def empty? # @example Do any documents exist for given conditions. # Person.exists?(name: "...") # - # @param [ Hash | Object | false ] id_or_conditions an _id to - # search for, a hash of conditions, nil or false. + # @example Always return false. + # context.exists?(false) + # + # @param [ :none | Hash | BSON::ObjectId | nil | false ] id_or_conditions + # May optionally supply search conditions as a hash or an object id. + # Will always return false when given nil or false. The symbol :none is + # the default when argument is not supplied. # # @return [ true | false ] If any documents exist for the conditions. # Always false if passed nil or false. From eb699d7689bc733014f185c280478fee479277fa Mon Sep 17 00:00:00 2001 From: johnnyshields Date: Fri, 21 Apr 2023 01:56:36 +0900 Subject: [PATCH 2/6] Use delegator --- .../association/referenced/has_many/proxy.rb | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/lib/mongoid/association/referenced/has_many/proxy.rb b/lib/mongoid/association/referenced/has_many/proxy.rb index 93b3236131..0b0277881d 100644 --- a/lib/mongoid/association/referenced/has_many/proxy.rb +++ b/lib/mongoid/association/referenced/has_many/proxy.rb @@ -11,7 +11,7 @@ class HasMany class Proxy < Association::Many extend Forwardable - def_delegator :criteria, :count + def_delegators :criteria, :count, :exists? def_delegators :_target, :first, :in_memory, :last, :reset, :uniq # Appends a document or array of documents to the association. Will set @@ -157,26 +157,6 @@ def each end end - # Determine if any documents in this association exist in the database. - # - # If the association contains documents but all of the documents - # exist only in the application, i.e. have not been persisted to the - # database, this method returns false. - # - # This method queries the database on each invocation even if the - # association is already loaded into memory. - # - # @example Are there persisted documents? - # person.posts.exists? - # - # @param [ Hash | Object | false ] id_or_conditions an _id to - # search for, a hash of conditions, nil or false. - # - # @return [ true | false ] True is persisted documents exist, false if not. - def exists?(id_or_conditions = :none) - criteria.exists?(id_or_conditions) - end - # Find the matching document on the association, either based on id or # conditions. # From 75222385ea583e68e33b65af860b598401536697 Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Wed, 8 Nov 2023 06:50:44 +0900 Subject: [PATCH 3/6] Update proxy.rb --- lib/mongoid/association/embedded/embeds_many/proxy.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongoid/association/embedded/embeds_many/proxy.rb b/lib/mongoid/association/embedded/embeds_many/proxy.rb index fd414dea3d..9d5d0f7cfb 100644 --- a/lib/mongoid/association/embedded/embeds_many/proxy.rb +++ b/lib/mongoid/association/embedded/embeds_many/proxy.rb @@ -311,7 +311,7 @@ def destroy_all(conditions = {}) # queries for the existence of persisted documents in the # association with a matching _id. # - # @return [ true | false ] True is persisted documents exist, false if not. + # @return [ true | false ] True if persisted documents exist, false if not. def exists?(id_or_conditions = :none) return _target.any?(&:persisted?) if id_or_conditions == :none From e6099e69e97d40965d7e5c4726c2a7c58e2faa98 Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:39:23 +0900 Subject: [PATCH 4/6] Update proxy.rb --- lib/mongoid/association/embedded/embeds_many/proxy.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/mongoid/association/embedded/embeds_many/proxy.rb b/lib/mongoid/association/embedded/embeds_many/proxy.rb index 9d5d0f7cfb..afcc7e7e4b 100644 --- a/lib/mongoid/association/embedded/embeds_many/proxy.rb +++ b/lib/mongoid/association/embedded/embeds_many/proxy.rb @@ -313,9 +313,12 @@ def destroy_all(conditions = {}) # # @return [ true | false ] True if persisted documents exist, false if not. def exists?(id_or_conditions = :none) - return _target.any?(&:persisted?) if id_or_conditions == :none - - criteria.exists?(id_or_conditions) + case id_or_conditions + when :none then _target.any?(&:persisted?) + when nil, false then false + when Hash then where(id_or_conditions).any?(&:persisted?) + else where(_id: id_or_conditions).any?(&:persisted?) + end end # Finds a document in this association through several different From 39a5296bd395090ff02d3ea35b61d357e58183ea Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Fri, 17 Nov 2023 07:57:19 +0900 Subject: [PATCH 5/6] Update proxy.rb --- lib/mongoid/association/embedded/embeds_many/proxy.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/mongoid/association/embedded/embeds_many/proxy.rb b/lib/mongoid/association/embedded/embeds_many/proxy.rb index afcc7e7e4b..10bacef36a 100644 --- a/lib/mongoid/association/embedded/embeds_many/proxy.rb +++ b/lib/mongoid/association/embedded/embeds_many/proxy.rb @@ -293,13 +293,14 @@ def destroy_all(conditions = {}) # person.posts.exists? # # @example Is a document with the given id persisted? - # context.exists?(BSON::ObjectId(...)) + # person.posts.exists?(BSON::ObjectId(...)) # # @example Are there persisted documents with the given title? # person.posts.exists?({ title: "50 Ways to Leave Your Lover" }) # - # @example Always return false. - # person.posts.exists?(false) + # @example Return false if nil is given. + # missing_post = nil + # person.posts.exists?(missing_post&._id) #=> false # # @param [ :none | nil | false | Hash | Object ] id_or_conditions # When :none (the default), returns true if any persisted From 13d9b7cf318e34dc0214eb20febf766e53f54861 Mon Sep 17 00:00:00 2001 From: Johnny Shields <27655+johnnyshields@users.noreply.github.com> Date: Fri, 17 Nov 2023 07:58:37 +0900 Subject: [PATCH 6/6] Update findable.rb --- lib/mongoid/findable.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mongoid/findable.rb b/lib/mongoid/findable.rb index 4545445cb1..19efbc0da9 100644 --- a/lib/mongoid/findable.rb +++ b/lib/mongoid/findable.rb @@ -108,8 +108,9 @@ def empty? # @example Do any documents exist for given conditions. # Person.exists?(name: "...") # - # @example Always return false. - # context.exists?(false) + # @example Return false if nil is given. + # missing_person = nil + # Person.exists?(missing_person&._id) #=> false # # @param [ :none | Hash | BSON::ObjectId | nil | false ] id_or_conditions # May optionally supply search conditions as a hash or an object id.