Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Atomic positionable $ replace
Uses the selector key, in the regex, to replace the digit to $ operator,
So even when we send another keys on the selector, it will still replace
only the ones that match on the operation
  • Loading branch information
arthurnn committed Feb 12, 2013
1 parent d4ad411 commit 96e56aa
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 26 deletions.
24 changes: 14 additions & 10 deletions lib/mongoid/atomic/positionable.rb
Expand Up @@ -38,31 +38,35 @@ def positionally(selector, operations, processed = {})
if selector.size == 1 || selector.values.any? { |val| val.nil? }
return operations
end
process_operations(selector.size - 2, operations, processed)
keys = selector.keys.map{ |m| m.sub('._id','') } - ['_id']
keys = keys.sort_by { |s| s.length*-1 }
process_operations(keys, operations, processed)
end

private

def process_operations(index, operations, processed)
def process_operations(keys, operations, processed)
operations.each_pair do |operation, update|
processed[operation] = process_updates(index, update)
processed[operation] = process_updates(keys, update)
end
processed
end

def process_updates(index, update, updates = {})
def process_updates(keys, update, updates = {})
update.each_pair do |position, value|
updates[replace_index(position, index)] = value
updates[replace_index(keys, position)] = value
end
updates
end

def replace_index(position, index, counter = 0)
position.gsub(/(\.\w+\.)/) do |match|
value = (counter == index && match[1, match.length - 2] =~ /\d+/) ? ".$." : match
counter += 1
value
def replace_index(keys, position)
# replace to $ only if that key is on the selector
keys.each do |kk|
if position =~ /^#{kk}\.\d+\.(.*)/
return "#{kk}.$.#{$1}"
end
end
position
end
end
end
Expand Down
69 changes: 53 additions & 16 deletions spec/mongoid/atomic/positionable_spec.rb
Expand Up @@ -26,25 +26,62 @@

context "when a child has an embeds many under an embeds one" do

let(:selector) do
{ "_id" => 1, "child._id" => 2 }
end
context "when selector does not include the embeds one" do

let(:ops) do
{
"$set" => {
"field" => "value",
"child.children.1.children.3.field" => "value",
let(:selector) do
{ "_id" => 1, "child._id" => 2 }
end

let(:ops) do
{
"$set" => {
"field" => "value",
"child.children.1.children.3.field" => "value",
}
}
}
end
end

let(:processed) do
positionable.positionally(selector, ops)
let(:processed) do
positionable.positionally(selector, ops)
end

it "does not do any replacement" do
processed.should eq(ops)
end
end

it "does not do any replacement" do
processed.should eq(ops)
context "when selector includes the embeds one" do

let(:selector) do
{ "_id" => 1, "child._id" => 2, "child.children._id" => 3 }
end

let(:ops) do
{
"$set" => {
"field" => "value",
"child.children.1.children.3.field" => "value",
}
}
end

let(:expected) do
{
"$set" => {
"field" => "value",
"child.children.$.children.3.field" => "value",
}
}
end


let(:processed) do
positionable.positionally(selector, ops)
end

it "does not do any replacement" do
processed.should eq(expected)
end
end
end

Expand Down Expand Up @@ -134,7 +171,7 @@
{
"$set" => {
"field" => "value",
"children.0.field" => "value",
"children.$.field" => "value",
"children.0.children.$.children.3.field" => "value",
"children.0.children.$.children.3.field" => "value",
},
Expand Down Expand Up @@ -168,7 +205,7 @@
{
"$set" => {
"field" => "value",
"children.0.field" => "value",
"children.$.field" => "value",
"children.0.children.1.children.$.field" => "value",
"children.0.children.1.children.$.field" => "value",
},
Expand Down

0 comments on commit 96e56aa

Please sign in to comment.