1#  Copyright 2014 - present 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
15use strict;
16use warnings;
17package MongoDB::BulkWriteView;
18
19# ABSTRACT: Bulk write operations against a query document
20
21use version;
22our $VERSION = 'v2.2.2';
23
24use Moo;
25
26use MongoDB::Error;
27use MongoDB::_Types qw(
28    Boolish
29    Document
30    IxHash
31);
32use Types::Standard qw(
33    Maybe
34    ArrayRef
35    InstanceOf
36);
37use boolean;
38use namespace::clean -except => 'meta';
39
40# A hash reference containing a MongoDB query document
41has _query => (
42    is       => 'ro',
43    isa      => IxHash,
44    coerce   => IxHash->coercion,
45    required => 1
46);
47
48# Originating bulk write object for executing write operations.
49has _bulk => (
50    is       => 'ro',
51    isa      => InstanceOf['MongoDB::BulkWrite'],
52    required => 1,
53    handles  => [qw/_enqueue_write/]
54);
55
56has _collation => (
57    is  => 'ro',
58    isa => Maybe [Document],
59);
60
61has _array_filters => (
62    is => 'ro',
63    isa => Maybe [ArrayRef[Document]],
64);
65
66has _upsert => (
67    is      => 'ro',
68    isa     => Boolish,
69    default => 0,
70);
71
72sub collation {
73    my ($self, $collation) = @_;
74    return $self->new( %$self, _collation => $collation );
75}
76
77sub arrayFilters {
78  my ( $self, $array_filters ) = @_;
79  return $self->new( %$self, _array_filters => $array_filters );
80}
81
82sub upsert {
83    my ($self) = @_;
84    unless ( @_ == 1 ) {
85        MongoDB::UsageError->throw("the upsert method takes no arguments");
86    }
87    return $self->new( %$self, _upsert => true );
88}
89
90sub update_many {
91    push @_, "update_many";
92    goto &_update;
93}
94
95sub update_one {
96    push @_, "update_one";
97    goto &_update;
98}
99
100sub replace_one {
101    push @_, "replace_one";
102    goto &_update;
103}
104
105sub _update {
106    my $method = pop @_;
107    my ( $self, $doc ) = @_;
108
109    my $type = ref $doc;
110    unless ( @_ == 2 && grep { $type eq $_ } qw/HASH ARRAY Tie::IxHash BSON::Array/ ) {
111        MongoDB::UsageError->throw("argument to $method must be a single hashref, arrayref, Tie::IxHash or BSON::Array");
112    }
113
114    if ( ref $doc eq 'ARRAY' ) {
115        MongoDB::UsageError->throw("array reference to $method must have key/value pairs")
116          if @$doc % 2;
117        $doc = Tie::IxHash->new(@$doc);
118    }
119    elsif ( ref $doc eq 'HASH' ) {
120        $doc = Tie::IxHash->new(%$doc);
121    }
122
123    $self->_bulk->_retryable( 0 ) if $method eq 'update_many';
124
125    my $update = {
126        q      => $self->_query,
127        u      => $doc,
128        multi  => $method eq 'update_many' ? true : false,
129        upsert => boolean( $self->_upsert ),
130        is_replace => $method eq 'replace_one',
131        (defined $self->_collation ? (collation => $self->_collation) : ()),
132        (defined $self->_array_filters ? (arrayFilters => $self->_array_filters) : ()),
133    };
134
135    $self->_enqueue_write( [ update => $update ] );
136
137    return;
138}
139
140sub delete_many {
141    my ($self) = @_;
142    $self->_bulk->_retryable( 0 );
143    $self->_enqueue_write(
144        [
145            delete => {
146                q     => $self->_query,
147                limit => 0,
148                ( defined $self->_collation ? ( collation => $self->_collation ) : () ),
149                (defined $self->_array_filters ? (arrayFilters => $self->_array_filters) : ()),
150            }
151        ]
152    );
153    return;
154}
155
156sub delete_one {
157    my ($self) = @_;
158    $self->_enqueue_write(
159        [
160            delete => {
161                q     => $self->_query,
162                limit => 1,
163                ( defined $self->_collation ? ( collation => $self->_collation ) : () ),
164                (defined $self->_array_filters ? (arrayFilters => $self->_array_filters) : ()),
165            }
166        ]
167    );
168    return;
169}
170
1711;
172
173__END__
174
175=pod
176
177=encoding UTF-8
178
179=head1 NAME
180
181MongoDB::BulkWriteView - Bulk write operations against a query document
182
183=head1 VERSION
184
185version v2.2.2
186
187=head1 SYNOPSIS
188
189    my $bulk = $collection->initialize_ordered_bulk_op;
190
191    # Update one document matching the selector
192    bulk->find( { a => 1 } )->update_one( { '$inc' => { x => 1 } } );
193
194    # Update all documents matching the selector
195    bulk->find( { a => 2 } )->update_many( { '$inc' => { x => 2 } } );
196
197    # Update all documents matching the selector, with respect to a collation
198    bulk->find( { a => { '$gte' => 'F' } )->collation($collation)
199          ->update_many( { '$inc' => { x => 2 } } );
200
201    # Update all documents
202    bulk->find( {} )->update_many( { '$inc' => { x => 2 } } );
203
204    # Replace entire document (update with whole doc replace)
205    bulk->find( { a => 3 } )->replace_one( { x => 3 } );
206
207    # Update one document matching the selector or upsert
208    bulk->find( { a => 1 } )->upsert()->update_one( { '$inc' => { x => 1 } } );
209
210    # Update all documents matching the selector or upsert
211    bulk->find( { a => 2 } )->upsert()->update_many( { '$inc' => { x => 2 } } );
212
213    # Replaces a single document matching the selector or upsert
214    bulk->find( { a => 3 } )->upsert()->replace_one( { x => 3 } );
215
216    # Remove a single document matching the selector
217    bulk->find( { a => 4 } )->delete_one();
218
219    # Remove all documents matching the selector
220    bulk->find( { a => 5 } )->delete_many();
221
222    # Update any arrays with the matching filter
223    bulk->find( {} )->arrayFilters([ { 'i.b' => 1 } ])->update_many( { '$set' => { 'y.$[i].b' => 2 } } );
224
225    # Remove all documents matching the selector, with respect to a collation
226    bulk->find( { a => { '$gte' => 'F' } )->collation($collation)->delete_many();
227
228    # Remove all documents
229    bulk->find( {} )->delete_many();
230
231=head1 DESCRIPTION
232
233This class provides means to specify write operations constrained by a query
234document.
235
236To instantiate a C<MongoDB::BulkWriteView>, use the L<find|MongoDB::BulkWrite/find>
237method from L<MongoDB::BulkWrite>.
238
239Except for L</arrayFilters>, L</collation> and L</upsert>, all methods have an
240empty return on success; an exception will be thrown on error.
241
242=head1 METHODS
243
244=head2 arrayFilters
245
246    $bulk->arrayFilters( $array_filters )->update_many( $modification );
247
248Returns a new C<MongoDB::BulkWriteView> object, where the specified arrayFilter
249will be used to determine which array elements to modify for an update
250operation on an array field.
251
252=head2 collation
253
254    $bulk->collation( $collation )->delete_one;
255
256Returns a new C<MongoDB::BulkWriteView> object, where the specified
257collation will be used to determine which documents match the query
258document.  A collation can be specified for any deletion, replacement,
259or update.
260
261=head2 delete_many
262
263    $bulk->delete_many;
264
265Removes all documents matching the query document.
266
267=head2 delete_one
268
269    $bulk->delete_one;
270
271Removes a single document matching the query document.
272
273=head2 replace_one
274
275    $bulk->replace_one( $doc );
276
277Replaces the document matching the query document.  The document
278to replace must not have any keys that begin with a dollar sign, C<$>.
279
280=head2 update_many
281
282    $bulk->update_many( $modification );
283
284Updates all documents  matching the query document.  The modification
285document must have all its keys begin with a dollar sign, C<$>.
286
287=head2 update_one
288
289    $bulk->update_one( $modification );
290
291Updates a single document matching the query document.  The modification
292document must have all its keys begin with a dollar sign, C<$>.
293
294=head2 upsert
295
296    $bulk->upsert->replace_one( $doc );
297
298Returns a new C<MongoDB::BulkWriteView> object that will treat every
299update, update_one or replace_one operation as an upsert operation.
300
301=head1 AUTHORS
302
303=over 4
304
305=item *
306
307David Golden <david@mongodb.com>
308
309=item *
310
311Rassi <rassi@mongodb.com>
312
313=item *
314
315Mike Friedman <friedo@friedo.com>
316
317=item *
318
319Kristina Chodorow <k.chodorow@gmail.com>
320
321=item *
322
323Florian Ragwitz <rafl@debian.org>
324
325=back
326
327=head1 COPYRIGHT AND LICENSE
328
329This software is Copyright (c) 2020 by MongoDB, Inc.
330
331This is free software, licensed under:
332
333  The Apache License, Version 2.0, January 2004
334
335=cut
336