Coverage Report - com.allanbank.mongodb.builder.FindAndModify
 
Classes in this File Line Coverage Branch Coverage Complexity
FindAndModify
100%
25/25
100%
4/4
1.059
FindAndModify$Builder
100%
46/46
100%
2/2
1.059
 
 1  
 /*
 2  
  * #%L
 3  
  * FindAndModify.java - mongodb-async-driver - Allanbank Consulting, Inc.
 4  
  * %%
 5  
  * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
 6  
  * %%
 7  
  * Licensed under the Apache License, Version 2.0 (the "License");
 8  
  * you may not use this file except in compliance with the License.
 9  
  * You may obtain a copy of the License at
 10  
  * 
 11  
  *      http://www.apache.org/licenses/LICENSE-2.0
 12  
  * 
 13  
  * Unless required by applicable law or agreed to in writing, software
 14  
  * distributed under the License is distributed on an "AS IS" BASIS,
 15  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  
  * See the License for the specific language governing permissions and
 17  
  * limitations under the License.
 18  
  * #L%
 19  
  */
 20  
 
 21  
 package com.allanbank.mongodb.builder;
 22  
 
 23  
 import static com.allanbank.mongodb.util.Assertions.assertNotNull;
 24  
 import static com.allanbank.mongodb.util.Assertions.assertThat;
 25  
 
 26  
 import java.util.concurrent.TimeUnit;
 27  
 
 28  
 import com.allanbank.mongodb.MongoCollection;
 29  
 import com.allanbank.mongodb.Version;
 30  
 import com.allanbank.mongodb.bson.Document;
 31  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 32  
 import com.allanbank.mongodb.bson.builder.BuilderFactory;
 33  
 import com.allanbank.mongodb.bson.builder.DocumentBuilder;
 34  
 import com.allanbank.mongodb.bson.element.IntegerElement;
 35  
 
 36  
 /**
 37  
  * Represents the state of a single {@link MongoCollection#findAndModify}
 38  
  * command. Objects of this class are created using the nested {@link Builder}.
 39  
  * 
 40  
  * @api.yes This class is part of the driver's API. Public and protected members
 41  
  *          will be deprecated for at least 1 non-bugfix release (version
 42  
  *          numbers are <major>.<minor>.<bugfix>) before being
 43  
  *          removed or modified.
 44  
  * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
 45  
  */
 46  
 public class FindAndModify {
 47  
     /** An (empty) query document to find all documents. */
 48  1
     public static final Document ALL = MongoCollection.ALL;
 49  
 
 50  
     /**
 51  
      * The first version of MongoDB to support the {@code findAndModify} command
 52  
      * with the ability to limit the execution time on the server.
 53  
      */
 54  1
     public static final Version MAX_TIMEOUT_VERSION = Find.MAX_TIMEOUT_VERSION;
 55  
 
 56  
     /** An (empty) update document to perform no actual modifications. */
 57  1
     public static final Document NONE = MongoCollection.NONE;
 58  
 
 59  
     /**
 60  
      * Creates a new builder for a {@link FindAndModify}.
 61  
      * 
 62  
      * @return The builder to construct a {@link FindAndModify}.
 63  
      */
 64  
     public static Builder builder() {
 65  4
         return new Builder();
 66  
     }
 67  
 
 68  
     /** The subset of fields to retrieve from the matched document. */
 69  
     private final Document myFields;
 70  
 
 71  
     /** The maximum amount of time to allow the command to run. */
 72  
     private final long myMaximumTimeMilliseconds;
 73  
 
 74  
     /** The query to locate the document to update. */
 75  
     private final Document myQuery;
 76  
 
 77  
     /** Set to a true to remove the object before returning */
 78  
     private final boolean myRemove;
 79  
 
 80  
     /**
 81  
      * Set to true if you want to return the modified object rather than the
 82  
      * original. Ignored for remove.
 83  
      */
 84  
     private final boolean myReturnNew;
 85  
 
 86  
     /**
 87  
      * If multiple docs match, choose the first one in the specified sort order
 88  
      * as the object to manipulate.
 89  
      */
 90  
     private final Document mySort;
 91  
 
 92  
     /** The updates to be applied to the document. */
 93  
     private final Document myUpdate;
 94  
 
 95  
     /** If true create the document if it doesn't exist. */
 96  
     private final boolean myUpsert;
 97  
 
 98  
     /**
 99  
      * Create a new FindAndModify.
 100  
      * 
 101  
      * @param builder
 102  
      *            The builder to copy from.
 103  
      */
 104  33
     protected FindAndModify(final Builder builder) {
 105  33
         assertNotNull(builder.myQuery,
 106  
                 "The findAndModify's query document cannot be null or empty.");
 107  31
         assertNotNull(builder.myQuery,
 108  
                 "The findAndModify's query document cannot be null or empty.");
 109  31
         assertThat((builder.myUpdate != null) || builder.myRemove,
 110  
                 "The findAndModify must have an update document or be a remove.");
 111  
 
 112  30
         myQuery = builder.myQuery;
 113  30
         myUpdate = builder.myUpdate;
 114  30
         mySort = builder.mySort;
 115  30
         myFields = builder.myFields;
 116  30
         myUpsert = builder.myUpsert;
 117  30
         myReturnNew = builder.myReturnNew;
 118  30
         myRemove = builder.myRemove;
 119  30
         myMaximumTimeMilliseconds = builder.myMaximumTimeMilliseconds;
 120  30
     }
 121  
 
 122  
     /**
 123  
      * Returns the subset of fields to retrieve from the matched document.
 124  
      * 
 125  
      * @return The subset of fields to retrieve from the matched document.
 126  
      */
 127  
     public Document getFields() {
 128  14
         return myFields;
 129  
     }
 130  
 
 131  
     /**
 132  
      * Returns the maximum amount of time to allow the command to run on the
 133  
      * Server before it is aborted.
 134  
      * 
 135  
      * @return The maximum amount of time to allow the command to run on the
 136  
      *         Server before it is aborted.
 137  
      * 
 138  
      * @since MongoDB 2.6
 139  
      */
 140  
     public long getMaximumTimeMilliseconds() {
 141  15
         return myMaximumTimeMilliseconds;
 142  
     }
 143  
 
 144  
     /**
 145  
      * Returns the query to locate the document to update.
 146  
      * 
 147  
      * @return The query to locate the document to update.
 148  
      */
 149  
     public Document getQuery() {
 150  36
         return myQuery;
 151  
     }
 152  
 
 153  
     /**
 154  
      * Returns the sort to apply if multiple docs match, choose the first one as
 155  
      * the object to manipulate.
 156  
      * 
 157  
      * @return The sort to apply if multiple docs match, choose the first one as
 158  
      *         the object to manipulate.
 159  
      */
 160  
     public Document getSort() {
 161  17
         return mySort;
 162  
     }
 163  
 
 164  
     /**
 165  
      * Returns the updates to be applied to the document.
 166  
      * 
 167  
      * @return The updates to be applied to the document.
 168  
      */
 169  
     public Document getUpdate() {
 170  34
         return myUpdate;
 171  
     }
 172  
 
 173  
     /**
 174  
      * Returns true if the document should be removed.
 175  
      * 
 176  
      * @return True if the document should be removed.
 177  
      */
 178  
     public boolean isRemove() {
 179  16
         return myRemove;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Returns true if the updated document should be returned instead of the
 184  
      * document before the update.
 185  
      * 
 186  
      * @return True if the updated document should be returned instead of the
 187  
      *         document before the update.
 188  
      */
 189  
     public boolean isReturnNew() {
 190  16
         return myReturnNew;
 191  
     }
 192  
 
 193  
     /**
 194  
      * Returns true to create the document if it doesn't exist.
 195  
      * 
 196  
      * @return True to create the document if it doesn't exist.
 197  
      */
 198  
     public boolean isUpsert() {
 199  16
         return myUpsert;
 200  
     }
 201  
 
 202  
     /**
 203  
      * Helper for creating immutable {@link FindAndModify} commands.
 204  
      * 
 205  
      * @api.yes This class is part of the driver's API. Public and protected
 206  
      *          members will be deprecated for at least 1 non-bugfix release
 207  
      *          (version numbers are <major>.<minor>.<bugfix>)
 208  
      *          before being removed or modified.
 209  
      * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
 210  
      */
 211  
     public static class Builder {
 212  
         /** Retrieve a subset of fields from the matched document. */
 213  
         protected Document myFields;
 214  
 
 215  
         /** The maximum amount of time to allow the command to run. */
 216  
         protected long myMaximumTimeMilliseconds;
 217  
 
 218  
         /** A query to locate the document to update. */
 219  
         protected Document myQuery;
 220  
 
 221  
         /** Set to a true to remove the object before returning */
 222  
         protected boolean myRemove;
 223  
 
 224  
         /**
 225  
          * Set to true if you want to return the modified object rather than the
 226  
          * original. Ignored for remove.
 227  
          */
 228  
         protected boolean myReturnNew;
 229  
 
 230  
         /**
 231  
          * If multiple docs match, choose the first one in the specified sort
 232  
          * order as the object to manipulate.
 233  
          */
 234  
         protected Document mySort;
 235  
 
 236  
         /** Updates to be applied to the document. */
 237  
         protected Document myUpdate;
 238  
 
 239  
         /** Create object if it doesn't exist. */
 240  
         protected boolean myUpsert;
 241  
 
 242  
         /**
 243  
          * Creates a new Builder.
 244  
          */
 245  21
         public Builder() {
 246  21
             reset();
 247  21
         }
 248  
 
 249  
         /**
 250  
          * Constructs a new {@link FindAndModify} object from the state of the
 251  
          * builder.
 252  
          * 
 253  
          * @return The new {@link FindAndModify} object.
 254  
          */
 255  
         public FindAndModify build() {
 256  33
             return new FindAndModify(this);
 257  
         }
 258  
 
 259  
         /**
 260  
          * Sets the subset of fields to retrieve from the matched document.
 261  
          * <p>
 262  
          * This method delegates to {@link #setFields(DocumentAssignable)}.
 263  
          * </p>
 264  
          * 
 265  
          * @param fields
 266  
          *            The subset of fields to retrieve from the matched
 267  
          *            document.
 268  
          * @return This builder for chaining method calls.
 269  
          */
 270  
         public Builder fields(final DocumentAssignable fields) {
 271  2
             return setFields(fields);
 272  
         }
 273  
 
 274  
         /**
 275  
          * Sets the maximum number of milliseconds to allow the command to run
 276  
          * before aborting the request on the server.
 277  
          * <p>
 278  
          * This method equivalent to {@link #setMaximumTimeMilliseconds(long)
 279  
          * setMaximumTimeMilliseconds(timeLimitUnits.toMillis(timeLimit)}.
 280  
          * </p>
 281  
          * 
 282  
          * @param timeLimit
 283  
          *            The new maximum amount of time to allow the command to
 284  
          *            run.
 285  
          * @param timeLimitUnits
 286  
          *            The units for the maximum amount of time to allow the
 287  
          *            command to run.
 288  
          * 
 289  
          * @return This {@link Builder} for method call chaining.
 290  
          * 
 291  
          * @since MongoDB 2.6
 292  
          */
 293  
         public Builder maximumTime(final long timeLimit,
 294  
                 final TimeUnit timeLimitUnits) {
 295  2
             return setMaximumTimeMilliseconds(timeLimitUnits
 296  
                     .toMillis(timeLimit));
 297  
         }
 298  
 
 299  
         /**
 300  
          * Sets the query to locate the document to update.
 301  
          * <p>
 302  
          * This method delegates to {@link #setQuery(DocumentAssignable)}.
 303  
          * </p>
 304  
          * 
 305  
          * @param query
 306  
          *            The query to locate the document to update.
 307  
          * @return This builder for chaining method calls.
 308  
          */
 309  
         public Builder query(final DocumentAssignable query) {
 310  3
             return setQuery(query);
 311  
         }
 312  
 
 313  
         /**
 314  
          * Sets to true if the document should be removed.
 315  
          * <p>
 316  
          * This method delegates to {@link #setRemove(boolean) setRemove(true)}.
 317  
          * </p>
 318  
          * 
 319  
          * @return This builder for chaining method calls.
 320  
          */
 321  
         public Builder remove() {
 322  2
             return setRemove(true);
 323  
         }
 324  
 
 325  
         /**
 326  
          * Sets to true if the document should be removed.
 327  
          * <p>
 328  
          * This method delegates to {@link #setRemove(boolean)}.
 329  
          * </p>
 330  
          * 
 331  
          * @param remove
 332  
          *            True if the document should be removed.
 333  
          * @return This builder for chaining method calls.
 334  
          */
 335  
         public Builder remove(final boolean remove) {
 336  1
             return setRemove(remove);
 337  
         }
 338  
 
 339  
         /**
 340  
          * Resets the builder back to its initial state.
 341  
          * 
 342  
          * @return This {@link Builder} for method call chaining.
 343  
          */
 344  
         public Builder reset() {
 345  22
             myFields = null;
 346  22
             myQuery = null;
 347  22
             myRemove = false;
 348  22
             myReturnNew = false;
 349  22
             mySort = null;
 350  22
             myUpdate = null;
 351  22
             myUpsert = false;
 352  22
             myMaximumTimeMilliseconds = 0;
 353  
 
 354  22
             return this;
 355  
         }
 356  
 
 357  
         /**
 358  
          * Sets to true if the updated document should be returned instead of
 359  
          * the document before the update.
 360  
          * <p>
 361  
          * This method delegates to {@link #setReturnNew(boolean)
 362  
          * setReturnNew(true)}.
 363  
          * </p>
 364  
          * 
 365  
          * @return This builder for chaining method calls.
 366  
          */
 367  
         public Builder returnNew() {
 368  1
             return setReturnNew(true);
 369  
         }
 370  
 
 371  
         /**
 372  
          * Sets to true if the updated document should be returned instead of
 373  
          * the document before the update.
 374  
          * <p>
 375  
          * This method delegates to {@link #setReturnNew(boolean)}.
 376  
          * </p>
 377  
          * 
 378  
          * @param returnNew
 379  
          *            True if the updated document should be returned instead of
 380  
          *            the document before the update.
 381  
          * @return This builder for chaining method calls.
 382  
          */
 383  
         public Builder returnNew(final boolean returnNew) {
 384  1
             return setReturnNew(returnNew);
 385  
         }
 386  
 
 387  
         /**
 388  
          * Sets the subset of fields to retrieve from the matched document.
 389  
          * 
 390  
          * @param fields
 391  
          *            The subset of fields to retrieve from the matched
 392  
          *            document.
 393  
          * @return This builder for chaining method calls.
 394  
          */
 395  
         public Builder setFields(final DocumentAssignable fields) {
 396  4
             myFields = fields.asDocument();
 397  4
             return this;
 398  
         }
 399  
 
 400  
         /**
 401  
          * Sets the maximum number of milliseconds to allow the command to run
 402  
          * before aborting the request on the server.
 403  
          * 
 404  
          * @param maximumTimeMilliseconds
 405  
          *            The new maximum number of milliseconds to allow the
 406  
          *            command to run.
 407  
          * @return This {@link Builder} for method call chaining.
 408  
          * 
 409  
          * @since MongoDB 2.6
 410  
          */
 411  
         public Builder setMaximumTimeMilliseconds(
 412  
                 final long maximumTimeMilliseconds) {
 413  3
             myMaximumTimeMilliseconds = maximumTimeMilliseconds;
 414  3
             return this;
 415  
         }
 416  
 
 417  
         /**
 418  
          * Sets the query to locate the document to update.
 419  
          * 
 420  
          * @param query
 421  
          *            The query to locate the document to update.
 422  
          * @return This builder for chaining method calls.
 423  
          */
 424  
         public Builder setQuery(final DocumentAssignable query) {
 425  21
             myQuery = query.asDocument();
 426  21
             return this;
 427  
         }
 428  
 
 429  
         /**
 430  
          * Sets to true if the document should be removed.
 431  
          * 
 432  
          * @param remove
 433  
          *            True if the document should be removed.
 434  
          * @return This builder for chaining method calls.
 435  
          */
 436  
         public Builder setRemove(final boolean remove) {
 437  7
             myRemove = remove;
 438  7
             return this;
 439  
         }
 440  
 
 441  
         /**
 442  
          * Sets to true if the updated document should be returned instead of
 443  
          * the document before the update.
 444  
          * 
 445  
          * @param returnNew
 446  
          *            True if the updated document should be returned instead of
 447  
          *            the document before the update.
 448  
          * @return This builder for chaining method calls.
 449  
          */
 450  
         public Builder setReturnNew(final boolean returnNew) {
 451  4
             myReturnNew = returnNew;
 452  4
             return this;
 453  
         }
 454  
 
 455  
         /**
 456  
          * Sets the sort to apply if multiple docs match, choose the first one
 457  
          * as the object to manipulate.
 458  
          * 
 459  
          * @param sort
 460  
          *            The sort to apply if multiple docs match, choose the first
 461  
          *            one as the object to manipulate.
 462  
          * @return This builder for chaining method calls.
 463  
          */
 464  
         public Builder setSort(final DocumentAssignable sort) {
 465  2
             mySort = sort.asDocument();
 466  2
             return this;
 467  
         }
 468  
 
 469  
         /**
 470  
          * Sets the sort to apply if multiple docs match, choose the first one
 471  
          * as the object to manipulate.
 472  
          * <p>
 473  
          * This method is intended to be used with the {@link Sort} class's
 474  
          * static methods: <blockquote>
 475  
          * 
 476  
          * <pre>
 477  
          * <code>
 478  
          * import static {@link Sort#asc(String) com.allanbank.mongodb.builder.Sort.asc};
 479  
          * import static {@link Sort#desc(String) com.allanbank.mongodb.builder.Sort.desc};
 480  
          * 
 481  
          * FindAndModify.Builder builder = new Find.Builder();
 482  
          * 
 483  
          * builder.setSort( asc("f"), desc("g") );
 484  
          * ...
 485  
          * </code>
 486  
          * </pre>
 487  
          * 
 488  
          * </blockquote>
 489  
          * 
 490  
          * @param sortFields
 491  
          *            The sort to apply if multiple docs match, choose the first
 492  
          *            one as the object to manipulate.
 493  
          * @return This builder for chaining method calls.
 494  
          */
 495  
         public Builder setSort(final IntegerElement... sortFields) {
 496  2
             final DocumentBuilder builder = BuilderFactory.start();
 497  4
             for (final IntegerElement sortField : sortFields) {
 498  2
                 builder.add(sortField);
 499  
             }
 500  2
             mySort = builder.build();
 501  2
             return this;
 502  
         }
 503  
 
 504  
         /**
 505  
          * Sets the updates to be applied to the document.
 506  
          * 
 507  
          * @param update
 508  
          *            The updates to be applied to the document.
 509  
          * @return This builder for chaining method calls.
 510  
          */
 511  
         public Builder setUpdate(final DocumentAssignable update) {
 512  17
             myUpdate = update.asDocument();
 513  17
             return this;
 514  
         }
 515  
 
 516  
         /**
 517  
          * Sets to true to create the document if it doesn't exist.
 518  
          * 
 519  
          * @param upsert
 520  
          *            True to create the document if it doesn't exist.
 521  
          * @return This builder for chaining method calls.
 522  
          */
 523  
         public Builder setUpsert(final boolean upsert) {
 524  4
             myUpsert = upsert;
 525  4
             return this;
 526  
         }
 527  
 
 528  
         /**
 529  
          * Sets the sort to apply if multiple docs match, choose the first one
 530  
          * as the object to manipulate.
 531  
          * <p>
 532  
          * This method delegates to {@link #setSort(DocumentAssignable)}.
 533  
          * </p>
 534  
          * 
 535  
          * @param sort
 536  
          *            The sort to apply if multiple docs match, choose the first
 537  
          *            one as the object to manipulate.
 538  
          * @return This builder for chaining method calls.
 539  
          */
 540  
         public Builder sort(final DocumentAssignable sort) {
 541  2
             return setSort(sort);
 542  
         }
 543  
 
 544  
         /**
 545  
          * Sets the sort to apply if multiple docs match, choose the first one
 546  
          * as the object to manipulate.
 547  
          * <p>
 548  
          * This method delegates to {@link #setSort(IntegerElement...)}.
 549  
          * </p>
 550  
          * <p>
 551  
          * This method is intended to be used with the {@link Sort} class's
 552  
          * static methods: <blockquote>
 553  
          * 
 554  
          * <pre>
 555  
          * <code>
 556  
          * import static {@link Sort#asc(String) com.allanbank.mongodb.builder.Sort.asc};
 557  
          * import static {@link Sort#desc(String) com.allanbank.mongodb.builder.Sort.desc};
 558  
          * 
 559  
          * FindAndModify.Builder builder = new Find.Builder();
 560  
          * 
 561  
          * builder.sort( asc("f"), desc("g") );
 562  
          * ...
 563  
          * </code>
 564  
          * </pre>
 565  
          * 
 566  
          * </blockquote>
 567  
          * 
 568  
          * @param sortFields
 569  
          *            The sort to apply if multiple docs match, choose the first
 570  
          *            one as the object to manipulate.
 571  
          * @return This builder for chaining method calls.
 572  
          */
 573  
         public Builder sort(final IntegerElement... sortFields) {
 574  1
             return setSort(sortFields);
 575  
         }
 576  
 
 577  
         /**
 578  
          * Sets the updates to be applied to the document.
 579  
          * <p>
 580  
          * This method delegates to {@link #setUpdate(DocumentAssignable)}.
 581  
          * </p>
 582  
          * 
 583  
          * @param update
 584  
          *            The updates to be applied to the document.
 585  
          * @return This builder for chaining method calls.
 586  
          */
 587  
         public Builder update(final DocumentAssignable update) {
 588  2
             return setUpdate(update);
 589  
         }
 590  
 
 591  
         /**
 592  
          * Sets to true to create the document if it doesn't exist.
 593  
          * <p>
 594  
          * This method delegates to {@link #setUpsert(boolean) setUpsert(true)}.
 595  
          * </p>
 596  
          * 
 597  
          * @return This builder for chaining method calls.
 598  
          */
 599  
         public Builder upsert() {
 600  1
             return setUpsert(true);
 601  
         }
 602  
 
 603  
         /**
 604  
          * Sets to true to create the document if it doesn't exist.
 605  
          * <p>
 606  
          * This method delegates to {@link #setUpsert(boolean)}.
 607  
          * </p>
 608  
          * 
 609  
          * @param upsert
 610  
          *            True to create the document if it doesn't exist.
 611  
          * @return This builder for chaining method calls.
 612  
          */
 613  
         public Builder upsert(final boolean upsert) {
 614  1
             return setUpsert(upsert);
 615  
         }
 616  
     }
 617  
 }