Skip to content

Commit f6a9660

Browse files
authored
MONGOID-5582 port more robust shard key processing to 7.5 (#5579)
* Correctly interpret shard keys in embedded documents * oof, neglected to save this before committing last time * wups, raised exception is different in 7.5 versus 8+ * code review feedback
1 parent bd7689a commit f6a9660

File tree

4 files changed

+207
-63
lines changed

4 files changed

+207
-63
lines changed

lib/mongoid/shardable.rb

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,22 @@ def shard_key_fields
4747
self.class.shard_key_fields
4848
end
4949

50-
# Returns the selector that would match the current version of this
51-
# document.
50+
# Returns the selector that would match the defined shard keys. If
51+
# `prefer_persisted` is false (the default), it uses the current values
52+
# of the specified shard keys, otherwise, it will try to use whatever value
53+
# was most recently persisted.
54+
#
55+
# @param [ true | false ] prefer_persisted Whether to use the current
56+
# value of the shard key fields, or to use their most recently persisted
57+
# values.
5258
#
5359
# @return [ Hash ] The shard key selector.
5460
#
5561
# @api private
56-
def shard_key_selector
57-
selector = {}
58-
shard_key_fields.each do |field|
59-
selector[field.to_s] = send(field)
62+
def shard_key_selector(prefer_persisted: false)
63+
shard_key_fields.each_with_object({}) do |field, selector|
64+
selector[field.to_s] = shard_key_field_value(field.to_s, prefer_persisted: prefer_persisted)
6065
end
61-
selector
6266
end
6367

6468
# Returns the selector that would match the existing version of this
@@ -72,11 +76,31 @@ def shard_key_selector
7276
#
7377
# @api private
7478
def shard_key_selector_in_db
75-
selector = {}
76-
shard_key_fields.each do |field|
77-
selector[field.to_s] = new_record? ? send(field) : attribute_was(field)
79+
shard_key_selector(prefer_persisted: true)
80+
end
81+
82+
# Returns the value for the named shard key. If the field identifies
83+
# an embedded document, the key will be parsed and recursively evaluated.
84+
# If `prefer_persisted` is true, the value last persisted to the database
85+
# will be returned, regardless of what the current value of the attribute
86+
# may be.
87+
#
88+
# @param [String] field The name of the field to evaluate
89+
# @param [ true|false ] prefer_persisted Whether or not to prefer the
90+
# persisted value over the current value.
91+
#
92+
# @return [ Object ] The value of the named field.
93+
#
94+
# @api private
95+
def shard_key_field_value(field, prefer_persisted:)
96+
if field.include?(".")
97+
relation, remaining = field.split(".", 2)
98+
send(relation)&.shard_key_field_value(remaining, prefer_persisted: prefer_persisted)
99+
elsif prefer_persisted && !new_record?
100+
attribute_was(field)
101+
else
102+
send(field)
78103
end
79-
selector
80104
end
81105

82106
module ClassMethods

spec/mongoid/shardable_models.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,17 @@ class SmDriver
5959
class SmNotSharded
6060
include Mongoid::Document
6161
end
62+
63+
class SmReviewAuthor
64+
include Mongoid::Document
65+
embedded_in :review, class_name: "SmReview", touch: false
66+
field :name, type: String
67+
end
68+
69+
class SmReview
70+
include Mongoid::Document
71+
72+
embeds_one :author, class_name: "SmReviewAuthor"
73+
74+
shard_key "author.name" => 1
75+
end

0 commit comments

Comments
 (0)