our
$VERSION
=
'v1.999.0'
;
Boolish
Document
)
;
Maybe
ArrayRef
)
;
has
filter
=> (
is
=>
'ro'
,
required
=> 1,
isa
=> Document,
);
has
update
=> (
is
=>
'ro'
,
required
=> 1,
);
has
is_replace
=> (
is
=>
'ro'
,
required
=> 1,
isa
=> Boolish,
);
has
multi
=> (
is
=>
'ro'
,
required
=> 1,
isa
=> Boolish,
);
has
upsert
=> (
is
=>
'ro'
,
);
has
collation
=> (
is
=>
'ro'
,
isa
=> Maybe( [Document] ),
);
has
arrayFilters
=> (
is
=>
'ro'
,
isa
=> Maybe( [ArrayRef[Document]] ),
);
with
$_
for
qw(
MongoDB::Role::_PrivateConstructor
MongoDB::Role::_CollectionOp
MongoDB::Role::_SingleBatchDocWrite
MongoDB::Role::_UpdatePreEncoder
MongoDB::Role::_BypassValidation
)
;
my
(
$true
,
$false
) = (true, false);
sub
execute {
my
(
$self
,
$link
) =
@_
;
if
(
defined
$self
->collation ) {
MongoDB::UsageError->throw(
"MongoDB host '"
.
$link
->address .
"' doesn't support collation"
)
if
!
$link
->supports_collation;
MongoDB::UsageError->throw(
"Unacknowledged updates that specify a collation are not allowed"
)
if
!
$self
->write_concern->is_acknowledged;
}
if
(
defined
$self
->arrayFilters ) {
MongoDB::UsageError->throw(
"MongoDB host '"
.
$link
->address .
"' doesn't support arrayFilters"
)
if
!
$link
->supports_arrayFilters;
MongoDB::UsageError->throw(
"Unacknowledged updates that specify arrayFilters are not allowed"
)
if
!
$self
->write_concern->is_acknowledged;
}
my
$orig_op
= {
q =>
(
ref
(
$self
->filter ) eq
'ARRAY'
? { @{
$self
->filter } }
:
$self
->filter
),
u
=>
$self
->_pre_encode_update(
$link
->max_bson_object_size,
$self
->update,
$self
->is_replace ),
multi
=>
$self
->multi ?
$true
:
$false
,
upsert
=>
$self
->upsert ?
$true
:
$false
,
(
defined
$self
->collation ? (
collation
=>
$self
->collation ) : () ),
(
defined
$self
->arrayFilters ? (
arrayFilters
=>
$self
->arrayFilters ) : () ),
};
return
$self
->_send_legacy_op_noreply(
$link
,
MongoDB::_Protocol::write_update(
$self
->full_name,
$self
->bson_codec->encode_one(
$orig_op
->{
q}, { invalid_chars => '' }
),
$self
->_pre_encode_update(
$link
->max_bson_object_size,
$orig_op
->{u},
$self
->is_replace )->{bson},
{
upsert
=>
$orig_op
->{upsert},
multi
=>
$orig_op
->{multi},
},
),
$orig_op
,
"MongoDB::UpdateResult"
,
"update"
,
)
if
!
$self
->write_concern->is_acknowledged;
return
$self
->_send_write_command(
$link
,
$self
->_maybe_bypass(
$link
->supports_document_validation,
[
update
=>
$self
->coll_name,
updates
=> [
{
%$orig_op
,
u
=>
$self
->_pre_encode_update(
$link
->max_bson_object_size,
$orig_op
->{u},
$self
->is_replace
),
}
],
@{
$self
->write_concern->as_args },
],
),
$orig_op
,
"MongoDB::UpdateResult"
)->assert
if
$link
->supports_write_commands;
return
$self
->_send_legacy_op_with_gle(
$link
,
MongoDB::_Protocol::write_update(
$self
->full_name,
$self
->bson_codec->encode_one(
$orig_op
->{
q}, { invalid_chars => '' }
),
$self
->_pre_encode_update(
$link
->max_bson_object_size,
$orig_op
->{u},
$self
->is_replace )->{bson},
{
upsert
=>
$orig_op
->{upsert},
multi
=>
$orig_op
->{multi},
},
),
$orig_op
,
"MongoDB::UpdateResult"
,
"update"
,
)->assert;
}
sub
_parse_cmd {
my
(
$self
,
$res
) =
@_
;
return
(
matched_count
=> (
$res
->{n} || 0) - @{
$res
->{upserted} || [] },
modified_count
=>
$res
->{nModified},
upserted_id
=>
$res
->{upserted} ?
$res
->{upserted}[0]{_id} :
undef
,
);
}
sub
_parse_gle {
my
(
$self
,
$res
,
$orig_doc
) =
@_
;
my
$upserted
=
$res
->{upserted};
if
(!
defined
(
$upserted
)
&&
exists
(
$res
->{updatedExisting} )
&& !
$res
->{updatedExisting}
&&
$res
->{n} == 1 )
{
$upserted
=
$self
->_find_id(
$orig_doc
->{u} );
$upserted
=
$self
->_find_id(
$orig_doc
->{
q} ) unless defined $upserted;
}
return
(
matched_count
=> (
$upserted
? 0 :
$res
->{n} || 0),
modified_count
=>
undef
,
upserted_id
=>
$upserted
,
);
}
sub
_find_id {
my
(
$self
,
$doc
) =
@_
;
if
(
ref
(
$doc
) eq
"BSON::Raw"
) {
$doc
=
$self
->bson_codec->decode_one(
$doc
);
}
my
$type
=
ref
(
$doc
);
return
(
$type
eq
'HASH'
?
$doc
->{_id}
:
$type
eq
'ARRAY'
?
do
{
my
$i
;
for
(
$i
= 0;
$i
<
@$doc
;
$i
++ ) {
last
if
$doc
->[
$i
] eq
'_id'
}
$i
<
$#$doc
?
$doc
->[
$i
+ 1 ] :
undef
;
}
:
$type
eq
'Tie::IxHash'
?
$doc
->FETCH(
'_id'
)
:
$doc
->{_id}
);
}
1;