Coverage Report - com.allanbank.mongodb.builder.AggregationGeoNear
 
Classes in this File Line Coverage Branch Coverage Complexity
AggregationGeoNear
100%
39/39
100%
10/10
1.176
AggregationGeoNear$Builder
97%
43/44
50%
1/2
1.176
 
 1  
 /*
 2  
  * #%L
 3  
  * AggregationGeoNear.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.assertNotEmpty;
 24  
 import static com.allanbank.mongodb.util.Assertions.assertNotNull;
 25  
 
 26  
 import java.awt.geom.Point2D;
 27  
 
 28  
 import com.allanbank.mongodb.bson.Document;
 29  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 30  
 import com.allanbank.mongodb.bson.builder.BuilderFactory;
 31  
 import com.allanbank.mongodb.bson.builder.DocumentBuilder;
 32  
 
 33  
 /**
 34  
  * AggregationGeoNear provides the options for the {@code $geoNear} pipeline
 35  
  * stage of an aggregation.
 36  
  * 
 37  
  * @api.yes This class is part of the driver's API. Public and protected members
 38  
  *          will be deprecated for at least 1 non-bugfix release (version
 39  
  *          numbers are <major>.<minor>.<bugfix>) before being
 40  
  *          removed or modified.
 41  
  * @copyright 2013, Allanbank Consulting, Inc., All Rights Reserved
 42  
  * 
 43  
  * @since MongoDB 2.4
 44  
  */
 45  
 public class AggregationGeoNear implements DocumentAssignable {
 46  
 
 47  
     /**
 48  
      * Creates a new builder for an {@link AggregationGeoNear}.
 49  
      * 
 50  
      * @return The builder to construct an {@link AggregationGeoNear}.
 51  
      */
 52  
     public static Builder builder() {
 53  7
         return new Builder();
 54  
     }
 55  
 
 56  
     /**
 57  
      * The name of the field to place the distance from the source
 58  
      * {@link #getLocation() location}.
 59  
      */
 60  
     private final String myDistanceField;
 61  
 
 62  
     /**
 63  
      * The distance multiplier to use in the {@code $geoNear}, if set.
 64  
      * <code>null</code> otherwise.
 65  
      */
 66  
     private final Double myDistanceMultiplier;
 67  
 
 68  
     /**
 69  
      * The maximum number of documents to return, if set. <code>null</code>
 70  
      * otherwise.
 71  
      */
 72  
     private final Long myLimit;
 73  
 
 74  
     /** The location to find documents near. */
 75  
     private final Point2D myLocation;
 76  
 
 77  
     /**
 78  
      * The name of the field to place the location information from the
 79  
      * document, if set. <code>null</code> otherwise.
 80  
      */
 81  
     private final String myLocationField;
 82  
 
 83  
     /**
 84  
      * The maximum distance to return documents from the specified location, if
 85  
      * set. <code>null</code> otherwise.
 86  
      */
 87  
     private final Double myMaxDistance;
 88  
 
 89  
     /**
 90  
      * The optional query for further refining the documents to add to the
 91  
      * pipeline.
 92  
      */
 93  
     private final Document myQuery;
 94  
 
 95  
     /**
 96  
      * If true the {@code $geoNear} should compute distances using spherical
 97  
      * coordinates instead of planar coordinates. Defaults to false.
 98  
      */
 99  
     private final boolean mySpherical;
 100  
 
 101  
     /**
 102  
      * If true the {@code $geoNear} should only return documents once. Defaults
 103  
      * to true.
 104  
      */
 105  
     private final boolean myUniqueDocs;
 106  
 
 107  
     /**
 108  
      * Creates a new AggregationGeoNear.
 109  
      * 
 110  
      * @param builder
 111  
      *            he builder for the AggregationGeoNear stage.
 112  
      * @throws IllegalArgumentException
 113  
      *             If the {@link #getLocation() location} or
 114  
      *             {@link #getDistanceField() distance field} have not been set.
 115  
      */
 116  
     protected AggregationGeoNear(final Builder builder)
 117  9
             throws IllegalArgumentException {
 118  
 
 119  9
         assertNotNull(builder.myLocation, "You must specify a location for "
 120  
                 + "a geoNear in an aggregation pipeline.");
 121  7
         assertNotEmpty(builder.myDistanceField,
 122  
                 "You must specify a distance field locations for "
 123  
                         + "a geoNear in an aggregation pipeline.");
 124  
 
 125  6
         myDistanceField = builder.myDistanceField;
 126  6
         myDistanceMultiplier = builder.myDistanceMultiplier;
 127  6
         myLocationField = builder.myLocationField;
 128  6
         myLimit = builder.myLimit;
 129  6
         myLocation = builder.myLocation;
 130  6
         myMaxDistance = builder.myMaxDistance;
 131  6
         myQuery = builder.myQuery;
 132  6
         mySpherical = builder.mySpherical;
 133  6
         myUniqueDocs = builder.myUniqueDocs;
 134  6
     }
 135  
 
 136  
     /**
 137  
      * {@inheritDoc}
 138  
      * <p>
 139  
      * Overridden to return the $geoNear aggregation pipeline's options
 140  
      * document. This does not include the $geoNear operator, just the options
 141  
      * document.
 142  
      * </p>
 143  
      */
 144  
     @Override
 145  
     public Document asDocument() {
 146  4
         final DocumentBuilder builder = BuilderFactory.start();
 147  
 
 148  4
         GeoJson.addRaw(builder.pushArray("near"), myLocation);
 149  4
         builder.add("distanceField", myDistanceField);
 150  4
         builder.add("spherical", mySpherical);
 151  4
         builder.add("uniqueDocs", myUniqueDocs);
 152  
 
 153  4
         if (myLimit != null) {
 154  3
             builder.add("limit", myLimit.longValue());
 155  
         }
 156  4
         if (myMaxDistance != null) {
 157  3
             builder.add("maxDistance", myMaxDistance);
 158  
         }
 159  4
         if (myQuery != null) {
 160  3
             builder.add("query", myQuery);
 161  
         }
 162  4
         if (myDistanceMultiplier != null) {
 163  3
             builder.add("distanceMultiplier",
 164  
                     myDistanceMultiplier.doubleValue());
 165  
         }
 166  4
         if (myLocationField != null) {
 167  3
             builder.add("includeLocs", myLocationField);
 168  
         }
 169  
 
 170  4
         return builder.build();
 171  
     }
 172  
 
 173  
     /**
 174  
      * Returns the name of the field to place the distance from the source
 175  
      * {@link #getLocation() location}.
 176  
      * 
 177  
      * @return The name of the field to place the distance from the source
 178  
      *         {@link #getLocation() location}.
 179  
      */
 180  
     public String getDistanceField() {
 181  5
         return myDistanceField;
 182  
     }
 183  
 
 184  
     /**
 185  
      * If set returns the distance multiplier to use in the {@code $geoNear}.
 186  
      * 
 187  
      * @return The distance multiplier to use in the {@code $geoNear}, if set.
 188  
      *         <code>null</code> otherwise.
 189  
      */
 190  
     public Double getDistanceMultiplier() {
 191  5
         return myDistanceMultiplier;
 192  
     }
 193  
 
 194  
     /**
 195  
      * If set returns the maximum number of documents to return.
 196  
      * 
 197  
      * @return The maximum number of documents to return, if set.
 198  
      *         <code>null</code> otherwise.
 199  
      */
 200  
     public Long getLimit() {
 201  5
         return myLimit;
 202  
     }
 203  
 
 204  
     /**
 205  
      * Returns the location to find documents near.
 206  
      * 
 207  
      * @return The location to find documents near.
 208  
      */
 209  
     public Point2D getLocation() {
 210  5
         return myLocation;
 211  
     }
 212  
 
 213  
     /**
 214  
      * If set returns the name of the field to place the location information
 215  
      * from the document.
 216  
      * 
 217  
      * @return The name of the field to place the location information from the
 218  
      *         document, if set. <code>null</code> otherwise.
 219  
      */
 220  
     public String getLocationField() {
 221  5
         return myLocationField;
 222  
     }
 223  
 
 224  
     /**
 225  
      * If set returns the maximum distance to return documents from the
 226  
      * specified location
 227  
      * 
 228  
      * @return The maximum distance to return documents from the specified
 229  
      *         location, if set. <code>null</code> otherwise.
 230  
      */
 231  
     public Double getMaxDistance() {
 232  5
         return myMaxDistance;
 233  
     }
 234  
 
 235  
     /**
 236  
      * If set returns the optional query for further refining the documents to
 237  
      * add to the pipeline.
 238  
      * 
 239  
      * @return The optional query for further refining the documents to add to
 240  
      *         the pipeline, if set. <code>null</code> otherwise.
 241  
      */
 242  
     public Document getQuery() {
 243  5
         return myQuery;
 244  
     }
 245  
 
 246  
     /**
 247  
      * Returns true if the {@code $geoNear} should compute distances using
 248  
      * spherical coordinates instead of planar coordinates. Defaults to false.
 249  
      * 
 250  
      * @return True if the {@code $geoNear} should compute distances using
 251  
      *         spherical coordinates instead of planar coordinates.
 252  
      */
 253  
     public boolean isSpherical() {
 254  5
         return mySpherical;
 255  
     }
 256  
 
 257  
     /**
 258  
      * Returns true if the {@code $geoNear} should only return documents once.
 259  
      * Defaults to true.
 260  
      * 
 261  
      * @return True if the {@code $geoNear} should only return documents once.
 262  
      */
 263  
     public boolean isUniqueDocs() {
 264  5
         return myUniqueDocs;
 265  
     }
 266  
 
 267  
     /**
 268  
      * Helper for creating immutable {@link Find} queries.
 269  
      * 
 270  
      * @api.yes This class is part of the driver's API. Public and protected
 271  
      *          members will be deprecated for at least 1 non-bugfix release
 272  
      *          (version numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;)
 273  
      *          before being removed or modified.
 274  
      * @copyright 2013, Allanbank Consulting, Inc., All Rights Reserved
 275  
      */
 276  
     public static class Builder {
 277  
         /**
 278  
          * The name of the field to place the distance from the source
 279  
          * {@link #getLocation() location}.
 280  
          */
 281  
         protected String myDistanceField;
 282  
 
 283  
         /**
 284  
          * The distance multiplier to use in the {@code $geoNear}, if set.
 285  
          * <code>null</code> otherwise.
 286  
          */
 287  
         protected Double myDistanceMultiplier;
 288  
 
 289  
         /**
 290  
          * The maximum number of documents to return, if set. <code>null</code>
 291  
          * otherwise.
 292  
          */
 293  
         protected Long myLimit;
 294  
 
 295  
         /** The location to find documents near. */
 296  
         protected Point2D myLocation;
 297  
 
 298  
         /**
 299  
          * The name of the field to place the location information from the
 300  
          * document, if set. <code>null</code> otherwise.
 301  
          */
 302  
         protected String myLocationField;
 303  
 
 304  
         /**
 305  
          * The maximum distance to return documents from the specified location,
 306  
          * if set. <code>null</code> otherwise.
 307  
          */
 308  
         protected Double myMaxDistance;
 309  
 
 310  
         /**
 311  
          * The optional query for further refining the documents to add to the
 312  
          * pipeline.
 313  
          */
 314  
         protected Document myQuery;
 315  
 
 316  
         /**
 317  
          * If true the {@code $geoNear} should compute distances using spherical
 318  
          * coordinates instead of planar coordinates. Defaults to false.
 319  
          */
 320  
         protected boolean mySpherical;
 321  
 
 322  
         /**
 323  
          * If true the {@code $geoNear} should only return documents once.
 324  
          * Defaults to true.
 325  
          */
 326  
         protected boolean myUniqueDocs;
 327  
 
 328  
         /**
 329  
          * Creates a new Builder.
 330  
          */
 331  7
         public Builder() {
 332  7
             reset();
 333  7
         }
 334  
 
 335  
         /**
 336  
          * Constructs a new {@link AggregationGeoNear} object from the state of
 337  
          * the builder.
 338  
          * 
 339  
          * @return The new {@link AggregationGeoNear} object.
 340  
          * @throws IllegalArgumentException
 341  
          *             If the {@link #setLocation(Point2D) location} or
 342  
          *             {@link #setDistanceField(String) distance field} have not
 343  
          *             been set.
 344  
          */
 345  
         public AggregationGeoNear build() {
 346  9
             return new AggregationGeoNear(this);
 347  
         }
 348  
 
 349  
         /**
 350  
          * Sets the name of the field to place the distance from the source
 351  
          * {@link #getLocation() location}.
 352  
          * <p>
 353  
          * This method delegates to {@link #setDistanceField(String)}.
 354  
          * </p>
 355  
          * 
 356  
          * @param distanceField
 357  
          *            The new name of the field to place the distance from the
 358  
          *            source {@link #setLocation(Point2D) location}.
 359  
          * @return This builder for chaining method calls.
 360  
          */
 361  
         public Builder distanceField(final String distanceField) {
 362  8
             return setDistanceField(distanceField);
 363  
         }
 364  
 
 365  
         /**
 366  
          * Sets the distance multiplier to use in the {@code $geoNear}.
 367  
          * <p>
 368  
          * This method delegates to {@link #setDistanceMultiplier(double)}.
 369  
          * </p>
 370  
          * 
 371  
          * @param distanceMultiplier
 372  
          *            The new distance multiplier to use in the {@code $geoNear}
 373  
          *            .
 374  
          * @return This builder for chaining method calls.
 375  
          */
 376  
         public Builder distanceMultiplier(final double distanceMultiplier) {
 377  4
             return setDistanceMultiplier(distanceMultiplier);
 378  
         }
 379  
 
 380  
         /**
 381  
          * Sets the maximum number of documents to return.
 382  
          * <p>
 383  
          * This method delegates to {@link #setLimit(long)}.
 384  
          * </p>
 385  
          * 
 386  
          * @param limit
 387  
          *            The new maximum number of documents to return.
 388  
          * @return This builder for chaining method calls.
 389  
          */
 390  
         public Builder limit(final long limit) {
 391  4
             return setLimit(limit);
 392  
         }
 393  
 
 394  
         /**
 395  
          * Sets the location to find documents near.
 396  
          * <p>
 397  
          * This method delegates to {@link #setLocation(Point2D)}.
 398  
          * </p>
 399  
          * 
 400  
          * @param location
 401  
          *            The new location to find documents near.
 402  
          * @return This builder for chaining method calls.
 403  
          * @see GeoJson#p
 404  
          */
 405  
         public Builder location(final Point2D location) {
 406  8
             return setLocation(location);
 407  
         }
 408  
 
 409  
         /**
 410  
          * Sets the name of the field to place the location information from the
 411  
          * document.
 412  
          * <p>
 413  
          * This method delegates to {@link #setLocationField(String)}.
 414  
          * </p>
 415  
          * 
 416  
          * @param locationField
 417  
          *            The new name of the field to place the location
 418  
          *            information from the document.
 419  
          * @return This builder for chaining method calls.
 420  
          */
 421  
         public Builder locationField(final String locationField) {
 422  4
             return setLocationField(locationField);
 423  
         }
 424  
 
 425  
         /**
 426  
          * Sets the maximum distance to return documents from the specified
 427  
          * location.
 428  
          * <p>
 429  
          * This method delegates to {@link #setMaxDistance(double)}.
 430  
          * </p>
 431  
          * 
 432  
          * @param maxDistance
 433  
          *            The new maximum distance to return documents from the
 434  
          *            specified location.
 435  
          * @return This builder for chaining method calls.
 436  
          */
 437  
         public Builder maxDistance(final double maxDistance) {
 438  4
             return setMaxDistance(maxDistance);
 439  
         }
 440  
 
 441  
         /**
 442  
          * Sets the optional query for further refining the documents to add to
 443  
          * the pipeline.
 444  
          * <p>
 445  
          * This method delegates to {@link #setQuery(DocumentAssignable)}.
 446  
          * </p>
 447  
          * 
 448  
          * @param query
 449  
          *            The new optional query for further refining the documents
 450  
          *            to add to the pipeline.
 451  
          * @return This builder for chaining method calls.
 452  
          */
 453  
         public Builder query(final DocumentAssignable query) {
 454  4
             return setQuery(query);
 455  
         }
 456  
 
 457  
         /**
 458  
          * Resets the builder back to its initial state for reuse.
 459  
          * 
 460  
          * @return This builder for chaining method calls.
 461  
          */
 462  
         public Builder reset() {
 463  8
             myDistanceField = null;
 464  8
             myDistanceMultiplier = null;
 465  8
             myLimit = null;
 466  8
             myLocation = null;
 467  8
             myLocationField = null;
 468  8
             myMaxDistance = null;
 469  8
             myQuery = null;
 470  8
             mySpherical = false;
 471  8
             myUniqueDocs = true;
 472  8
             return this;
 473  
         }
 474  
 
 475  
         /**
 476  
          * Sets the name of the field to place the distance from the source
 477  
          * {@link #getLocation() location}.
 478  
          * 
 479  
          * @param distanceField
 480  
          *            The new name of the field to place the distance from the
 481  
          *            source {@link #setLocation(Point2D) location}.
 482  
          * @return This builder for chaining method calls.
 483  
          */
 484  
         public Builder setDistanceField(final String distanceField) {
 485  8
             myDistanceField = distanceField;
 486  8
             return this;
 487  
         }
 488  
 
 489  
         /**
 490  
          * Sets the distance multiplier to use in the {@code $geoNear}.
 491  
          * 
 492  
          * @param distanceMultiplier
 493  
          *            The new distance multiplier to use in the {@code $geoNear}
 494  
          *            .
 495  
          * @return This builder for chaining method calls.
 496  
          */
 497  
         public Builder setDistanceMultiplier(final double distanceMultiplier) {
 498  4
             myDistanceMultiplier = Double.valueOf(distanceMultiplier);
 499  4
             return this;
 500  
         }
 501  
 
 502  
         /**
 503  
          * Sets the maximum number of documents to return.
 504  
          * 
 505  
          * @param limit
 506  
          *            The new maximum number of documents to return.
 507  
          * @return This builder for chaining method calls.
 508  
          */
 509  
         public Builder setLimit(final long limit) {
 510  4
             myLimit = Long.valueOf(limit);
 511  4
             return this;
 512  
         }
 513  
 
 514  
         /**
 515  
          * Sets the location to find documents near.
 516  
          * 
 517  
          * @param location
 518  
          *            The new location to find documents near.
 519  
          * @return This builder for chaining method calls.
 520  
          * @see GeoJson#p
 521  
          */
 522  
         public Builder setLocation(final Point2D location) {
 523  8
             myLocation = location;
 524  8
             return this;
 525  
         }
 526  
 
 527  
         /**
 528  
          * Sets the name of the field to place the location information from the
 529  
          * document.
 530  
          * 
 531  
          * @param locationField
 532  
          *            The new name of the field to place the location
 533  
          *            information from the document.
 534  
          * @return This builder for chaining method calls.
 535  
          */
 536  
         public Builder setLocationField(final String locationField) {
 537  4
             myLocationField = locationField;
 538  4
             return this;
 539  
         }
 540  
 
 541  
         /**
 542  
          * Sets the maximum distance to return documents from the specified
 543  
          * location.
 544  
          * 
 545  
          * @param maxDistance
 546  
          *            The new maximum distance to return documents from the
 547  
          *            specified location.
 548  
          * @return This builder for chaining method calls.
 549  
          */
 550  
         public Builder setMaxDistance(final double maxDistance) {
 551  4
             myMaxDistance = Double.valueOf(maxDistance);
 552  4
             return this;
 553  
         }
 554  
 
 555  
         /**
 556  
          * Sets the optional query for further refining the documents to add to
 557  
          * the pipeline.
 558  
          * 
 559  
          * @param query
 560  
          *            The new optional query for further refining the documents
 561  
          *            to add to the pipeline.
 562  
          * @return This builder for chaining method calls.
 563  
          */
 564  
         public Builder setQuery(final DocumentAssignable query) {
 565  4
             if (query != null) {
 566  4
                 myQuery = query.asDocument();
 567  
             }
 568  
             else {
 569  0
                 myQuery = null;
 570  
             }
 571  4
             return this;
 572  
         }
 573  
 
 574  
         /**
 575  
          * Sets if (true) the {@code $geoNear} should compute distances using
 576  
          * spherical coordinates instead of planar coordinates. Defaults to
 577  
          * false.
 578  
          * 
 579  
          * @param spherical
 580  
          *            The new value for if the {@code $geoNear} should compute
 581  
          *            distances using spherical coordinates instead of planar
 582  
          *            coordinates
 583  
          * @return This builder for chaining method calls.
 584  
          */
 585  
         public Builder setSpherical(final boolean spherical) {
 586  4
             mySpherical = spherical;
 587  4
             return this;
 588  
         }
 589  
 
 590  
         /**
 591  
          * Sets if (true) the {@code $geoNear} should only return documents
 592  
          * once. Defaults to true.
 593  
          * 
 594  
          * @param uniqueDocs
 595  
          *            The new value for if the {@code $geoNear} should only
 596  
          *            return documents once.
 597  
          * @return This builder for chaining method calls.
 598  
          */
 599  
         public Builder setUniqueDocs(final boolean uniqueDocs) {
 600  4
             myUniqueDocs = uniqueDocs;
 601  4
             return this;
 602  
         }
 603  
 
 604  
         /**
 605  
          * Sets the {@code $geoNear} to compute distances using spherical
 606  
          * coordinates instead of planar coordinates.
 607  
          * <p>
 608  
          * This method delegates to {@link #setSpherical(boolean)
 609  
          * setSpherical(true)}.
 610  
          * </p>
 611  
          * 
 612  
          * 
 613  
          * @return This builder for chaining method calls.
 614  
          */
 615  
         public Builder spherical() {
 616  2
             return setSpherical(true);
 617  
         }
 618  
 
 619  
         /**
 620  
          * Sets if (true) the {@code $geoNear} should compute distances using
 621  
          * spherical coordinates instead of planar coordinates. Defaults to
 622  
          * false.
 623  
          * <p>
 624  
          * This method delegates to {@link #setSpherical(boolean)}.
 625  
          * </p>
 626  
          * 
 627  
          * @param spherical
 628  
          *            The new value for if the {@code $geoNear} should compute
 629  
          *            distances using spherical coordinates instead of planar
 630  
          *            coordinates
 631  
          * @return This builder for chaining method calls.
 632  
          */
 633  
         public Builder spherical(final boolean spherical) {
 634  2
             return setSpherical(spherical);
 635  
         }
 636  
 
 637  
         /**
 638  
          * Sets if (true) the {@code $geoNear} should only return documents
 639  
          * once. Defaults to true.
 640  
          * <p>
 641  
          * This method delegates to {@link #setUniqueDocs(boolean)}.
 642  
          * </p>
 643  
          * 
 644  
          * @param uniqueDocs
 645  
          *            The new value for if the {@code $geoNear} should only
 646  
          *            return documents once.
 647  
          * @return This builder for chaining method calls.
 648  
          */
 649  
         public Builder uniqueDocs(final boolean uniqueDocs) {
 650  4
             return setUniqueDocs(uniqueDocs);
 651  
         }
 652  
     }
 653  
 }