Skip to content

Commit 8efba1e

Browse files
committed
Merge pull request #593 from estolfo/RUBY-882-id
RUBY 882 Add id to document before inserting if it's missing one
2 parents 648aad1 + b456881 commit 8efba1e

File tree

13 files changed

+206
-16
lines changed

13 files changed

+206
-16
lines changed

lib/mongo/operation/result.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def each(&block)
119119
documents.each(&block)
120120
end
121121

122-
# Initialize a new result result.
122+
# Initialize a new result.
123123
#
124124
# @example Instantiate the result.
125125
# Result.new(replies)

lib/mongo/operation/write.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
require 'mongo/operation/write/idable'
1516
require 'mongo/operation/write/bulk'
1617
require 'mongo/operation/write/delete'
1718
require 'mongo/operation/write/insert'

lib/mongo/operation/write/bulk/bulk_insert.rb

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ module Write
4747
# @since 2.0.0
4848
class BulkInsert
4949
include Specifiable
50+
include Idable
5051

5152
# Execute the bulk insert operation.
5253
#
@@ -69,21 +70,22 @@ def execute(context)
6970
private
7071

7172
def execute_write_command(context)
72-
Result.new(Command::Insert.new(spec).execute(context))
73+
command_spec = spec.merge(:documents => ensure_ids(documents))
74+
Result.new(Command::Insert.new(command_spec).execute(context), @ids)
7375
end
7476

7577
def execute_message(context)
7678
replies = []
7779
messages.map do |m|
7880
context.with_connection do |connection|
79-
result = LegacyResult.new(connection.dispatch([ m, gle ].compact))
81+
result = LegacyResult.new(connection.dispatch([ m, gle ].compact), @ids)
8082
replies << result.reply
8183
if stop_sending?(result)
82-
return LegacyResult.new(replies)
84+
return LegacyResult.new(replies, @ids)
8385
end
8486
end
8587
end
86-
LegacyResult.new(replies.compact.empty? ? nil : replies)
88+
LegacyResult.new(replies.compact.empty? ? nil : replies, @ids)
8789
end
8890

8991
def stop_sending?(result)
@@ -117,10 +119,10 @@ def gle
117119
def messages
118120
if ordered? || gle
119121
documents.collect do |doc|
120-
Protocol::Insert.new(db_name, coll_name, [ doc ], options)
122+
Protocol::Insert.new(db_name, coll_name, ensure_ids([ doc ]), options)
121123
end
122124
else
123-
[ Protocol::Insert.new(db_name, coll_name, documents, { :flags => [:continue_on_error] }) ]
125+
[ Protocol::Insert.new(db_name, coll_name, ensure_ids(documents), { :flags => [:continue_on_error] }) ]
124126
end
125127
end
126128
end

lib/mongo/operation/write/bulk/bulk_insert/result.rb

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,25 @@ class BulkInsert
2626
class Result < Operation::Result
2727
include BulkMergable
2828

29+
# Get the ids of the inserted documents.
30+
#
31+
# @since 2.0.0
32+
attr_reader :inserted_ids
33+
34+
# Initialize a new result.
35+
#
36+
# @example Instantiate the result.
37+
# Result.new(replies, inserted_ids)
38+
#
39+
# @param [ Protocol::Reply ] replies The wire protocol replies.
40+
# @params [ Array<Object> ] ids The ids of the inserted documents.
41+
#
42+
# @since 2.0.0
43+
def initialize(replies, ids)
44+
@replies = replies.is_a?(Protocol::Reply) ? [ replies ] : replies
45+
@inserted_ids = ids
46+
end
47+
2948
# Gets the number of documents inserted.
3049
#
3150
# @example Get the number of documents inserted.
@@ -37,6 +56,18 @@ class Result < Operation::Result
3756
def n_inserted
3857
written_count
3958
end
59+
60+
# Gets the id of the document inserted.
61+
#
62+
# @example Get id of the document inserted.
63+
# result.inserted_id
64+
#
65+
# @return [ Object ] The id of the document inserted.
66+
#
67+
# @since 2.0.0
68+
def inserted_id
69+
inserted_ids.first
70+
end
4071
end
4172

4273
# Defines custom behaviour of results when inserting.
@@ -46,6 +77,25 @@ def n_inserted
4677
class LegacyResult < Operation::Result
4778
include LegacyBulkMergable
4879

80+
# Get the ids of the inserted documents.
81+
#
82+
# @since 2.0.0
83+
attr_reader :inserted_ids
84+
85+
# Initialize a new result.
86+
#
87+
# @example Instantiate the result.
88+
# Result.new(replies, inserted_ids)
89+
#
90+
# @param [ Protocol::Reply ] replies The wire protocol replies.
91+
# @params [ Array<Object> ] ids The ids of the inserted documents.
92+
#
93+
# @since 2.0.0
94+
def initialize(replies, ids)
95+
@replies = replies.is_a?(Protocol::Reply) ? [ replies ] : replies
96+
@inserted_ids = ids
97+
end
98+
4999
# Gets the number of documents inserted.
50100
#
51101
# @example Get the number of documents inserted.
@@ -61,6 +111,18 @@ def n_inserted
61111
n
62112
end
63113
end
114+
115+
# Gets the id of the document inserted.
116+
#
117+
# @example Get id of the document inserted.
118+
# result.inserted_id
119+
#
120+
# @return [ Object ] The id of the document inserted.
121+
#
122+
# @since 2.0.0
123+
def inserted_id
124+
inserted_ids.first
125+
end
64126
end
65127
end
66128
end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright (C) 2014-2015 MongoDB, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
module Mongo
16+
module Operation
17+
module Write
18+
module Idable
19+
20+
private
21+
22+
def id(doc)
23+
doc.respond_to?(:id) ? doc.id : (doc['_id'] || doc[:_id])
24+
end
25+
26+
def has_id?(doc)
27+
id(doc)
28+
end
29+
30+
def ensure_ids(documents)
31+
@ids ||= []
32+
documents.collect do |doc|
33+
doc_with_id = has_id?(doc) ? doc : doc.merge(_id: BSON::ObjectId.new)
34+
@ids << id(doc_with_id)
35+
doc_with_id
36+
end
37+
end
38+
end
39+
end
40+
end
41+
end

lib/mongo/operation/write/insert.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module Write
4444
class Insert
4545
include Executable
4646
include Specifiable
47+
include Idable
4748

4849
# Execute the insert operation.
4950
#
@@ -66,12 +67,13 @@ def execute(context)
6667
private
6768

6869
def execute_write_command(context)
69-
Result.new(Command::Insert.new(spec).execute(context)).validate!
70+
command_spec = spec.merge(:documents => ensure_ids(documents))
71+
Result.new(Command::Insert.new(command_spec).execute(context), @ids).validate!
7072
end
7173

7274
def execute_message(context)
7375
context.with_connection do |connection|
74-
Result.new(connection.dispatch([ message, gle ].compact)).validate!
76+
Result.new(connection.dispatch([ message, gle ].compact), @ids).validate!
7577
end
7678
end
7779

@@ -82,7 +84,7 @@ def initialize_copy(original)
8284

8385
def message
8486
opts = !!options[:continue_on_error] ? { :flags => [:continue_on_error] } : {}
85-
Protocol::Insert.new(db_name, coll_name, documents, opts)
87+
Protocol::Insert.new(db_name, coll_name, ensure_ids(documents), opts)
8688
end
8789
end
8890
end

lib/mongo/operation/write/insert/result.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,36 @@ class Insert
2525
# @since 2.0.0
2626
class Result < Operation::Result
2727

28+
# Get the ids of the inserted documents.
29+
#
30+
# @since 2.0.0
31+
attr_reader :inserted_ids
32+
33+
# Initialize a new result.
34+
#
35+
# @example Instantiate the result.
36+
# Result.new(replies, inserted_ids)
37+
#
38+
# @param [ Protocol::Reply ] replies The wire protocol replies.
39+
# @params [ Array<Object> ] ids The ids of the inserted documents.
40+
#
41+
# @since 2.0.0
42+
def initialize(replies, ids)
43+
@replies = replies.is_a?(Protocol::Reply) ? [ replies ] : replies
44+
@inserted_ids = ids
45+
end
46+
47+
# Gets the id of the document inserted.
48+
#
49+
# @example Get id of the document inserted.
50+
# result.inserted_id
51+
#
52+
# @return [ Object ] The id of the document inserted.
53+
#
54+
# @since 2.0.0
55+
def inserted_id
56+
inserted_ids.first
57+
end
2858
end
2959
end
3060
end

spec/mongo/operation/write/bulk_insert_spec.rb renamed to spec/mongo/operation/write/bulk/bulk_insert_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
described_class.new(spec)
2020
end
2121

22+
after do
23+
authorized_collection.find.delete_many
24+
end
25+
2226
describe '#initialize' do
2327

2428
context 'spec' do
@@ -81,6 +85,29 @@
8185
end
8286
end
8387

88+
describe 'document ids' do
89+
90+
context 'when documents do not contain an id' do
91+
92+
let(:documents) do
93+
[{ 'field' => 'test' },
94+
{ 'field' => 'test' }]
95+
end
96+
97+
let(:inserted_ids) do
98+
op.execute(authorized_primary.context).inserted_ids
99+
end
100+
101+
let(:collection_ids) do
102+
authorized_collection.find(field: 'test').collect { |d| d['_id'] }
103+
end
104+
105+
it 'adds an id to the documents' do
106+
expect(inserted_ids).to eq(collection_ids)
107+
end
108+
end
109+
end
110+
84111
describe '#execute' do
85112

86113
before do

0 commit comments

Comments
 (0)