From d81c4f2ebd1182ca103556a2c203882be48b9e5f Mon Sep 17 00:00:00 2001 From: LongHua Huang Date: Sat, 28 Mar 2015 11:28:44 +0800 Subject: [PATCH 0001/1665] Update the default chunk size in comment Update the comment to make it consistent with the code. --- driver/src/main/com/mongodb/gridfs/GridFS.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/driver/src/main/com/mongodb/gridfs/GridFS.java b/driver/src/main/com/mongodb/gridfs/GridFS.java index e4fa2748205..1572a3842fb 100644 --- a/driver/src/main/com/mongodb/gridfs/GridFS.java +++ b/driver/src/main/com/mongodb/gridfs/GridFS.java @@ -37,7 +37,7 @@ *

Implementation of GridFS - a specification for storing and retrieving files that exceed the BSON-document size limit of 16MB.

* *

Instead of storing a file in a single document, GridFS divides a file into parts, or chunks, and stores each of those chunks as a - * separate document. By default GridFS limits chunk size to 256k. GridFS uses two collections to store files. One collection stores the + * separate document. By default GridFS limits chunk size to 255k. GridFS uses two collections to store files. One collection stores the * file chunks, and the other stores file metadata.

* *

When you query a GridFS store for a file, the driver or client will reassemble the chunks as needed. You can perform range queries on From 83cff7afa07442591a06b51c873b42a914d810f0 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 31 Mar 2015 16:52:37 -0400 Subject: [PATCH 0002/1665] Updating version to 3.1.0-SNAPSHOT --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 934bbe2a44e..6a5be5c148c 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ configure(subprojects.findAll { it.name != 'util' }) { evaluationDependsOn(':util') group = 'org.mongodb' - version = '3.0.0' + version = '3.1.0-SNAPSHOT' sourceCompatibility = JavaVersion.VERSION_1_6 targetCompatibility = JavaVersion.VERSION_1_6 From 96034756e8ee438d8ef2d7e2054fdbf4afbdaf30 Mon Sep 17 00:00:00 2001 From: Xavier Coulon Date: Wed, 1 Apr 2015 14:20:33 +0200 Subject: [PATCH 0003/1665] Update codecs.md Fix typo --- docs/reference/content/bson/codecs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/content/bson/codecs.md b/docs/reference/content/bson/codecs.md index 3ed8933f61b..587cfaae50f 100644 --- a/docs/reference/content/bson/codecs.md +++ b/docs/reference/content/bson/codecs.md @@ -98,7 +98,7 @@ The `DocumentCodec`, because it is constructed with a `CodecRegistry`, can now u values contained in each Document that it encodes. One more problem remains, however. Consider the problem of encoding values to a BSON DateTime. An application may want to -encode to a BSON DateTime instances of both the original Java `Date` class as well as the Java 8 `Instance` class. It's easy to create +encode to a BSON DateTime instances of both the original Java `Date` class as well as the Java 8 `Instant` class. It's easy to create implemenations of `Codec` and `Codec`, and either one can be used for encoding. But when decoding, a Document `Codec` also has to choose which Java type to decode a BSON DateTime to. Rather than hard-coding it in the `DocumentCodec`, the decision is abstracted via the `BsonTypeClassMap` class. From 13ff30f64694c1adf6046e9c2bd8c98f84cf5624 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 1 Apr 2015 19:33:03 +0100 Subject: [PATCH 0004/1665] Fix intellij 14.1 import gradle project Have to apply the idea plugin explicitly in the local build --- mongo-java-driver/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/mongo-java-driver/build.gradle b/mongo-java-driver/build.gradle index 6dda49f5902..da8bafb87cd 100644 --- a/mongo-java-driver/build.gradle +++ b/mongo-java-driver/build.gradle @@ -16,6 +16,7 @@ def configDir = new File(rootDir, 'config') +apply plugin: 'idea' apply plugin: 'osgi' archivesBaseName = 'mongo-java-driver' From 5cb1a27256bfc868b30396a95d7a19d588f6f2e8 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Thu, 2 Apr 2015 11:49:25 +0100 Subject: [PATCH 0005/1665] Fix async src doc links --- .../content/driver-async/getting-started/quick-tour.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/reference/content/driver-async/getting-started/quick-tour.md b/docs/reference/content/driver-async/getting-started/quick-tour.md index 36d22e8fdff..0a70a036408 100644 --- a/docs/reference/content/driver-async/getting-started/quick-tour.md +++ b/docs/reference/content/driver-async/getting-started/quick-tour.md @@ -86,7 +86,7 @@ cluster and use it across your application. When creating multiple instances: ## Get a Collection To get a collection to operate upon, specify the name of the collection to -the [`getCollection(String collectionName)`]({{< apiref "com/mongodb/client/MongoDatabase.html#getCollection-java.lang.String-">}}) +the [`getCollection(String collectionName)`]({{< apiref "com/mongodb/async/client/MongoDatabase.html#getCollection-java.lang.String-">}}) method: The following example gets the collection `test`: @@ -181,7 +181,7 @@ collection.insertMany(documents, new SingleResultCallback() { Now that we've inserted 101 documents (the 100 we did in the loop, plus the first one), we can check to see if we have them all using the -[count()]({{< apiref "com/mongodb/client/MongoCollection#count--">}}) +[count()]({{< apiref "com/mongodb/async/client/MongoCollection#count--">}}) method. The following code should print `101`. ```java @@ -197,7 +197,7 @@ collection.count( ## Query the Collection Use the -[find()]({{< apiref "com/mongodb/client/MongoCollection.html#find--">}}) +[find()]({{< apiref "com/mongodb/async/client/MongoCollection.html#find--">}}) method to query the collection. ### Find the First Document in a Collection @@ -205,8 +205,8 @@ method to query the collection. call the first() method on the result of the find() of method To get the first document in the collection, call the -[first()]({{< apiref "com/mongodb/client/MongoIterable.html#first--">}}) -method on the [find()]({{< apiref "com/mongodb/client/MongoCollection.html#find--">}}) +[first()]({{< apiref "com/mongodb/async/client/MongoIterable.html#first--">}}) +method on the [find()]({{< apiref "com/mongodb/async/client/MongoCollection.html#find--">}}) operation. `collection.find().first()` returns the first document or null rather than a cursor. This is useful for queries that should only match a single document, or if you are interested in the first document only. From 8e028711c3cb7b2ff3ad8363dafc27e6de869c4c Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 1 Apr 2015 17:11:04 -0400 Subject: [PATCH 0006/1665] Added functional test specifications for Filters, Projections, and Sorts --- .../FiltersFunctionalSpecification.groovy | 210 ++++++++++++++++++ .../ProjectionFunctionalSpecification.groovy | 117 ++++++++++ .../model/SortsFunctionalSpecification.groovy | 76 +++++++ .../mongodb/client/test/CollectionHelper.java | 37 ++- 4 files changed, 437 insertions(+), 3 deletions(-) create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy diff --git a/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy new file mode 100644 index 00000000000..25c3c534509 --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy @@ -0,0 +1,210 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONObjectITIONS OF ANY KINObject, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.OperationFunctionalSpecification +import org.bson.BsonType +import org.bson.Document +import org.bson.conversions.Bson + +import java.util.regex.Pattern + +import static com.mongodb.client.model.Filters.all +import static com.mongodb.client.model.Filters.and +import static com.mongodb.client.model.Filters.elemMatch +import static com.mongodb.client.model.Filters.eq +import static com.mongodb.client.model.Filters.exists +import static com.mongodb.client.model.Filters.gt +import static com.mongodb.client.model.Filters.gte +import static com.mongodb.client.model.Filters.lt +import static com.mongodb.client.model.Filters.lte +import static com.mongodb.client.model.Filters.mod +import static com.mongodb.client.model.Filters.ne +import static com.mongodb.client.model.Filters.nin +import static com.mongodb.client.model.Filters.nor +import static com.mongodb.client.model.Filters.not +import static com.mongodb.client.model.Filters.or +import static com.mongodb.client.model.Filters.regex +import static com.mongodb.client.model.Filters.size +import static com.mongodb.client.model.Filters.text +import static com.mongodb.client.model.Filters.type +import static com.mongodb.client.model.Filters.where + +class FiltersFunctionalSpecification extends OperationFunctionalSpecification { + def a = new Document('_id', 1).append('x', 1) + .append('y', 'a') + .append('a', [1, 2, 3]) + .append('a1', [new Document('c', 1).append('d', 2), new Document('c', 2).append('d', 3)]) + + def b = new Document('_id', 2).append('x', 2) + .append('y', 'b') + .append('a', [3, 4, 5, 6]) + .append('a1', [new Document('c', 2).append('d', 3), new Document('c', 3).append('d', 4)]) + + def c = new Document('_id', 3).append('x', 3) + .append('y', 'c') + .append('z', true) + + def setup() { + getCollectionHelper().insertDocuments(a, b, c) + getCollectionHelper().createIndex(new Document('y', 'text')) + } + + def 'find'(Bson filter) { + getCollectionHelper().find(filter, new Document('_id', 1)) // sort by _id + } + + def 'eq'() { + expect: + find(eq('x', 1)) == [a] + } + + def '$ne'() { + expect: + find(ne('x', 1)) == [b, c] + } + + def '$not'() { + expect: + find(not(eq('x', 1))) == [b, c] + find(not(gt('x', 1))) == [a] + find(not(regex('y', 'a.*'))) == [b, c] + find(not(and(eq('x', 1), eq('x', 1)))) == [b, c] + find(not(and(Filters.in('a', 1, 2), eq('x', 1)))) == [b, c] + find(not(and(eq('x', 1), eq('y', 'a')))) == [b, c] + // find(not(and(eq('x', 1), eq('y', 'b')))) == [a, b, c] // should pass, but see JAVA-1740 + } + + def '$nor'() { + expect: + find(nor(eq('x', 1))) == [b, c] + find(nor(eq('x', 1), eq('x', 2))) == [c] + find(nor(and(eq('x', 1), eq('y', 'b')))) == [a, b, c] + } + + def '$gt'() { + expect: + find(gt('x', 1)) == [b, c] + } + + def '$lt'() { + expect: + find(lt('x', 3)) == [a, b] + } + + def '$gte'() { + expect: + find(gte('x', 2)) == [b, c] + } + + def '$lte'() { + expect: + find(lte('x', 2)) == [a, b] + } + + def '$exists'() { + expect: + find(exists('z')) == [c] + find(exists('z', false)) == [a, b] + } + + def '$or'() { + expect: + find(or([eq('x', 1)])) == [a] + find(or([eq('x', 1), eq('y', 'b')])) == [a, b] + } + + def 'and'() { + expect: + find(and([eq('x', 1)])) == [a] + find(and([eq('x', 1), eq('y', 'a')])) == [a] + } + + def 'and should duplicate clashing keys'() { + expect: + find(and([eq('x', 1), eq('x', 1)])) == [a] + } + + def 'and should flatten multiple operators for the same key'() { + expect: + find(and([gte('x', 1), lte('x', 2)])) == [a, b] + } + + def 'and should flatten nested'() { + expect: + find(and([and([eq('x', 3), eq('y', 'c')]), eq('z', true)])) == [c] + find(and([and([eq('x', 3), eq('x', 3)]), eq('z', true)])) == [c] + find(and([gt('x', 1), gt('y', 'a')])) == [b, c] + find(and([lt('x', 4), lt('x', 3)])) == [a, b] + } + + def 'should render $all'() { + expect: + find(all('a', [1, 2])) == [a] + } + + def 'should render $elemMatch'() { + expect: + find(elemMatch('a', new Document('$gte', 2).append('$lte', 2))) == [a] + find(elemMatch('a1', and(eq('c', 1), gte('d', 2)))) == [a] + find(elemMatch('a1', and(eq('c', 2), eq('d', 3)))) == [a, b] + } + + def 'should render $in'() { + expect: + find(Filters.in('a', [0, 1, 2])) == [a] + } + + def 'should render $nin'() { + expect: + find(nin('a', [1, 2])) == [b, c] + } + + def 'should render $mod'() { + expect: + find(mod('x', 2, 0)) == [b] + } + + def 'should render $size'() { + expect: + find(size('a', 4)) == [b] + } + + def 'should render $type'() { + expect: + find(type('x', BsonType.INT32)) == [a, b, c] + find(type('x', BsonType.ARRAY)) == [] + } + + def 'should render $text'() { + expect: + find(text('I love MongoDB')) == [] + find(text('I love MongoDB', 'English')) == [] + } + + def 'should render $regex'() { + expect: + find(regex('y', 'a.*')) == [a] + find(regex('y', 'a.*', 'si')) == [a] + find(regex('y', Pattern.compile('a.*'))) == [a] + } + + def 'should render $where'() { + expect: + find(where('Array.isArray(this.a)')) == [a, b] + } +} diff --git a/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy new file mode 100644 index 00000000000..7b53818c2f4 --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy @@ -0,0 +1,117 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONObjectITIONS OF ANY KINObject, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.MongoQueryException +import com.mongodb.OperationFunctionalSpecification +import org.bson.Document +import org.bson.conversions.Bson + +import static com.mongodb.client.model.Filters.and +import static com.mongodb.client.model.Filters.eq +import static com.mongodb.client.model.Projections.elemMatch +import static com.mongodb.client.model.Projections.exclude +import static com.mongodb.client.model.Projections.excludeId +import static com.mongodb.client.model.Projections.fields +import static com.mongodb.client.model.Projections.include +import static com.mongodb.client.model.Projections.metaTextScore +import static com.mongodb.client.model.Projections.slice + +class ProjectionFunctionalSpecification extends OperationFunctionalSpecification { + def a = new Document('_id', 1).append('x', 1).append('y', [new Document('a', 1).append('b', 2), + new Document('a', 2).append('b', 3), + new Document('a', 3).append('b', 4)]) + def aYSlice1 = new Document('_id', 1).append('x', 1).append('y', [new Document('a', 1).append('b', 2)]) + def aYSlice12 = new Document('_id', 1).append('x', 1).append('y', [new Document('a', 2).append('b', 3), + new Document('a', 3).append('b', 4)]) + def aNoY = new Document('_id', 1).append('x', 1) + def aId = new Document('_id', 1) + def aNoId = new Document().append('x', 1).append('y', [new Document('a', 1).append('b', 2), + new Document('a', 2).append('b', 3), + new Document('a', 3).append('b', 4)]) + def aWithScore = new Document('_id', 1).append('x', 1).append('y', [new Document('a', 1).append('b', 2), + new Document('a', 2).append('b', 3), + new Document('a', 3).append('b', 4)]) + .append('score', 0.0) + + def setup() { + getCollectionHelper().insertDocuments(a) + getCollectionHelper().createIndex(new Document('y', 'text')) + } + + def 'find'(Bson projection) { + getCollectionHelper().find(new Document(), new Document('_id', 1), projection) + } + + def 'find'(Bson filter, Bson projection) { + getCollectionHelper().find(filter, new Document('_id', 1), projection) + } + + def 'include'() { + expect: + find(include('x')) == [aNoY] + find(include('x', 'y')) == [a] + find(include(['x', 'y', 'x'])) == [a] + } + + def 'exclude'() { + expect: + find(exclude('y')) == [aNoY] + find(exclude('x', 'y')) == [aId] + find(exclude(['x', 'y', 'x'])) == [aId] + } + + def 'excludeId'() { + expect: + find(excludeId()) == [aNoId] + } + + def 'firstElem'() { + expect: + find(new Document('y', new Document('$elemMatch', new Document('a', 1).append('b', 2))), + fields(include('x'), elemMatch('y'))) == [aYSlice1] + } + + def 'elemMatch'() { + expect: + find(fields(include('x'), elemMatch('y', and(eq('a', 1), eq('b', 2))))) == [aYSlice1] + } + + def 'slice'() { + expect: + find(slice('y', 1)) == [aYSlice1] + find(slice('y', 1, 2)) == [aYSlice12] + } + + def 'metaTextScore'() { + expect: + find(metaTextScore('score')) == [aWithScore] + } + + def 'combine fields'() { + expect: + find(fields(include('x', 'y'), exclude('_id'))) == [aNoId] + } + + def 'combine fields illegally'() { + when: + find(fields(include('x', 'y'), exclude('y'))) == [aNoY] + + then: + thrown(MongoQueryException) + } +} \ No newline at end of file diff --git a/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy new file mode 100644 index 00000000000..b37a111c591 --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy @@ -0,0 +1,76 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONObjectITIONS OF ANY KINObject, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.OperationFunctionalSpecification +import org.bson.Document +import org.bson.conversions.Bson + +import static com.mongodb.client.model.Sorts.ascending +import static com.mongodb.client.model.Sorts.descending +import static com.mongodb.client.model.Sorts.metaTextScore +import static com.mongodb.client.model.Sorts.orderBy + +class SortsFunctionalSpecification extends OperationFunctionalSpecification { + def a = new Document('_id', 1).append('x', 1) + .append('y', 'b') + + def b = new Document('_id', 2).append('x', 1) + .append('y', 'a') + + def c = new Document('_id', 3).append('x', 2) + .append('y', 'c') + + def setup() { + getCollectionHelper().insertDocuments(a, b, c) + getCollectionHelper().createIndex(new Document('y', 'text')) + } + + def 'find'(Bson sort) { + getCollectionHelper().find(new Document(), sort) + } + + def 'find'(Bson sort, Bson projection) { + getCollectionHelper().find(new Document(), sort, projection) + } + + def 'ascending'() { + expect: + find(ascending('_id')) == [a, b, c] + find(ascending('y')) == [b, a, c] + find(ascending('x', 'y')) == [b, a, c] + } + + def 'descending'() { + expect: + find(descending('_id')) == [c, b, a] + find(descending('y')) == [c, a, b] + find(descending('x', 'y')) == [c, a, b] + } + + def 'metaTextScore'() { + expect: + find(metaTextScore('score'), new Document('score', new Document('$meta', 'textScore')))*.containsKey('score') + } + + def 'orderBy'() { + expect: + find(orderBy([ascending('x'), descending('y')])) == [a, b, c] + find(orderBy(ascending('x'), descending('y'), descending('x'))) == [c, a, b] + } + +} \ No newline at end of file diff --git a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java index 1f3a90aa192..31b55c7239a 100644 --- a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java +++ b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java @@ -36,9 +36,15 @@ import org.bson.BsonDocument; import org.bson.BsonDocumentWrapper; import org.bson.Document; +import org.bson.codecs.BsonValueCodecProvider; import org.bson.codecs.Codec; import org.bson.codecs.Decoder; import org.bson.codecs.DocumentCodec; +import org.bson.codecs.DocumentCodecProvider; +import org.bson.codecs.ValueCodecProvider; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.conversions.Bson; import java.util.ArrayList; import java.util.List; @@ -50,6 +56,9 @@ public final class CollectionHelper { private Codec codec; + private CodecRegistry registry = CodecRegistries.fromProviders(new BsonValueCodecProvider(), + new ValueCodecProvider(), + new DocumentCodecProvider()); private MongoNamespace namespace; public CollectionHelper(final Codec codec, final MongoNamespace namespace) { @@ -142,12 +151,34 @@ public List find(final Codec codec) { return results; } - public List find(final Document filter) { - return find(new BsonDocumentWrapper(filter, new DocumentCodec()), codec); + public List find(final Bson filter) { + return find(filter, null); + } + + public List find(final Bson filter, final Bson sort) { + return find(filter != null ? filter.toBsonDocument(Document.class, registry) : null, + sort != null ? sort.toBsonDocument(Document.class, registry) : null, + codec); + } + + public List find(final Bson filter, final Bson sort, final Bson projection) { + return find(filter != null ? filter.toBsonDocument(Document.class, registry) : null, + sort != null ? sort.toBsonDocument(Document.class, registry) : null, + projection != null ? projection.toBsonDocument(Document.class, registry) : null, + codec); } public List find(final BsonDocument filter, final Decoder decoder) { - BatchCursor cursor = new FindOperation(namespace, decoder).filter(filter).execute(getBinding()); + return find(filter, null, decoder); + } + + public List find(final BsonDocument filter, final BsonDocument sort, final Decoder decoder) { + return find(filter, sort, null, decoder); + } + + public List find(final BsonDocument filter, final BsonDocument sort, final BsonDocument projection, final Decoder decoder) { + BatchCursor cursor = new FindOperation(namespace, decoder).filter(filter).sort(sort).projection(projection) + .execute(getBinding()); List results = new ArrayList(); while (cursor.hasNext()) { results.addAll(cursor.next()); From 3865fb43689678f975a8d2e5b541cdb04e890217 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 2 Apr 2015 15:42:38 -0400 Subject: [PATCH 0007/1665] Fixed functional test specifications for Filters, Projections, and Sorts to make sure they pass will all supported MongoDB configurations --- .../client/model/FiltersFunctionalSpecification.groovy | 4 ++++ .../client/model/ProjectionFunctionalSpecification.groovy | 7 +++++-- .../client/model/SortsFunctionalSpecification.groovy | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy index 25c3c534509..91d2a79cc53 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy @@ -20,9 +20,11 @@ import com.mongodb.OperationFunctionalSpecification import org.bson.BsonType import org.bson.Document import org.bson.conversions.Bson +import spock.lang.IgnoreIf import java.util.regex.Pattern +import static com.mongodb.ClusterFixture.serverVersionAtLeast import static com.mongodb.client.model.Filters.all import static com.mongodb.client.model.Filters.and import static com.mongodb.client.model.Filters.elemMatch @@ -78,6 +80,7 @@ class FiltersFunctionalSpecification extends OperationFunctionalSpecification { find(ne('x', 1)) == [b, c] } + @IgnoreIf({ !serverVersionAtLeast([2, 6, 0]) }) def '$not'() { expect: find(not(eq('x', 1))) == [b, c] @@ -190,6 +193,7 @@ class FiltersFunctionalSpecification extends OperationFunctionalSpecification { find(type('x', BsonType.ARRAY)) == [] } + @IgnoreIf({ !serverVersionAtLeast([2, 6, 0]) }) def 'should render $text'() { expect: find(text('I love MongoDB')) == [] diff --git a/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy index 7b53818c2f4..367b27043c5 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/client/model/ProjectionFunctionalSpecification.groovy @@ -20,7 +20,9 @@ import com.mongodb.MongoQueryException import com.mongodb.OperationFunctionalSpecification import org.bson.Document import org.bson.conversions.Bson +import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.serverVersionAtLeast import static com.mongodb.client.model.Filters.and import static com.mongodb.client.model.Filters.eq import static com.mongodb.client.model.Projections.elemMatch @@ -54,11 +56,11 @@ class ProjectionFunctionalSpecification extends OperationFunctionalSpecification } def 'find'(Bson projection) { - getCollectionHelper().find(new Document(), new Document('_id', 1), projection) + getCollectionHelper().find(null, null, projection) } def 'find'(Bson filter, Bson projection) { - getCollectionHelper().find(filter, new Document('_id', 1), projection) + getCollectionHelper().find(filter, null, projection) } def 'include'() { @@ -97,6 +99,7 @@ class ProjectionFunctionalSpecification extends OperationFunctionalSpecification find(slice('y', 1, 2)) == [aYSlice12] } + @IgnoreIf({ !serverVersionAtLeast([2, 6, 0]) }) def 'metaTextScore'() { expect: find(metaTextScore('score')) == [aWithScore] diff --git a/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy index b37a111c591..a850e28a365 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/client/model/SortsFunctionalSpecification.groovy @@ -19,7 +19,9 @@ package com.mongodb.client.model import com.mongodb.OperationFunctionalSpecification import org.bson.Document import org.bson.conversions.Bson +import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.serverVersionAtLeast import static com.mongodb.client.model.Sorts.ascending import static com.mongodb.client.model.Sorts.descending import static com.mongodb.client.model.Sorts.metaTextScore @@ -62,6 +64,7 @@ class SortsFunctionalSpecification extends OperationFunctionalSpecification { find(descending('x', 'y')) == [c, a, b] } + @IgnoreIf({ !serverVersionAtLeast([2, 6, 0]) }) def 'metaTextScore'() { expect: find(metaTextScore('score'), new Document('score', new Document('$meta', 'textScore')))*.containsKey('score') From 1096a50d478dbe14aa2a180bb4f9161c94da2608 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Tue, 7 Apr 2015 11:55:31 +0100 Subject: [PATCH 0008/1665] Documentation fixes --- .../getting-started/quick-tour-admin.md | 17 ++++++++------- .../getting-started/quick-tour.md | 21 ++++++++++--------- .../getting-started/quick-tour-admin.md | 16 +++++++------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/docs/reference/content/driver-async/getting-started/quick-tour-admin.md b/docs/reference/content/driver-async/getting-started/quick-tour-admin.md index f9a48d0f4bf..3c14d977007 100644 --- a/docs/reference/content/driver-async/getting-started/quick-tour-admin.md +++ b/docs/reference/content/driver-async/getting-started/quick-tour-admin.md @@ -26,7 +26,7 @@ for instructions on how to install the MongoDB Driver. ## Setup -To get use started we'll quickly connect and create a `mongoClient`, `database` and `collection` +To get started we'll quickly connect and create a `mongoClient`, `database` and `collection` variable for use in the examples below: ```java @@ -35,6 +35,12 @@ MongoDatabase database = mongoClient.getDatabase("mydb"); MongoCollection collection = database.getCollection("test"); ``` +{{% note %}} +Calling the `getDatabase()` on `MongoClient` does not create a database. +Only when a database is written to will a database be created. Examples include the creation of an index or the insertion of a document +into a previously non-existent collection. +{{% /note %}} + {{% note %}} Sometimes you will need the same or similar callbacks more than once. In these situations it makes sense to DRY (Do not Repeat Yourself) up your code and save the callback either @@ -64,11 +70,6 @@ mongoClient.listDatabaseNames().forEach(new Block() { }, callbackWhenFinished); ``` -Calling the `getDatabase()` on `MongoClient` does not create a database. -Only when a database is written to will a database be created. Examples -would be creating an index or collection or inserting a document into a -collection. - ## Drop A Database You can drop a database by name using a `MongoClient` instance: @@ -79,7 +80,9 @@ mongoClient.getDatabase("databaseToBeDropped").drop(callbackWhenFinished); ## Create A Collection -Collections in MongoDB are created automatically simply by inserted a document into it. Using the `[createCollection]({{< apiref "com/mongodb/async/client/MongoDatabase.html#createCollection-java.lang.String-com.mongodb.async.SingleResultCallback-">}})` method, you can also create a collection explicitly in order to to customize its configuration. For example, to create a capped collection sized to 1 megabyte: +Collections in MongoDB are created automatically simply by inserted a document into it. Using the +[`createCollection`]({{< apiref "com/mongodb/async/client/MongoDatabase.html#createCollection-java.lang.String-com.mongodb.async.SingleResultCallback-">}}) +method, you can also create a collection explicitly in order to to customize its configuration. For example, to create a capped collection sized to 1 megabyte: ```java database.createCollection("cappedCollection", diff --git a/docs/reference/content/driver-async/getting-started/quick-tour.md b/docs/reference/content/driver-async/getting-started/quick-tour.md index 0a70a036408..7f79a5af006 100644 --- a/docs/reference/content/driver-async/getting-started/quick-tour.md +++ b/docs/reference/content/driver-async/getting-started/quick-tour.md @@ -63,7 +63,7 @@ server for the specified database. There is no callback required for `getDatabase("mydb")` as there is no network IO required. A `MongoDatabase` instance provides methods to interact with a database but the database might not actually exist and will only be created on the -insertion of data via some means; eg the creation of a collection or the insertion of documents +insertion of data via some means; e.g. the creation of a collection or the insertion of documents which do require callbacks as they require network IO. {{% /note %}} @@ -287,7 +287,7 @@ import static com.mongodb.client.model.Filters.*; collection.find(eq("i", 71)).first(printDocument); ``` -and it should return immediately and eventually print just one document: +will eventually print just one document: ```json { "_id" : { "$oid" : "5515836e58c7b4fbc756320b" }, "i" : 71 } @@ -330,9 +330,9 @@ collection.find(exists("i")).sort(descending("i")).first(printDocument); ## Projecting fields -Sometimes we don't need all the data contained in a document, the [Projections]({{< apiref "com/mongodb/client/model/Projections">}}) helpers help build the projection parameter for the -find operation. Below we'll sort the collection, exclude the `_id` field and output the first -matching document: +Sometimes we don't need all the data contained in a document. The [Projections]({{< apiref "com/mongodb/client/model/Projections">}}) +helpers can be used to build the projection parameter for the find operation and limit the fields returned. +Below we'll sort the collection, exclude the `_id` field and output the first matching document: ```java collection.find().projection(excludeId()).first(printDocument); @@ -370,7 +370,7 @@ collection.updateMany(lt("i", 100), new Document("$inc", new Document("i", 100)) }); ``` -The update methods return a [`UpdateResult`]({{< apiref "com/mongodb/client/result/UpdateResult.html">}}) +The update methods return an [`UpdateResult`]({{< apiref "com/mongodb/client/result/UpdateResult.html">}}), which provides information about the operation including the number of documents modified by the update. ## Deleting documents @@ -387,8 +387,9 @@ collection.deleteOne(eq("i", 110), new SingleResultCallback() { }); ``` -To delete all documents matching the filter use the [`deleteMany`]({{< apiref "com/mongodb/async/client/MongoCollection.html#deleteMany-org.bson.conversions.Bson-">}}) method. -Here we delete all documents where `i` is greater or equal to `100`: +To delete all documents matching the filter use the +[`deleteMany`]({{< apiref "com/mongodb/async/client/MongoCollection.html#deleteMany-org.bson.conversions.Bson-">}}) method. Here we delete +all documents where `i` is greater or equal to `100`: ```java collection.deleteMany(gte("i", 100), new SingleResultCallback() { @@ -399,13 +400,13 @@ collection.deleteMany(gte("i", 100), new SingleResultCallback() { }); ``` -The delete methods return a [`DeleteResult`]({{< apiref "com/mongodb/client/result/DeleteResult.html">}}) +The delete methods return a [`DeleteResult`]({{< apiref "com/mongodb/client/result/DeleteResult.html">}}), which provides information about the operation including the number of documents deleted. ## Bulk operations -These new commands allow for the execution of bulk +These commands allow for the execution of bulk insert/update/delete operations. There are two types of bulk operations: 1. Ordered bulk operations. diff --git a/docs/reference/content/driver/getting-started/quick-tour-admin.md b/docs/reference/content/driver/getting-started/quick-tour-admin.md index dbf11fc1a25..6be2b2de0fc 100644 --- a/docs/reference/content/driver/getting-started/quick-tour-admin.md +++ b/docs/reference/content/driver/getting-started/quick-tour-admin.md @@ -26,7 +26,7 @@ for instructions on how to install the MongoDB Driver. ## Setup -To get use started we'll quickly connect and create a `mongoClient`, `database` and `collection` +To get started we'll quickly connect and create a `mongoClient`, `database` and `collection` variable for use in the examples below: ```java @@ -35,6 +35,12 @@ MongoDatabase database = mongoClient.getDatabase("mydb"); MongoCollection collection = database.getCollection("test"); ``` +{{% note %}} +Calling the `getDatabase()` on `MongoClient` does not create a database. +Only when a database is written to will a database be created. Examples include the creation of an index or the insertion of a document +into a previously non-existent collection. +{{% /note %}} + ## Get A List of Databases You can get a list of the available databases: @@ -45,11 +51,6 @@ for (String name: mongoClient.listDatabaseNames()) { } ``` -Calling the `getDatabase()` on `MongoClient` does not create a database. -Only when a database is written to will a database be created. Examples -would be creating an index or collection or inserting a document into a -collection. - ## Drop A Database You can drop a database by name using a `MongoClient` instance: @@ -60,7 +61,8 @@ mongoClient.getDatabase("databaseToBeDropped").drop(); ## Create A Collection -Collections in MongoDB are created automatically simply by inserted a document into it. Using the `[createCollection]({{< apiref "com/mongodb/client/MongoDatabase.html#createCollection-java.lang.String-">}})` method, you can also create a collection explicitly in order to to customize its configuration. For example, to create a capped collection sized to 1 megabyte: +Collections in MongoDB are created automatically simply by inserted a document into it. Using the [`createCollection`]({{< apiref "com/mongodb/client/MongoDatabase.html#createCollection-java.lang.String-">}}) +method, you can also create a collection explicitly in order to to customize its configuration. For example, to create a capped collection sized to 1 megabyte: ```java database.createCollection("cappedCollection", From 97837be462d2e0c4fc55a89950b9caad5c1c4de5 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 25 Mar 2015 22:41:31 -0400 Subject: [PATCH 0009/1665] Added toJson and parse methods to BasicDBObject JAVA-1721 --- config/checkstyle-exclude.xml | 2 + .../src/main/com/mongodb/BasicDBObject.java | 87 +++++++++++++++++++ .../unit/com/mongodb/BasicDBObjectTest.java | 31 +++++++ 3 files changed, 120 insertions(+) diff --git a/config/checkstyle-exclude.xml b/config/checkstyle-exclude.xml index dea58a406ca..84f450c0d4f 100644 --- a/config/checkstyle-exclude.xml +++ b/config/checkstyle-exclude.xml @@ -58,6 +58,8 @@ + + diff --git a/driver/src/main/com/mongodb/BasicDBObject.java b/driver/src/main/com/mongodb/BasicDBObject.java index d6dd06fa5ba..ec5262dc637 100644 --- a/driver/src/main/com/mongodb/BasicDBObject.java +++ b/driver/src/main/com/mongodb/BasicDBObject.java @@ -20,11 +20,21 @@ import org.bson.BasicBSONObject; import org.bson.BsonDocument; import org.bson.BsonDocumentWrapper; +import org.bson.codecs.Decoder; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.Encoder; +import org.bson.codecs.EncoderContext; import org.bson.codecs.configuration.CodecRegistry; import org.bson.conversions.Bson; +import org.bson.json.JsonReader; +import org.bson.json.JsonWriter; +import org.bson.json.JsonWriterSettings; +import java.io.StringWriter; import java.util.Map; +import static com.mongodb.MongoClient.getDefaultCodecRegistry; + /** * A basic implementation of BSON object that is MongoDB specific. A {@code DBObject} can be created as follows, using this class: *

@@ -40,6 +50,31 @@ public class BasicDBObject extends BasicBSONObject implements DBObject, Bson {
 
     private boolean isPartialObject;
 
+    /**
+     * Parses a string in MongoDB Extended JSON format to a {@code BasicDBObject}.
+     *
+     * @param json the JSON string
+     * @return a corresponding {@code BasicDBObject} object
+     * @see org.bson.json.JsonReader
+     * @mongodb.driver.manual reference/mongodb-extended-json/ MongoDB Extended JSON
+     */
+    public static BasicDBObject parse(final String json) {
+        return parse(json, getDefaultCodecRegistry().get(BasicDBObject.class));
+    }
+
+    /**
+     * Parses a string in MongoDB Extended JSON format to a {@code BasicDBObject}.
+     *
+     * @param json the JSON string
+     * @param decoder the decoder to use to decode the BasicDBObject instance
+     * @return a corresponding {@code BasicDBObject} object
+     * @see org.bson.json.JsonReader
+     * @mongodb.driver.manual reference/mongodb-extended-json/ MongoDB Extended JSON
+     */
+    public static BasicDBObject parse(final String json, final Decoder decoder) {
+        return decoder.decode(new JsonReader(json), DecoderContext.builder().build());
+    }
+
     /**
      * Creates an empty object.
      */
@@ -98,6 +133,58 @@ public boolean isPartialObject() {
         return isPartialObject;
     }
 
+    /**
+     * Gets a JSON representation of this document
+     *
+     * 

With the default {@link JsonWriterSettings} and {@link DBObjectCodec}.

+ * + * @return a JSON representation of this document + * @throws org.bson.codecs.configuration.CodecConfigurationException if the document contains types not in the default registry + */ + public String toJson() { + return toJson(new JsonWriterSettings()); + } + + /** + * Gets a JSON representation of this document + * + *

With the default {@link DBObjectCodec}.

+ * + * @param writerSettings the json writer settings to use when encoding + * @return a JSON representation of this document + * @throws org.bson.codecs.configuration.CodecConfigurationException if the document contains types not in the default registry + */ + public String toJson(final JsonWriterSettings writerSettings) { + return toJson(writerSettings, getDefaultCodecRegistry().get(BasicDBObject.class)); + } + + /** + * Gets a JSON representation of this document + * + *

With the default {@link JsonWriterSettings}.

+ * + * @param encoder the BasicDBObject codec instance to encode the document with + * @return a JSON representation of this document + * @throws org.bson.codecs.configuration.CodecConfigurationException if the registry does not contain a codec for the document values. + */ + public String toJson(final Encoder encoder) { + return toJson(new JsonWriterSettings(), encoder); + } + + /** + * Gets a JSON representation of this document + * + * @param writerSettings the json writer settings to use when encoding + * @param encoder the BasicDBObject codec instance to encode the document with + * @return a JSON representation of this document + * @throws org.bson.codecs.configuration.CodecConfigurationException if the registry does not contain a codec for the document values. + */ + public String toJson(final JsonWriterSettings writerSettings, final Encoder encoder) { + JsonWriter writer = new JsonWriter(new StringWriter(), writerSettings); + encoder.encode(writer, this, EncoderContext.builder().isEncodingCollectibleDocument(true).build()); + return writer.getWriter().toString(); + } + /** *

Returns a JSON serialization of this object

* diff --git a/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java b/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java index 265ab880a2b..272416f3c61 100644 --- a/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java +++ b/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java @@ -18,6 +18,8 @@ import com.mongodb.util.JSON; import org.bson.BasicBSONObject; +import org.bson.json.JsonMode; +import org.bson.json.JsonWriterSettings; import org.bson.types.ObjectId; import org.junit.Test; @@ -26,6 +28,7 @@ import java.util.Map; import java.util.TreeMap; +import static com.mongodb.MongoClient.getDefaultCodecRegistry; import static java.util.Arrays.asList; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; @@ -35,6 +38,34 @@ public class BasicDBObjectTest { + @Test + public void testParse() { + BasicDBObject document = BasicDBObject.parse("{ 'int' : 1, 'string' : 'abc' }"); + assertEquals(new BasicDBObject("int", 1).append("string", "abc"), document); + + document = BasicDBObject.parse("{ 'int' : 1, 'string' : 'abc' }", getDefaultCodecRegistry().get(BasicDBObject.class)); + assertEquals(new BasicDBObject("int", 1).append("string", "abc"), document); + + document = BasicDBObject.parse("{d : {$gte : ISODate('2015-03-19'), $lt : ISODate('2015-04-19') } }"); + assertEquals(new BasicDBObject("d", new BasicDBObject("$gte", new Date(1426737600000L)).append("$lt", new Date(1429416000000L))), + document); + } + + @Test + public void testToJson() { + BasicDBObject doc = new BasicDBObject("_id", new ObjectId("5522d5d12cf8fb556a991f45")).append("int", 1).append("string", "abc"); + + assertEquals("{ \"_id\" : { \"$oid\" : \"5522d5d12cf8fb556a991f45\" }, \"int\" : 1, \"string\" : \"abc\" }", doc.toJson()); + assertEquals("{ \"_id\" : ObjectId(\"5522d5d12cf8fb556a991f45\"), \"int\" : 1, \"string\" : \"abc\" }", + doc.toJson(new JsonWriterSettings(JsonMode.SHELL))); + + assertEquals("{ \"_id\" : { \"$oid\" : \"5522d5d12cf8fb556a991f45\" }, \"int\" : 1, \"string\" : \"abc\" }", + doc.toJson(getDefaultCodecRegistry().get(BasicDBObject.class))); + + assertEquals("{ \"_id\" : ObjectId(\"5522d5d12cf8fb556a991f45\"), \"int\" : 1, \"string\" : \"abc\" }", + doc.toJson(new JsonWriterSettings(JsonMode.SHELL), getDefaultCodecRegistry().get(BasicDBObject.class))); + } + @Test public void testGetDate() { final Date date = new Date(); From 449d75da096517e67e8b2211ff64d9159ddb9d9d Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Mon, 6 Apr 2015 13:47:00 -0400 Subject: [PATCH 0010/1665] Message size for send message event must be calculated before the message is written. Otherwise, ByteBuf.remaining() returns 0. JAVA-1743 --- .../connection/InternalStreamConnection.java | 9 +-- ...ternalStreamConnectionSpecification.groovy | 58 +++++++++++++++---- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/driver-core/src/main/com/mongodb/connection/InternalStreamConnection.java b/driver-core/src/main/com/mongodb/connection/InternalStreamConnection.java index 4ff5272b998..b928723790d 100644 --- a/driver-core/src/main/com/mongodb/connection/InternalStreamConnection.java +++ b/driver-core/src/main/com/mongodb/connection/InternalStreamConnection.java @@ -197,8 +197,9 @@ public void sendMessage(final List byteBuffers, final int lastRequestId writerLock.lock(); try { + int messageSize = getMessageSize(byteBuffers); stream.write(byteBuffers); - connectionListener.messagesSent(new ConnectionMessagesSentEvent(getId(), lastRequestId, getTotalRemaining(byteBuffers))); + connectionListener.messagesSent(new ConnectionMessagesSentEvent(getId(), lastRequestId, messageSize)); } catch (Exception e) { close(); throw translateWriteException(e); @@ -289,6 +290,7 @@ public void sendMessageAsync(final List byteBuffers, final int lastRequ } private void writeAsync(final SendMessageRequest request) { + final int messageSize = getMessageSize(request.getByteBuffers()); stream.writeAsync(request.getByteBuffers(), new AsyncCompletionHandler() { @Override public void completed(final Void v) { @@ -303,8 +305,7 @@ public void completed(final Void v) { writerLock.unlock(); } - connectionListener.messagesSent(new ConnectionMessagesSentEvent(getId(), request.getMessageId(), - getTotalRemaining(request.getByteBuffers()))); + connectionListener.messagesSent(new ConnectionMessagesSentEvent(getId(), request.getMessageId(), messageSize)); request.getCallback().onResult(null, null); if (nextMessage != null) { @@ -579,7 +580,7 @@ public void onResult(final ByteBuf result, final Throwable t) { } } - private int getTotalRemaining(final List byteBuffers) { + private int getMessageSize(final List byteBuffers) { int messageSize = 0; for (final ByteBuf cur : byteBuffers) { messageSize += cur.remaining(); diff --git a/driver-core/src/test/unit/com/mongodb/connection/InternalStreamConnectionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/connection/InternalStreamConnectionSpecification.groovy index 699fe8cd074..836cfac5a8d 100644 --- a/driver-core/src/test/unit/com/mongodb/connection/InternalStreamConnectionSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/connection/InternalStreamConnectionSpecification.groovy @@ -27,6 +27,8 @@ import com.mongodb.ServerAddress import com.mongodb.async.FutureResultCallback import com.mongodb.async.SingleResultCallback import com.mongodb.event.ConnectionListener +import com.mongodb.event.ConnectionMessageReceivedEvent +import com.mongodb.event.ConnectionMessagesSentEvent import org.bson.BsonBinaryWriter import org.bson.BsonDocument import org.bson.BsonInt32 @@ -50,6 +52,7 @@ import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import static MongoNamespace.COMMAND_COLLECTION_NAME +import static com.mongodb.CustomMatchers.compare import static com.mongodb.connection.ConnectionDescription.getDefaultMaxMessageSize import static com.mongodb.connection.ConnectionDescription.getDefaultMaxWriteBatchSize import static com.mongodb.connection.ServerDescription.getDefaultMaxDocumentSize @@ -61,7 +64,9 @@ class InternalStreamConnectionSpecification extends Specification { def helper = new StreamHelper() def serverAddress = new ServerAddress() - def connectionDescription = new ConnectionDescription(new ConnectionId(SERVER_ID, 1, 1), new ServerVersion(), ServerType.STANDALONE, + def connectionId = new ConnectionId(SERVER_ID, 1, 1) + + def connectionDescription = new ConnectionDescription(connectionId, new ServerVersion(), ServerType.STANDALONE, getDefaultMaxWriteBatchSize(), getDefaultMaxDocumentSize(), getDefaultMaxMessageSize()) def stream = Mock(Stream) { @@ -106,23 +111,31 @@ class InternalStreamConnectionSpecification extends Specification { given: def connection = getOpenedConnection() def (buffers1, messageId1) = helper.isMaster() - stream.read(_) >>> helper.read([messageId1]) + def messageSize = helper.remaining(buffers1) + stream.write(_) >> { + helper.write(buffers1) + } when: connection.sendMessage(buffers1, messageId1) + then: - 1 * listener.messagesSent(_) + 1 * listener.messagesSent { + compare(new ConnectionMessagesSentEvent(connectionId, messageId1, messageSize), it) + } } @Category(Async) @IgnoreIf({ javaVersion < 1.7 }) def 'should fire message sent event asynchronously'() { - stream.writeAsync(_, _) >> { List buffers, AsyncCompletionHandler callback -> - callback.completed(null) - } def (buffers1, messageId1) = helper.isMaster() + def messageSize = helper.remaining(buffers1) def connection = getOpenedConnection() def latch = new CountDownLatch(1); + stream.writeAsync(_, _) >> { List buffers, AsyncCompletionHandler callback -> + helper.write(buffers1) + callback.completed(null) + } when: connection.sendMessageAsync(buffers1, messageId1, new SingleResultCallback() { @@ -134,7 +147,9 @@ class InternalStreamConnectionSpecification extends Specification { latch.await() then: - 1 * listener.messagesSent(_) + 1 * listener.messagesSent { + compare(new ConnectionMessagesSentEvent(connectionId, messageId1, messageSize), it) + } } def 'should fire message received event'() { @@ -147,7 +162,9 @@ class InternalStreamConnectionSpecification extends Specification { connection.receiveMessage(messageId1) then: - 1 * listener.messageReceived(_) + 1 * listener.messageReceived { + compare(new ConnectionMessageReceivedEvent(connectionId, messageId1, 110), it) + } } @Category(Async) @@ -175,7 +192,9 @@ class InternalStreamConnectionSpecification extends Specification { latch.await() then: - 1 * listener.messageReceived(_) + 1 * listener.messageReceived { + compare(new ConnectionMessageReceivedEvent(connectionId, messageId1, 110), it) + } } def 'should change the connection description when opened'() { @@ -653,6 +672,21 @@ class InternalStreamConnectionSpecification extends Specification { class StreamHelper { int nextMessageId = 900000 // Generates a message then adds one to the id + def remaining(List buffers) { + int remaining = 0 + buffers.each { + remaining += it.remaining() + } + remaining + } + + def write(List buffers) { + buffers.each { + it.get(new byte[it.remaining()]) + } + } + + def read(List messageIds) { read(messageIds, true) } @@ -706,10 +740,10 @@ class InternalStreamConnectionSpecification extends Specification { def command = new CommandMessage(new MongoNamespace('admin', COMMAND_COLLECTION_NAME).getFullName(), new BsonDocument('ismaster', new BsonInt32(1)), false, MessageSettings.builder().build()); - OutputBuffer buffer = new BasicOutputBuffer(); - command.encode(buffer); + OutputBuffer outputBuffer = new BasicOutputBuffer(); + command.encode(outputBuffer); nextMessageId++ - [buffer.byteBuffers, nextMessageId] + [outputBuffer.byteBuffers, nextMessageId] } def isMasterAsync() { From 7bdbb24aff0eb8a2b2de54a7fcd68476847fd03e Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 7 Apr 2015 12:46:47 -0400 Subject: [PATCH 0011/1665] Changed test for BasicDBObject parse method to remove timezone dependency --- driver/src/test/unit/com/mongodb/BasicDBObjectTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java b/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java index 272416f3c61..4e7d85399a9 100644 --- a/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java +++ b/driver/src/test/unit/com/mongodb/BasicDBObjectTest.java @@ -46,9 +46,8 @@ public void testParse() { document = BasicDBObject.parse("{ 'int' : 1, 'string' : 'abc' }", getDefaultCodecRegistry().get(BasicDBObject.class)); assertEquals(new BasicDBObject("int", 1).append("string", "abc"), document); - document = BasicDBObject.parse("{d : {$gte : ISODate('2015-03-19'), $lt : ISODate('2015-04-19') } }"); - assertEquals(new BasicDBObject("d", new BasicDBObject("$gte", new Date(1426737600000L)).append("$lt", new Date(1429416000000L))), - document); + document = BasicDBObject.parse("{_id : ObjectId('5524094c2cf8fb61dede210c')}"); + assertEquals(new BasicDBObject("_id", new ObjectId("5524094c2cf8fb61dede210c")), document); } @Test From dab9d426dedf8040536aa57464c937584ae062ee Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 7 Apr 2015 13:51:37 -0400 Subject: [PATCH 0012/1665] Added @Ignore for tests of binding implementations that used to be in production but are now only in test. --- .../binding/AsyncSingleConnectionBindingTest.java | 10 +++++++--- .../mongodb/binding/SingleConnectionBindingTest.java | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/driver-core/src/test/functional/com/mongodb/binding/AsyncSingleConnectionBindingTest.java b/driver-core/src/test/functional/com/mongodb/binding/AsyncSingleConnectionBindingTest.java index a639be385b4..577c622b757 100644 --- a/driver-core/src/test/functional/com/mongodb/binding/AsyncSingleConnectionBindingTest.java +++ b/driver-core/src/test/functional/com/mongodb/binding/AsyncSingleConnectionBindingTest.java @@ -22,6 +22,7 @@ import com.mongodb.connection.AsyncConnection; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -37,6 +38,7 @@ import static org.junit.Assert.assertThat; @Category(ReplicaSet.class) +@Ignore // Ignoring, since this is test of a test class public class AsyncSingleConnectionBindingTest { private AsyncSingleConnectionBinding binding; @@ -86,7 +88,7 @@ public void shouldHaveTheSameConnectionForReadsAndWritesWithPrimaryReadPreferenc @Test public void shouldNotDevourAllConnections() throws Throwable { for (int i = 0; i < 250; i++) { - AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), 1, SECONDS); + AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), ClusterFixture.TIMEOUT, SECONDS); getAndReleaseConnectionSourceAndConnection(getReadConnectionSource(binding)); getAndReleaseConnectionSourceAndConnection(getReadConnectionSource(binding)); getAndReleaseConnectionSourceAndConnection(getWriteConnectionSource(binding)); @@ -99,7 +101,8 @@ public void shouldNotDevourAllConnections() throws Throwable { @Test public void shouldHaveTheDifferentConnectionForReadsAndWritesWithNonPrimaryReadPreference() throws Throwable { - AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), secondary(), 1, SECONDS); + AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), secondary(), ClusterFixture.TIMEOUT, + SECONDS); AsyncConnectionSource writeSource = getWriteConnectionSource(binding); AsyncConnection writeConnection = getConnection(writeSource); @@ -117,7 +120,8 @@ public void shouldHaveTheDifferentConnectionForReadsAndWritesWithNonPrimaryReadP @Test public void shouldNotDevourAllConnectionsWhenUsingNonPrimaryReadPreference() throws Throwable { for (int i = 0; i < 500; i++) { - AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), secondary(), 1, SECONDS); + AsyncSingleConnectionBinding binding = new AsyncSingleConnectionBinding(getAsyncCluster(), secondary(), ClusterFixture.TIMEOUT, + SECONDS); getAndReleaseConnectionSourceAndConnection(getReadConnectionSource(binding)); getAndReleaseConnectionSourceAndConnection(getReadConnectionSource(binding)); getAndReleaseConnectionSourceAndConnection(getWriteConnectionSource(binding)); diff --git a/driver-core/src/test/functional/com/mongodb/binding/SingleConnectionBindingTest.java b/driver-core/src/test/functional/com/mongodb/binding/SingleConnectionBindingTest.java index d6d1d1e14bf..21e9a96fb19 100644 --- a/driver-core/src/test/functional/com/mongodb/binding/SingleConnectionBindingTest.java +++ b/driver-core/src/test/functional/com/mongodb/binding/SingleConnectionBindingTest.java @@ -20,6 +20,7 @@ import com.mongodb.connection.Connection; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -31,6 +32,7 @@ import static org.junit.Assert.assertThat; @Category(ReplicaSet.class) +@Ignore // Ignoring, since this is test of a test class public class SingleConnectionBindingTest { private SingleConnectionBinding binding; From 9875f164bfaece2db7d7d9dc3267907e82de4fe2 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 11:49:53 +0100 Subject: [PATCH 0013/1665] Updated Filter.Not JAVA-1740 --- .../com/mongodb/client/model/Filters.java | 68 ++++--------------- .../client/model/FiltersSpecification.groovy | 15 ++-- 2 files changed, 21 insertions(+), 62 deletions(-) diff --git a/driver-core/src/main/com/mongodb/client/model/Filters.java b/driver-core/src/main/com/mongodb/client/model/Filters.java index c83207ad38b..54dc8dec069 100644 --- a/driver-core/src/main/com/mongodb/client/model/Filters.java +++ b/driver-core/src/main/com/mongodb/client/model/Filters.java @@ -689,69 +689,27 @@ public NotFilter(final Bson filter) { @Override public BsonDocument toBsonDocument(final Class documentClass, final CodecRegistry codecRegistry) { - BsonDocument bsonFilter = toFilter(filter.toBsonDocument(documentClass, codecRegistry)); - if (bsonFilter.keySet().iterator().next().startsWith("$")) { - throw new IllegalArgumentException("Invalid $not document, the filter document must start with the field name that " - + "the $not operator applies to: " + filter); - } - return bsonFilter; - } - - public BsonDocument toFilter(final BsonDocument filterDocument) { - BsonDocument combinedDocument = new BsonDocument(); - for (Map.Entry docs : filterDocument.entrySet()) { - combinedDocument = combineDocuments(combinedDocument, createFilter(docs.getKey(), docs.getValue())); + BsonDocument filterDocument = filter.toBsonDocument(documentClass, codecRegistry); + if (filterDocument.size() == 1) { + Map.Entry entry = filterDocument.entrySet().iterator().next(); + return createFilter(entry.getKey(), entry.getValue()); + } else { + BsonArray values = new BsonArray(); + for (Map.Entry docs : filterDocument.entrySet()) { + values.add(new BsonDocument(docs.getKey(), docs.getValue())); + } + return createFilter("$and", values); } - return combinedDocument; } private BsonDocument createFilter(final String fieldName, final BsonValue value) { - if (fieldName.equals("$and")) { - return toFilter(flattenBsonArray(value.asArray())); - } else if (value.isDocument() && ((BsonDocument) value).keySet().iterator().next().startsWith("$")) { - return new BsonDocument(fieldName, new BsonDocument("$not", value)); - } else if (value.isRegularExpression()) { + if (fieldName.startsWith("$")) { + return new BsonDocument("$not", new BsonDocument(fieldName, value)); + } else if (value.isDocument() || value.isRegularExpression()) { return new BsonDocument(fieldName, new BsonDocument("$not", value)); } return new BsonDocument(fieldName, new BsonDocument("$not", new BsonDocument("$eq", value))); } - private BsonDocument combineDocuments(final BsonDocument document1, final BsonDocument document2) { - BsonDocument combinedDocument = document1; - for (Map.Entry entry : document2.entrySet()) { - String key = entry.getKey(); - BsonValue val = entry.getValue(); - BsonDocument document = combinedDocument.getDocument(key, new BsonDocument()); - if (!val.isDocument()) { - if (document.containsKey("$in")) { - BsonArray inArray = document.getArray("$in"); - inArray.add(val); - document.put("$in", inArray); - } else if (document.containsKey("$eq")) { - BsonArray inArray = document.getArray("$in", new BsonArray()); - inArray.add(document.remove("$eq")); - inArray.add(val); - document.put("$in", inArray); - } else { - document.put("$eq", val); - } - } else { - document = val.asDocument(); - } - combinedDocument.put(key, document); - } - return combinedDocument; - } - - private BsonDocument flattenBsonArray(final BsonArray bsonArray) { - BsonDocument combinedDocument = new BsonDocument(); - for (BsonValue bsonValue : bsonArray) { - if (!bsonValue.isDocument()) { - throw new IllegalArgumentException("Invalid $not document " + bsonValue); - } - combinedDocument = combineDocuments(combinedDocument, bsonValue.asDocument()); - } - return combinedDocument; - } } } diff --git a/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy index c235cb926af..17441212060 100644 --- a/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy @@ -72,15 +72,16 @@ class FiltersSpecification extends Specification { toBson(not(eq('x', 1))) == parse('{x : {$not: {$eq: 1}}}') toBson(not(gt('x', 1))) == parse('{x : {$not: {$gt: 1}}}') toBson(not(regex('x', '^p.*'))) == parse('{x : {$not: /^p.*/}}') - toBson(not(and(gt('x', 1), eq('y', 20)))) == parse('{x : {$not: {$gt: 1}}, y : {$not: {$eq: 20}}}') - toBson(not(and(eq('x', 1), eq('x', 2)))) == parse('{x : {$not: {$in: [1, 2]}}}') - toBson(not(and(Filters.in('x', 1, 2), eq('x', 3)))) == parse('{x : {$not: {$in: [1, 2, 3]}}}') - when: 'Missing a field name it should error' - toBson(not(new BsonDocument('$in', new BsonArray(asList(new BsonInt32(1)))))) + toBson(not(and(gt('x', 1), eq('y', 20)))) == parse('{$not: {$and: [{x: {$gt: 1}}, {y: 20}]}}') + toBson(not(and(eq('x', 1), eq('x', 2)))) == parse('{$not: {$and: [{x: 1}, {x: 2}]}}') + toBson(not(and(Filters.in('x', 1, 2), eq('x', 3)))) == parse('{$not: {$and: [{x: {$in: [1, 2]}}, {x: 3}]}}') - then: - thrown(IllegalArgumentException) + toBson(not(or(gt('x', 1), eq('y', 20)))) == parse('{$not: {$or: [{x: {$gt: 1}}, {y: 20}]}}') + toBson(not(or(eq('x', 1), eq('x', 2)))) == parse('{$not: {$or: [{x: 1}, {x: 2}]}}') + toBson(not(or(Filters.in('x', 1, 2), eq('x', 3)))) == parse('{$not: {$or: [{x: {$in: [1, 2]}}, {x: 3}]}}') + + toBson(not(new BsonDocument('$in', new BsonArray(asList(new BsonInt32(1)))))) == parse('{$not: {$in: [1]}}') } def 'should render $nor'() { From 0f92dde635f883197fbf438eea3ca28a171e0440 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 11:59:19 +0100 Subject: [PATCH 0014/1665] Updated FiltersFunctionalSpecification as Filters.Not has changed JAVA-1740 --- .../client/model/FiltersFunctionalSpecification.groovy | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy index 91d2a79cc53..1afeeab7b47 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/client/model/FiltersFunctionalSpecification.groovy @@ -16,6 +16,7 @@ package com.mongodb.client.model +import com.mongodb.MongoQueryException import com.mongodb.OperationFunctionalSpecification import org.bson.BsonType import org.bson.Document @@ -86,10 +87,12 @@ class FiltersFunctionalSpecification extends OperationFunctionalSpecification { find(not(eq('x', 1))) == [b, c] find(not(gt('x', 1))) == [a] find(not(regex('y', 'a.*'))) == [b, c] + + when: find(not(and(eq('x', 1), eq('x', 1)))) == [b, c] - find(not(and(Filters.in('a', 1, 2), eq('x', 1)))) == [b, c] - find(not(and(eq('x', 1), eq('y', 'a')))) == [b, c] - // find(not(and(eq('x', 1), eq('y', 'b')))) == [a, b, c] // should pass, but see JAVA-1740 + + then: + thrown MongoQueryException } def '$nor'() { From dd370426495a890187c51bdbeccb93821b484b09 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 14:23:03 +0100 Subject: [PATCH 0015/1665] Added dependencies to installation guides JAVA-1749 --- .../driver-async/getting-started/installation-guide.md | 2 +- .../driver/getting-started/installation-guide.md | 2 +- docs/reference/layouts/shortcodes/install.html | 10 +++++----- docs/reference/static/css/java.css | 5 ++++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/reference/content/driver-async/getting-started/installation-guide.md b/docs/reference/content/driver-async/getting-started/installation-guide.md index b328fc95da3..0778cc14496 100644 --- a/docs/reference/content/driver-async/getting-started/installation-guide.md +++ b/docs/reference/content/driver-async/getting-started/installation-guide.md @@ -17,4 +17,4 @@ The recommended way to get started using one of the drivers in your project is w ## MongoDB Async Driver The new asynchronous API that can leverage either Netty or Java 7's AsynchronousSocketChannel for fast and non-blocking IO. -{{< install artifactId="mongodb-driver-async" version="3.0.0" >}} +{{< install artifactId="mongodb-driver-async" version="3.0.0" dependencies="`bson`, `mongodb-driver-core`">}} diff --git a/docs/reference/content/driver/getting-started/installation-guide.md b/docs/reference/content/driver/getting-started/installation-guide.md index 247335bc0ba..a08e86b9f89 100644 --- a/docs/reference/content/driver/getting-started/installation-guide.md +++ b/docs/reference/content/driver/getting-started/installation-guide.md @@ -22,7 +22,7 @@ The MongoDB Driver is the updated synchronous Java driver that includes the legacy API as well as a new generic MongoCollection interface that complies with a new cross-driver CRUD specification. -{{< install artifactId="mongodb-driver" version="3.0.0" >}} +{{< install artifactId="mongodb-driver" version="3.0.0" dependencies="`bson`, `mongodb-driver-core`">}} ## Uber MongoDB Java Driver diff --git a/docs/reference/layouts/shortcodes/install.html b/docs/reference/layouts/shortcodes/install.html index 8ff5e28767c..c94451343e3 100644 --- a/docs/reference/layouts/shortcodes/install.html +++ b/docs/reference/layouts/shortcodes/install.html @@ -1,4 +1,4 @@ -{{ $artifactId := .Get "artifactId"}}{{ $version := .Get "version"}} +{{ $artifactId := .Get "artifactId"}}{{ $version := .Get "version"}}{{ $dependencies := .Get "dependencies"}}

 <dependencies>
@@ -19,9 +19,9 @@
 
 
-
-

You can also download the jars +

+

You can also download the jars directly - from sonatype. -

+ from sonatype.

+{{ with $dependencies}}{{ $depMarkdown := add (add (add (add "**Note:** `" $artifactId ) "` requires the following dependencies: ") . ) "." }}{{$depMarkdown | markdownify}}{{end}}
diff --git a/docs/reference/static/css/java.css b/docs/reference/static/css/java.css index e032db1c2a5..80383a4ba9a 100644 --- a/docs/reference/static/css/java.css +++ b/docs/reference/static/css/java.css @@ -1,4 +1,7 @@ .downloadInfo { margin-top: -24px; - font-size: 14px; + font-size: 13px; +} +.downloadInfo p { + margin: 0px; } From 4f98eec1377ecb133cec91405e799f0cfa311e0b Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 14:24:41 +0100 Subject: [PATCH 0016/1665] Added minimum java version note to driver-async installation guide --- .../driver-async/getting-started/installation-guide.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/reference/content/driver-async/getting-started/installation-guide.md b/docs/reference/content/driver-async/getting-started/installation-guide.md index 0778cc14496..fd64bf782d6 100644 --- a/docs/reference/content/driver-async/getting-started/installation-guide.md +++ b/docs/reference/content/driver-async/getting-started/installation-guide.md @@ -10,8 +10,13 @@ title = "Installation Guide" # Installation + The recommended way to get started using one of the drivers in your project is with a dependency management system. +{{% note class="important" %}} +The MongoDB Async Driver requires Java 7 or greater. +{{% /note %}} + {{< distroPicker >}} ## MongoDB Async Driver From c9b5c747e3c27f5f94f5cfadde2e6704a5892a87 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 14:28:52 +0100 Subject: [PATCH 0017/1665] Added link the to API Documentation JAVA-1750 --- docs/reference/config.toml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/reference/config.toml b/docs/reference/config.toml index 2246ca57e75..ea013c1cf5d 100644 --- a/docs/reference/config.toml +++ b/docs/reference/config.toml @@ -7,10 +7,9 @@ canonifyurls = false [blackfriday] plainIdAnchors = true -# Example custom menu Item (Useful for linking to API docs) -# [[menu.main]] -# name = "Issues & Help" -# pre = "" -# weight = 100 -# identifier = "help" -# url = "https://jira.mongodb.org/browse/JAVA" +[[menu.main]] + name = "API Documentation" + pre = "" + weight = 90 + identifier = "apiDocs" + url = "http://api.mongodb.org/java/3.0" From d16cb1c38ccc35cdb270689a9b361b349173e8cb Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 16:12:41 +0100 Subject: [PATCH 0018/1665] Updated Uber Jar description --- .../content/driver/getting-started/installation-guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/content/driver/getting-started/installation-guide.md b/docs/reference/content/driver/getting-started/installation-guide.md index a08e86b9f89..c3e3b8eda82 100644 --- a/docs/reference/content/driver/getting-started/installation-guide.md +++ b/docs/reference/content/driver/getting-started/installation-guide.md @@ -26,6 +26,6 @@ a new cross-driver CRUD specification. ## Uber MongoDB Java Driver -This is the legacy uber jar that contains everything you need; the BSON library, the core library and the mongodb-driver. +An uber jar that contains everything you need; the BSON library, the core library and the mongodb-driver. {{< install artifactId="mongo-java-driver" version="3.0.0" >}} From 37a29d8db310fbb559c55dc6ce3134ede7e1c925 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Wed, 8 Apr 2015 16:37:53 +0100 Subject: [PATCH 0019/1665] Documentation updates Updated the github branch in the docs Added a link to the Source Code in the menu --- docs/reference/config.toml | 9 +++++++++ docs/reference/data/mongodb.toml | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/reference/config.toml b/docs/reference/config.toml index ea013c1cf5d..bdee6baf56f 100644 --- a/docs/reference/config.toml +++ b/docs/reference/config.toml @@ -7,9 +7,18 @@ canonifyurls = false [blackfriday] plainIdAnchors = true + +# Update versions in mongodb.toml as well [[menu.main]] name = "API Documentation" pre = "" weight = 90 identifier = "apiDocs" url = "http://api.mongodb.org/java/3.0" + +[[menu.main]] + name = "Source Code" + pre = "" + weight = 90 + identifier = "githubLink" + url = "https://github.com/mongodb/mongo-java-driver/tree/3.0.x" diff --git a/docs/reference/data/mongodb.toml b/docs/reference/data/mongodb.toml index 4c2d3039f11..d5eabf5af6b 100644 --- a/docs/reference/data/mongodb.toml +++ b/docs/reference/data/mongodb.toml @@ -1,5 +1,6 @@ +# Update versions in config.toml as well githubRepo = "mongo-java-driver" -githubBranch = "master" +githubBranch = "3.0.x" currentVersion = "3.0" highlightTheme = "idea.css" apiUrl = "http://api.mongodb.org/java/3.0/" From 0c43aeab14114ada008e1aab29a04c441594cca6 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Thu, 9 Apr 2015 10:33:47 +0100 Subject: [PATCH 0020/1665] Added links to the dependencies on sonatype JAVA-1749 --- .../driver-async/getting-started/installation-guide.md | 4 ++-- .../content/driver/getting-started/installation-guide.md | 2 +- docs/reference/layouts/shortcodes/install.html | 8 +++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/reference/content/driver-async/getting-started/installation-guide.md b/docs/reference/content/driver-async/getting-started/installation-guide.md index fd64bf782d6..f8b166edac6 100644 --- a/docs/reference/content/driver-async/getting-started/installation-guide.md +++ b/docs/reference/content/driver-async/getting-started/installation-guide.md @@ -14,7 +14,7 @@ title = "Installation Guide" The recommended way to get started using one of the drivers in your project is with a dependency management system. {{% note class="important" %}} -The MongoDB Async Driver requires Java 7 or greater. +The MongoDB Async Driver requires either [Netty](http://netty.io/) or Java 7. {{% /note %}} {{< distroPicker >}} @@ -22,4 +22,4 @@ The MongoDB Async Driver requires Java 7 or greater. ## MongoDB Async Driver The new asynchronous API that can leverage either Netty or Java 7's AsynchronousSocketChannel for fast and non-blocking IO. -{{< install artifactId="mongodb-driver-async" version="3.0.0" dependencies="`bson`, `mongodb-driver-core`">}} +{{< install artifactId="mongodb-driver-async" version="3.0.0" dependencies="true">}} diff --git a/docs/reference/content/driver/getting-started/installation-guide.md b/docs/reference/content/driver/getting-started/installation-guide.md index c3e3b8eda82..08340b24275 100644 --- a/docs/reference/content/driver/getting-started/installation-guide.md +++ b/docs/reference/content/driver/getting-started/installation-guide.md @@ -22,7 +22,7 @@ The MongoDB Driver is the updated synchronous Java driver that includes the legacy API as well as a new generic MongoCollection interface that complies with a new cross-driver CRUD specification. -{{< install artifactId="mongodb-driver" version="3.0.0" dependencies="`bson`, `mongodb-driver-core`">}} +{{< install artifactId="mongodb-driver" version="3.0.0" dependencies="true">}} ## Uber MongoDB Java Driver diff --git a/docs/reference/layouts/shortcodes/install.html b/docs/reference/layouts/shortcodes/install.html index c94451343e3..c841b1eea48 100644 --- a/docs/reference/layouts/shortcodes/install.html +++ b/docs/reference/layouts/shortcodes/install.html @@ -23,5 +23,11 @@

You can also download the jars directly from sonatype.

-{{ with $dependencies}}{{ $depMarkdown := add (add (add (add "**Note:** `" $artifactId ) "` requires the following dependencies: ") . ) "." }}{{$depMarkdown | markdownify}}{{end}} +{{ with $dependencies}} +

+ Note: {{$artifactId}} requires the following dependencies: + bson and + mongodb-driver-core +

+{{end}}
From 611fbdc1c1c601352031082c7c72e8b2be6f0c82 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 9 Apr 2015 11:33:26 -0400 Subject: [PATCH 0021/1665] Working around sharding issue by only testing collection rename when not connected to a sharded cluster JAVA-1757 --- .../client/SmokeTestSpecification.groovy | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/driver-async/src/test/functional/com/mongodb/async/client/SmokeTestSpecification.groovy b/driver-async/src/test/functional/com/mongodb/async/client/SmokeTestSpecification.groovy index 598e2250ad8..5ffd6087016 100644 --- a/driver-async/src/test/functional/com/mongodb/async/client/SmokeTestSpecification.groovy +++ b/driver-async/src/test/functional/com/mongodb/async/client/SmokeTestSpecification.groovy @@ -23,6 +23,7 @@ import spock.lang.IgnoreIf import static com.mongodb.ClusterFixture.serverVersionAtLeast import static com.mongodb.async.client.Fixture.getMongoClient +import static com.mongodb.async.client.Fixture.isSharded import static java.util.Arrays.asList import static java.util.concurrent.TimeUnit.SECONDS @@ -149,17 +150,6 @@ class SmokeTestSpecification extends FunctionalSpecification { then: 'has a single index left "_id" ' run(collection.listIndexes().&into, []).size == 1 - then: 'can rename the collection' - def newCollectionName = 'newCollectionName' - run(collection.&renameCollection, new MongoNamespace(databaseName, newCollectionName)) == null - - then: 'the new collection name is in the collection names list' - !run(database.listCollectionNames().&into, []).contains(collectionName) - run(database.listCollectionNames().&into, []).contains(newCollectionName) - - when: - collection = database.getCollection(newCollectionName) - then: 'drop the collection' run(collection.&drop) == null @@ -170,6 +160,26 @@ class SmokeTestSpecification extends FunctionalSpecification { !run(database.listCollectionNames().&into, []).contains(collectionName) } + @IgnoreIf({ isSharded() }) // see JAVA-1757 for why sharded clusters are currently excluded from this test + def 'should handle rename collection administrative scenario without error'() { + given: + def mongoClient = getMongoClient() + def database = mongoClient.getDatabase(databaseName) + def collection = database.getCollection(collectionName) + run(mongoClient.getDatabase(databaseName).&drop) == null + + when: 'Create a collection and the created database is in the list' + run(database.&createCollection, collectionName) + + then: 'can rename the collection' + def newCollectionName = 'newCollectionName' + run(collection.&renameCollection, new MongoNamespace(databaseName, newCollectionName)) == null + + then: 'the new collection name is in the collection names list' + !run(database.listCollectionNames().&into, []).contains(collectionName) + run(database.listCollectionNames().&into, []).contains(newCollectionName) + } + def run(operation, ... args) { def futureResultCallback = new FutureResultCallback() def opArgs = (args != null) ? args : [] From 9426566f6fcbc25d9697da5e31351c9198a97828 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Tue, 14 Apr 2015 09:32:02 +0100 Subject: [PATCH 0022/1665] Updated releases.toml for 2.13.1 --- docs/landing/data/releases.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/landing/data/releases.toml b/docs/landing/data/releases.toml index bfe414ecde0..ddefabc8e19 100644 --- a/docs/landing/data/releases.toml +++ b/docs/landing/data/releases.toml @@ -6,7 +6,7 @@ current = "3.0.0" api = "http://api.mongodb.org/java/3.0" [[versions]] - version = "2.13.0" + version = "2.13.1" status = "" docs = "./2.13" api = "http://api.mongodb.org/java/2.13" @@ -19,7 +19,7 @@ current = "3.0.0" [[drivers]] name = "mongo-java-driver" description = "An uber jar containing the bson library, the core library and the mongodb-driver." - versions = "3.0.0,2.13.0" + versions = "3.0.0,2.13.1" [[drivers]] name = "mongodb-driver-async" From 86207eace2d87d3855374f21a791c3c62777de00 Mon Sep 17 00:00:00 2001 From: vambo Date: Thu, 16 Apr 2015 15:57:15 +0200 Subject: [PATCH 0023/1665] replaceOne example syntax fix (added missing closing brace for eq) --- docs/reference/content/driver/reference/crud/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/content/driver/reference/crud/index.md b/docs/reference/content/driver/reference/crud/index.md index 6e11b83c8a7..29d389b1b4b 100644 --- a/docs/reference/content/driver/reference/crud/index.md +++ b/docs/reference/content/driver/reference/crud/index.md @@ -40,7 +40,7 @@ collection.insertOne(document); document.append("x", 2).append("y", 3); // replace a document -collection.replaceOne(Filters.eq("_id", document.get("_id"), document); +collection.replaceOne(Filters.eq("_id", document.get("_id")), document); // find documents List foundDocument = collection.find().into(new ArrayList()); From 7808d695b3dba5d7cb75d41777acf00c4560d029 Mon Sep 17 00:00:00 2001 From: fbuecklers Date: Sun, 19 Apr 2015 15:03:17 +0200 Subject: [PATCH 0024/1665] implement "$date": "2015-04-14T14:55:57.626Z" and "$date": "2015-04-14T14:55:57+02:00" extended json parsing in JsonReader --- bson/src/main/org/bson/json/JsonReader.java | 27 ++++++++++--- .../unit/org/bson/json/JsonReaderTest.java | 39 +++++++++++++++++++ 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/bson/src/main/org/bson/json/JsonReader.java b/bson/src/main/org/bson/json/JsonReader.java index 11b4fd6fd3f..3181a5ea81b 100644 --- a/bson/src/main/org/bson/json/JsonReader.java +++ b/bson/src/main/org/bson/json/JsonReader.java @@ -784,7 +784,7 @@ private BsonBinary visitHexDataConstructor() { } private long visitDateTimeConstructor() { - DateFormat df = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss z"); + DateFormat format = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss z", Locale.ENGLISH); verifyToken("("); @@ -795,7 +795,7 @@ private long visitDateTimeConstructor() { verifyToken(")"); String s = token.getValue(String.class); ParsePosition pos = new ParsePosition(0); - Date dateTime = df.parse(s, pos); + Date dateTime = format.parse(s, pos); if (dateTime != null && pos.getIndex() == s.length()) { return dateTime.getTime(); } else { @@ -870,11 +870,26 @@ private BsonBinary visitBinDataExtendedJson() { private long visitDateTimeExtendedJson() { verifyToken(":"); JsonToken valueToken = popToken(); - if (valueToken.getType() != JsonTokenType.INT32 && valueToken.getType() != JsonTokenType.INT64) { - throw new JsonParseException("JSON reader expected an integer but found '%s'.", valueToken.getValue()); - } verifyToken("}"); - return valueToken.getValue(Long.class); + + if (valueToken.getType() == JsonTokenType.INT32 || valueToken.getType() == JsonTokenType.INT64) { + return valueToken.getValue(Long.class); + } else if (valueToken.getType() == JsonTokenType.STRING) { + String dateString = valueToken.getValue(String.class); + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH); + ParsePosition pos = new ParsePosition(0); + format.setLenient(true); + + Date date = format.parse(dateString, pos); + + if (date != null && pos.getIndex() == dateString.length()) { + return date.getTime(); + } + + throw new JsonParseException("JSON reader expected an ISO-8601 date string but found.", dateString); + } else { + throw new JsonParseException("JSON reader expected an integer or string but found '%s'.", valueToken.getValue()); + } } private MaxKey visitMaxKeyExtendedJson() { diff --git a/bson/src/test/unit/org/bson/json/JsonReaderTest.java b/bson/src/test/unit/org/bson/json/JsonReaderTest.java index 727194fd880..a64664e5649 100644 --- a/bson/src/test/unit/org/bson/json/JsonReaderTest.java +++ b/bson/src/test/unit/org/bson/json/JsonReaderTest.java @@ -127,6 +127,45 @@ public void testDateTimeStrict() { assertEquals(AbstractBsonReader.State.DONE, bsonReader.getState()); } + @Test + public void testDateTimeISOString() { + String json = "{ \"$date\" : \"2015-04-16T14:55:57.626Z\" }"; + bsonReader = new JsonReader(json); + assertEquals(BsonType.DATE_TIME, bsonReader.readBsonType()); + assertEquals(1429196157626L, bsonReader.readDateTime()); + assertEquals(AbstractBsonReader.State.DONE, bsonReader.getState()); + } + + @Test + public void testDateTimeISOStringWithTimeOffset() { + String json = "{ \"$date\" : \"2015-04-16T16:55:57.626+02:00\" }"; + bsonReader = new JsonReader(json); + assertEquals(BsonType.DATE_TIME, bsonReader.readBsonType()); + assertEquals(1429196157626L, bsonReader.readDateTime()); + assertEquals(AbstractBsonReader.State.DONE, bsonReader.getState()); + } + + @Test(expected = JsonParseException.class) + public void testInvalidDateTimeISOString1() { + String json = "{ \"$date\" : \"2015-04-16T16:55:57.626+02:000\" }"; + bsonReader = new JsonReader(json); + bsonReader.readBsonType(); + } + + @Test(expected = JsonParseException.class) + public void testInvalidDateTimeISOString2() { + String json = "{ \"$date\" : \"2015-04-16T16:55:57.626Z invalid string\" }"; + bsonReader = new JsonReader(json); + bsonReader.readBsonType(); + } + + @Test(expected = JsonParseException.class) + public void testInvalidDateTimeValue() { + String json = "{ \"$date\" : {} }"; + bsonReader = new JsonReader(json); + bsonReader.readBsonType(); + } + @Test public void testDateTimeTengen() { String json = "new Date(0)"; From 0f02e65b4f50b0d1bb8891678929816f5c189158 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Sun, 19 Apr 2015 16:16:19 -0400 Subject: [PATCH 0025/1665] In JsonReader, replaced SimpleDateFormat with DatatypeConverter.parseDateTime, as Java 6 does not support the 'X' pattern character. JAVA-1768 --- bson/src/main/org/bson/json/JsonReader.java | 16 +++++----------- .../test/unit/org/bson/json/JsonReaderTest.java | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/bson/src/main/org/bson/json/JsonReader.java b/bson/src/main/org/bson/json/JsonReader.java index 3181a5ea81b..9e95fc5b4c2 100644 --- a/bson/src/main/org/bson/json/JsonReader.java +++ b/bson/src/main/org/bson/json/JsonReader.java @@ -875,18 +875,12 @@ private long visitDateTimeExtendedJson() { if (valueToken.getType() == JsonTokenType.INT32 || valueToken.getType() == JsonTokenType.INT64) { return valueToken.getValue(Long.class); } else if (valueToken.getType() == JsonTokenType.STRING) { - String dateString = valueToken.getValue(String.class); - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH); - ParsePosition pos = new ParsePosition(0); - format.setLenient(true); - - Date date = format.parse(dateString, pos); - - if (date != null && pos.getIndex() == dateString.length()) { - return date.getTime(); + String dateTimeString = valueToken.getValue(String.class); + try { + return DatatypeConverter.parseDateTime(dateTimeString).getTimeInMillis(); + } catch (IllegalArgumentException e) { + throw new JsonParseException("JSON reader expected an ISO-8601 date time string but found.", dateTimeString); } - - throw new JsonParseException("JSON reader expected an ISO-8601 date string but found.", dateString); } else { throw new JsonParseException("JSON reader expected an integer or string but found '%s'.", valueToken.getValue()); } diff --git a/bson/src/test/unit/org/bson/json/JsonReaderTest.java b/bson/src/test/unit/org/bson/json/JsonReaderTest.java index a64664e5649..d32ad9287c3 100644 --- a/bson/src/test/unit/org/bson/json/JsonReaderTest.java +++ b/bson/src/test/unit/org/bson/json/JsonReaderTest.java @@ -147,7 +147,7 @@ public void testDateTimeISOStringWithTimeOffset() { @Test(expected = JsonParseException.class) public void testInvalidDateTimeISOString1() { - String json = "{ \"$date\" : \"2015-04-16T16:55:57.626+02:000\" }"; + String json = "{ \"$date\" : \"2015-04-16T16:55:57.626+02:0000\" }"; bsonReader = new JsonReader(json); bsonReader.readBsonType(); } From ea179cdf3f7e4422c2170994eddfa01ad619b2ec Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Fri, 17 Apr 2015 17:43:38 -0400 Subject: [PATCH 0026/1665] When encoding a DBObject, if a value implements both Iterable and Map, encode it as a document rather than array. This preserves compatibility with 2.x encoding behavior. JAVA-1760 --- .../src/main/com/mongodb/DBObjectCodec.java | 4 +-- .../com/mongodb/DBObjectCodecTest.java | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/driver/src/main/com/mongodb/DBObjectCodec.java b/driver/src/main/com/mongodb/DBObjectCodec.java index 845cc7b2c75..481be65f9a3 100644 --- a/driver/src/main/com/mongodb/DBObjectCodec.java +++ b/driver/src/main/com/mongodb/DBObjectCodec.java @@ -192,10 +192,10 @@ private void writeValue(final BsonWriter bsonWriter, final EncoderContext encode bsonWriter.writeNull(); } else if (value instanceof DBRef) { encodeDBRef(bsonWriter, (DBRef) value); - } else if (value instanceof Iterable) { - encodeIterable(bsonWriter, (Iterable) value); } else if (value instanceof Map) { encodeMap(bsonWriter, (Map) value); + } else if (value instanceof Iterable) { + encodeIterable(bsonWriter, (Iterable) value); } else if (value instanceof BSONObject) { encodeBsonObject(bsonWriter, ((BSONObject) value)); } else if (value instanceof CodeWScope) { diff --git a/driver/src/test/functional/com/mongodb/DBObjectCodecTest.java b/driver/src/test/functional/com/mongodb/DBObjectCodecTest.java index 140b33a6976..dd053b440a7 100644 --- a/driver/src/test/functional/com/mongodb/DBObjectCodecTest.java +++ b/driver/src/test/functional/com/mongodb/DBObjectCodecTest.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -177,4 +178,28 @@ public void shouldEncodedNestedMapsListsAndDocuments() { .append("lazyDoc", zeroOneBsonDocument) .append("lazyArray", zeroOneBsonArray), writer.getDocument()); } + + @Test + public void shouldEncodeIterableMapAsMap() { + IterableMap iterableMap = new IterableMap(); + iterableMap.put("first", 1); + + DBObjectCodec dbObjectCodec = new DBObjectCodec(fromProviders(asList(new ValueCodecProvider(), new DBObjectCodecProvider()))); + + DBObject doc = new BasicDBObject("map", iterableMap); + + BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); + dbObjectCodec.encode(writer, doc, EncoderContext.builder().build()); + + assertEquals(new BsonDocument("map", new BsonDocument("first", new BsonInt32(1))), writer.getDocument()); + } + + static class IterableMap extends HashMap implements Iterable { + private static final long serialVersionUID = -5090421898469363392L; + + @Override + public Iterator iterator() { + return values().iterator(); + } + } } From fa60415971bd69a1e4cfbfc57fdfa1ca17ec329b Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Fri, 17 Apr 2015 17:54:51 -0400 Subject: [PATCH 0027/1665] When encoding a Document, encode all Iterable instances as BSON arrays, rather than just List instances. This is consistent with the behavior of the DBObject encoder, so this will make it easier to migrate from DBObject to Document JAVA-1761 --- bson/src/main/org/bson/codecs/DocumentCodec.java | 6 +++--- .../test/unit/org/bson/codecs/DocumentCodecTest.java | 11 ++++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bson/src/main/org/bson/codecs/DocumentCodec.java b/bson/src/main/org/bson/codecs/DocumentCodec.java index 85a279966b4..46f0df26c9b 100644 --- a/bson/src/main/org/bson/codecs/DocumentCodec.java +++ b/bson/src/main/org/bson/codecs/DocumentCodec.java @@ -166,8 +166,8 @@ private boolean skipField(final EncoderContext encoderContext, final String key) private void writeValue(final BsonWriter writer, final EncoderContext encoderContext, final Object value) { if (value == null) { writer.writeNull(); - } else if (List.class.isAssignableFrom(value.getClass())) { - writeList(writer, (List) value, encoderContext.getChildContext()); + } else if (Iterable.class.isAssignableFrom(value.getClass())) { + writeIterable(writer, (Iterable) value, encoderContext.getChildContext()); } else if (Map.class.isAssignableFrom(value.getClass())) { writeMap(writer, (Map) value, encoderContext.getChildContext()); } else { @@ -191,7 +191,7 @@ private void writeMap(final BsonWriter writer, final Map map, fi writer.writeEndDocument(); } - private void writeList(final BsonWriter writer, final List list, final EncoderContext encoderContext) { + private void writeIterable(final BsonWriter writer, final Iterable list, final EncoderContext encoderContext) { writer.writeStartArray(); for (final Object value : list) { writeValue(writer, encoderContext, value); diff --git a/bson/src/test/unit/org/bson/codecs/DocumentCodecTest.java b/bson/src/test/unit/org/bson/codecs/DocumentCodecTest.java index 58aa4b81a78..10066accac3 100644 --- a/bson/src/test/unit/org/bson/codecs/DocumentCodecTest.java +++ b/bson/src/test/unit/org/bson/codecs/DocumentCodecTest.java @@ -40,6 +40,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.Date; +import java.util.HashSet; import java.util.List; import static java.util.Arrays.asList; @@ -90,14 +91,18 @@ public void testPrimitiveBSONTypeCodecs() throws IOException { @Test public void testIterableEncoding() throws IOException { DocumentCodec documentCodec = new DocumentCodec(); - Document doc = new Document(); - doc.put("array", asList(1, 2, 3, 4, 5)); + Document doc = new Document() + .append("list", asList(1, 2, 3, 4, 5)) + .append("set", new HashSet(asList(1, 2, 3, 4))); documentCodec.encode(writer, doc, EncoderContext.builder().build()); BsonInput bsonInput = createInputBuffer(); Document decodedDocument = documentCodec.decode(new BsonBinaryReader(bsonInput), DecoderContext.builder().build()); - assertEquals(doc, decodedDocument); + assertEquals(new Document() + .append("list", asList(1, 2, 3, 4, 5)) + .append("set", asList(1, 2, 3, 4)), + decodedDocument); } @Test From dd5b36bfd1aa63d893edfe4f024fd4831bc2d0fb Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Sat, 18 Apr 2015 07:01:42 -0400 Subject: [PATCH 0028/1665] When selecting a server that satisifies a read preference, select any ok server when cluster connection mode is SINGLE. JAVA-1767 --- .../ReadPreferenceServerSelector.java | 6 +- ...eferenceServerSelectorSpecification.groovy | 75 +++++++++++++++++++ .../ReadPreferenceServerSelectorTest.java | 58 -------------- 3 files changed, 80 insertions(+), 59 deletions(-) create mode 100644 driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorSpecification.groovy delete mode 100644 driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorTest.java diff --git a/driver-core/src/main/com/mongodb/selector/ReadPreferenceServerSelector.java b/driver-core/src/main/com/mongodb/selector/ReadPreferenceServerSelector.java index 607c9db68f5..2682ac63344 100644 --- a/driver-core/src/main/com/mongodb/selector/ReadPreferenceServerSelector.java +++ b/driver-core/src/main/com/mongodb/selector/ReadPreferenceServerSelector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2014 MongoDB, Inc. + * Copyright 2008-2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.mongodb.selector; import com.mongodb.ReadPreference; +import com.mongodb.connection.ClusterConnectionMode; import com.mongodb.connection.ClusterDescription; import com.mongodb.connection.ServerDescription; @@ -52,6 +53,9 @@ public ReadPreference getReadPreference() { @Override public List select(final ClusterDescription clusterDescription) { + if (clusterDescription.getConnectionMode() == ClusterConnectionMode.SINGLE) { + return clusterDescription.getAny(); + } return readPreference.choose(clusterDescription); } diff --git a/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorSpecification.groovy b/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorSpecification.groovy new file mode 100644 index 00000000000..1bc25201671 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorSpecification.groovy @@ -0,0 +1,75 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.selector + +import com.mongodb.ServerAddress +import com.mongodb.connection.ClusterDescription +import com.mongodb.connection.ServerDescription +import com.mongodb.connection.ServerType +import spock.lang.Specification + +import static com.mongodb.ReadPreference.primary +import static com.mongodb.ReadPreference.secondary +import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE +import static com.mongodb.connection.ClusterConnectionMode.SINGLE +import static com.mongodb.connection.ClusterType.REPLICA_SET +import static com.mongodb.connection.ServerConnectionState.CONNECTED + +class ReadPreferenceServerSelectorSpecification extends Specification { + + def primary = ServerDescription.builder() + .state(CONNECTED) + .address(new ServerAddress()) + .ok(true) + .type(ServerType.REPLICA_SET_PRIMARY) + .build(); + def secondary = ServerDescription.builder() + .state(CONNECTED) + .address(new ServerAddress('localhost', 27018)) + .ok(true) + .type(ServerType.REPLICA_SET_SECONDARY) + .build(); + + def 'constructor should throws if read preference is null'() { + when: + new ReadPreferenceServerSelector(null) + + then: + thrown(IllegalArgumentException) + } + + def 'should get read preference'() { + expect: + new ReadPreferenceServerSelector(primary()).readPreference == primary() + } + + def 'should override toString'() { + expect: + new ReadPreferenceServerSelector(primary()).toString() == 'ReadPreferenceServerSelector{readPreference=primary}' + } + + def 'should select server that matches read preference when connection mode is multiple'() { + expect: + new ReadPreferenceServerSelector(primary()).select(new ClusterDescription(MULTIPLE, REPLICA_SET, [primary, secondary])) == + [primary] + new ReadPreferenceServerSelector(secondary()).select(new ClusterDescription(MULTIPLE, REPLICA_SET, [primary, secondary])) == + [secondary] + } + + def 'should select any ok server when connection mode is single'() { + expect: + new ReadPreferenceServerSelector(primary()).select(new ClusterDescription(SINGLE, REPLICA_SET, [secondary])) == [secondary] + } +} diff --git a/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorTest.java b/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorTest.java deleted file mode 100644 index 0175c631557..00000000000 --- a/driver-core/src/test/unit/com/mongodb/selector/ReadPreferenceServerSelectorTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2008-2014 MongoDB, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.mongodb.selector; - -import com.mongodb.ReadPreference; -import com.mongodb.ServerAddress; -import com.mongodb.connection.ClusterDescription; -import com.mongodb.connection.ServerDescription; -import com.mongodb.connection.ServerType; -import org.junit.Test; - -import java.net.UnknownHostException; - -import static com.mongodb.connection.ClusterConnectionMode.MULTIPLE; -import static com.mongodb.connection.ClusterType.REPLICA_SET; -import static com.mongodb.connection.ServerConnectionState.CONNECTED; -import static java.util.Arrays.asList; -import static org.junit.Assert.assertEquals; - -public class ReadPreferenceServerSelectorTest { - @Test - public void testAll() throws UnknownHostException { - ReadPreferenceServerSelector selector = new ReadPreferenceServerSelector(ReadPreference.primary()); - - assertEquals(ReadPreference.primary(), selector.getReadPreference()); - - assertEquals("ReadPreferenceServerSelector{readPreference=primary}", selector.toString()); - - ServerDescription primary = ServerDescription.builder() - .state(CONNECTED) - .address(new ServerAddress()) - .ok(true) - .type(ServerType.REPLICA_SET_PRIMARY) - .build(); - ServerDescription secondary = ServerDescription.builder() - .state(CONNECTED) - .address(new ServerAddress()) - .ok(true) - .type(ServerType.REPLICA_SET_SECONDARY) - .build(); - assertEquals(asList(primary), selector.select(new ClusterDescription(MULTIPLE, REPLICA_SET, asList(primary, secondary)))); - } -} - From 0831e9bc5a09d0e15fce268ec9210060ba27f4c7 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 7 Apr 2015 09:09:28 -0400 Subject: [PATCH 0029/1665] Added GeoJson object model with enough functionality for use as query filters Added GeoJson object model codecs (with only encoding support initially) Added geoWithin and geoIntersects factory methods to Filters class Added near and nearSphere factory methods to Filters class Added geoWithinBox, geoWithinPolygon, geoWithinCenter, and getWithinCenterSphere factory methodsto Filters class Added GeoJsonCodecProvider to default codec registry in com.mongodb.MongoClient and com.mongodb.async.client.MongoClientImpl JAVA-1664 --- .../mongodb/async/client/MongoClientImpl.java | 5 +- .../client/MongoClientSpecification.groovy | 15 + .../com/mongodb/client/model/Filters.java | 313 ++++++++++++++- .../geojson/CoordinateReferenceSystem.java | 35 ++ .../CoordinateReferenceSystemType.java | 49 +++ .../model/geojson/GeoJsonObjectType.java | 74 ++++ .../client/model/geojson/Geometry.java | 114 ++++++ .../model/geojson/GeometryCollection.java | 103 +++++ .../client/model/geojson/LineString.java | 108 ++++++ .../client/model/geojson/MultiLineString.java | 110 ++++++ .../client/model/geojson/MultiPoint.java | 106 +++++ .../client/model/geojson/MultiPolygon.java | 103 +++++ .../NamedCoordinateReferenceSystem.java | 106 +++++ .../mongodb/client/model/geojson/Point.java | 107 ++++++ .../mongodb/client/model/geojson/Polygon.java | 131 +++++++ .../model/geojson/PolygonCoordinates.java | 112 ++++++ .../client/model/geojson/Position.java | 103 +++++ .../geojson/codecs/GeoJsonCodecProvider.java | 60 +++ .../geojson/codecs/GeometryCodecHelper.java | 89 +++++ .../codecs/GeometryCollectionCodec.java | 79 ++++ .../model/geojson/codecs/LineStringCodec.java | 71 ++++ .../geojson/codecs/MultiLineStringCodec.java | 77 ++++ .../model/geojson/codecs/MultiPointCodec.java | 71 ++++ .../geojson/codecs/MultiPolygonCodec.java | 71 ++++ .../NamedCoordinateReferenceSystemCodec.java | 52 +++ .../model/geojson/codecs/PointCodec.java | 68 ++++ .../model/geojson/codecs/PolygonCodec.java | 68 ++++ .../model/geojson/codecs/package-info.java | 20 + .../client/model/geojson/package-info.java | 20 + .../GeoFiltersFunctionalSpecification.groovy | 77 ++++ ...oJsonFiltersFunctionalSpecification.groovy | 81 ++++ .../mongodb/client/test/CollectionHelper.java | 7 +- .../client/model/FiltersSpecification.groovy | 362 +++++++++++++++++- .../GeometryCollectionSpecification.groovy | 54 +++ .../geojson/LineStringSpecification.groovy | 77 ++++ .../MultiLineStringSpecification.groovy | 72 ++++ .../geojson/MultiPointSpecification.groovy | 71 ++++ .../geojson/MultiPolygonSpecification.groovy | 76 ++++ .../model/geojson/PointSpecification.groovy | 62 +++ .../model/geojson/PolygonSpecification.groovy | 90 +++++ .../geojson/PositionSpecification.groovy | 71 ++++ ...eometryCollectionCodecSpecification.groovy | 69 ++++ .../LineStringCodecSpecification.groovy | 63 +++ .../MultiLineStringCodecSpecification.groovy | 64 ++++ .../MultiPointCodecSpecification.groovy | 63 +++ .../MultiPolygonCodecSpecification.groovy | 87 +++++ .../codecs/PointCodecSpecification.groovy | 58 +++ .../codecs/PolygonCodecSpecification.groovy | 91 +++++ driver/src/main/com/mongodb/MongoClient.java | 5 +- .../mongodb/MongoClientSpecification.groovy | 35 ++ 50 files changed, 4061 insertions(+), 14 deletions(-) create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystem.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystemType.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/GeoJsonObjectType.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/Geometry.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/GeometryCollection.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/LineString.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/MultiLineString.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/MultiPoint.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/MultiPolygon.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/NamedCoordinateReferenceSystem.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/Point.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/Polygon.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/PolygonCoordinates.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/Position.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeoJsonCodecProvider.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCodecHelper.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/LineStringCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiLineStringCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPointCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPolygonCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/NamedCoordinateReferenceSystemCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/PointCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/PolygonCodec.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/codecs/package-info.java create mode 100644 driver-core/src/main/com/mongodb/client/model/geojson/package-info.java create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/GeoFiltersFunctionalSpecification.groovy create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/GeoJsonFiltersFunctionalSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/GeometryCollectionSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/LineStringSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiLineStringSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPointSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPolygonSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/PointSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/PolygonSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/PositionSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/LineStringCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiLineStringCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPointCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPolygonCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PointCodecSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PolygonCodecSpecification.groovy create mode 100644 driver/src/test/unit/com/mongodb/MongoClientSpecification.groovy diff --git a/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java b/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java index 5a7f3be52cc..3a11318aec3 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java @@ -23,6 +23,7 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.AsyncReadWriteBinding; import com.mongodb.binding.AsyncWriteBinding; +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import com.mongodb.connection.Cluster; import com.mongodb.operation.AsyncOperationExecutor; import com.mongodb.operation.AsyncReadOperation; @@ -46,7 +47,8 @@ class MongoClientImpl implements MongoClient { private static final CodecRegistry DEFAULT_CODEC_REGISTRY = fromProviders(asList(new ValueCodecProvider(), new DocumentCodecProvider(), - new BsonValueCodecProvider())); + new BsonValueCodecProvider(), + new GeoJsonCodecProvider())); /** * Gets the default codec registry. It includes the following providers: @@ -55,6 +57,7 @@ class MongoClientImpl implements MongoClient { *
  • {@link org.bson.codecs.ValueCodecProvider}
  • *
  • {@link org.bson.codecs.DocumentCodecProvider}
  • *
  • {@link org.bson.codecs.BsonValueCodecProvider}
  • + *
  • {@link com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider}
  • * * * @return the default codec registry diff --git a/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy index a52fb7749a1..84c0bc7302f 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy @@ -17,6 +17,7 @@ package com.mongodb.async.client import com.mongodb.WriteConcern +import com.mongodb.client.model.geojson.MultiPolygon import com.mongodb.connection.Cluster import org.bson.BsonDocument import org.bson.Document @@ -86,4 +87,18 @@ class MongoClientSpecification extends Specification { WriteConcern.MAJORITY, new TestOperationExecutor([])) } + def 'default codec registry should contain all supported providers'() { + given: + def settings = MongoClientSettings.builder().build() + def cluster = Stub(Cluster) + def executor = new TestOperationExecutor([null, null, null]) + def client = new MongoClientImpl(settings, cluster, executor) + def codecRegistry = client.getDefaultCodecRegistry() + + expect: + codecRegistry.get(BsonDocument) + codecRegistry.get(Document) + codecRegistry.get(Integer) + codecRegistry.get(MultiPolygon) + } } diff --git a/driver-core/src/main/com/mongodb/client/model/Filters.java b/driver-core/src/main/com/mongodb/client/model/Filters.java index 54dc8dec069..0f3afdcd197 100644 --- a/driver-core/src/main/com/mongodb/client/model/Filters.java +++ b/driver-core/src/main/com/mongodb/client/model/Filters.java @@ -16,10 +16,13 @@ package com.mongodb.client.model; +import com.mongodb.client.model.geojson.Geometry; +import com.mongodb.client.model.geojson.Point; import org.bson.BsonArray; import org.bson.BsonBoolean; import org.bson.BsonDocument; import org.bson.BsonDocumentWriter; +import org.bson.BsonDouble; import org.bson.BsonInt32; import org.bson.BsonInt64; import org.bson.BsonRegularExpression; @@ -31,6 +34,8 @@ import org.bson.codecs.configuration.CodecRegistry; import org.bson.conversions.Bson; +import java.util.Arrays; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -485,10 +490,266 @@ public static Bson size(final String fieldName, final int size) { return new OperatorFilter("$size", fieldName, size); } - // TODO: $geoWithin - // TODO: $geoIntersects - // TODO: $near - // TODO: $nearSphere + /** + * Creates a filter that matches all documents containing a field with geospatial data that exists entirely within the specified shape. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.server.release 2.4 + */ + public static Bson geoWithin(final String fieldName, final Geometry geometry) { + return new GeometryOperatorFilter("$geoWithin", fieldName, geometry); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that exists entirely within the specified shape. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.server.release 2.4 + */ + public static Bson geoWithin(final String fieldName, final Bson geometry) { + return new GeometryOperatorFilter("$geoWithin", fieldName, geometry); + } + + /** + * Creates a filter that matches all documents containing a field with grid coordinates data that exist entirely within the specified + * box. + * + * @param fieldName the field name + * @param lowerLeftX the lower left x coordinate of the box + * @param lowerLeftY the lower left y coordinate of the box + * @param upperRightX the upper left x coordinate of the box + * @param upperRightY the upper left y coordinate of the box + * @return the filter + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.driver.manual reference/operator/query/box/#op._S_box $box + * @mongodb.server.release 2.4 + * @since 3.1 + */ + public static Bson geoWithinBox(final String fieldName, final double lowerLeftX, final double lowerLeftY, final double upperRightX, + final double upperRightY) { + BsonDocument box = new BsonDocument("$box", + new BsonArray(asList(new BsonArray(asList(new BsonDouble(lowerLeftX), + new BsonDouble(lowerLeftY))), + new BsonArray(asList(new BsonDouble(upperRightX), + new BsonDouble(upperRightY)))))); + return new OperatorFilter("$geoWithin", fieldName, box); + } + + /** + * Creates a filter that matches all documents containing a field with grid coordinates data that exist entirely within the specified + * polygon. + * + * @param fieldName the field name + * @param points a list of pairs of x, y coordinates. Any extra dimensions are ignored + * @return the filter + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.driver.manual reference/operator/query/polygon/#op._S_polygon $polygon + * @mongodb.server.release 2.4 + * @since 3.1 + */ + public static Bson geoWithinPolygon(final String fieldName, final List> points) { + BsonArray pointsArray = new BsonArray(); + for (List point : points) { + pointsArray.add(new BsonArray(asList(new BsonDouble(point.get(0)), new BsonDouble(point.get(1))))); + } + BsonDocument polygon = new BsonDocument("$polygon", pointsArray); + return new OperatorFilter("$geoWithin", fieldName, polygon); + } + + /** + * Creates a filter that matches all documents containing a field with grid coordinates data that exist entirely within the specified + * circle. + * + * @param fieldName the field name + * @param x the x coordinate of the circle + * @param y the y coordinate of the circle + * @param radius the radius of the circle, as measured in the units used by the coordinate system + * @return the filter + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.driver.manual reference/operator/query/center/#op._S_center $center + * @mongodb.server.release 2.4 + * @since 3.1 + */ + public static Bson geoWithinCenter(final String fieldName, final double x, final double y, final double radius) { + BsonDocument center = new BsonDocument("$center", + new BsonArray(Arrays.asList(new BsonArray(asList(new BsonDouble(x), + new BsonDouble(y))), + new BsonDouble(radius)))); + return new OperatorFilter("$geoWithin", fieldName, center); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data (GeoJSON or legacy coordinate pairs) that exist + * entirely within the specified circle, using spherical geometry. If using longitude and latitude, specify longitude first. + * + * @param fieldName the field name + * @param x the x coordinate of the circle + * @param y the y coordinate of the circle + * @param radius the radius of the circle, in radians + * @return the filter + * @mongodb.driver.manual reference/operator/query/geoWithin/ $geoWithin + * @mongodb.driver.manual reference/operator/query/centerSphere/#op._S_centerSphere $centerSphere + * @mongodb.server.release 2.4 + * @since 3.1 + */ + public static Bson geoWithinCenterSphere(final String fieldName, final double x, final double y, final double radius) { + BsonDocument centerSphere = new BsonDocument("$centerSphere", + new BsonArray(Arrays.asList(new BsonArray(asList(new BsonDouble(x), + new BsonDouble(y))), + new BsonDouble(radius)))); + return new OperatorFilter("$geoWithin", fieldName, centerSphere); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that intersects with the specified shape. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/geoIntersects/ $geoIntersects + * @mongodb.server.release 2.4 + */ + public static Bson geoIntersects(final String fieldName, final Bson geometry) { + return new GeometryOperatorFilter("$geoIntersects", fieldName, geometry); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that intersects with the specified shape. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/geoIntersects/ $geoIntersects + * @mongodb.server.release 2.4 + */ + public static Bson geoIntersects(final String fieldName, final Geometry geometry) { + return new GeometryOperatorFilter("$geoIntersects", fieldName, geometry); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified GeoJSON point. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @param maxDistance the maximum distance from the point, in meters + * @param minDistance the minimum distance from the point, in meters + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson near(final String fieldName, final Point geometry, final Double maxDistance, final Double minDistance) { + return new GeometryOperatorFilter("$near", fieldName, geometry, maxDistance, minDistance); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified GeoJSON point. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @param maxDistance the maximum distance from the point, in meters + * @param minDistance the minimum distance from the point, in meters + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson near(final String fieldName, final Bson geometry, final Double maxDistance, final Double minDistance) { + return new GeometryOperatorFilter("$near", fieldName, geometry, maxDistance, minDistance); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified point. + * + * @param fieldName the field name + * @param x the x coordinate + * @param y the y coordinate + * @param maxDistance the maximum distance from the point, in radians + * @param minDistance the minimum distance from the point, in radians + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson near(final String fieldName, final double x, final double y, final Double maxDistance, final Double minDistance) { + return createNearFilterDocument(fieldName, x, y, maxDistance, minDistance, "$near"); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified GeoJSON point using + * spherical geometry. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @param maxDistance the maximum distance from the point, in meters + * @param minDistance the minimum distance from the point, in meters + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson nearSphere(final String fieldName, final Point geometry, final Double maxDistance, final Double minDistance) { + return new GeometryOperatorFilter("$nearSphere", fieldName, geometry, maxDistance, minDistance); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified GeoJSON point using + * spherical geometry. + * + * @param fieldName the field name + * @param geometry the bounding GeoJSON geometry object + * @param maxDistance the maximum distance from the point, in meters + * @param minDistance the minimum distance from the point, in meters + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson nearSphere(final String fieldName, final Bson geometry, final Double maxDistance, final Double minDistance) { + return new GeometryOperatorFilter("$nearSphere", fieldName, geometry, maxDistance, minDistance); + } + + /** + * Creates a filter that matches all documents containing a field with geospatial data that is near the specified point using + * spherical geometry. + * + * @param fieldName the field name + * @param x the x coordinate + * @param y the y coordinate + * @param maxDistance the maximum distance from the point, in radians + * @param minDistance the minimum distance from the point, in radians + * @return the filter + * @since 3.1 + * @mongodb.driver.manual reference/operator/query/near/ $near + * @mongodb.server.release 2.4 + */ + public static Bson nearSphere(final String fieldName, final double x, final double y, final Double maxDistance, + final Double minDistance) { + return createNearFilterDocument(fieldName, x, y, maxDistance, minDistance, "$nearSphere"); + } + + private static Bson createNearFilterDocument(final String fieldName, final double x, final double y, final Double maxDistance, + final Double minDistance, final String operator) { + BsonDocument nearFilter = new BsonDocument(operator, new BsonArray(Arrays.asList(new BsonDouble(x), new BsonDouble(y)))); + if (maxDistance != null) { + nearFilter.append("$maxDistance", new BsonDouble(maxDistance)); + } + if (minDistance != null) { + nearFilter.append("$minDistance", new BsonDouble(minDistance)); + } + return new BsonDocument(fieldName, nearFilter); + } + private static final class SimpleFilter implements Bson { private final String fieldName; @@ -712,4 +973,48 @@ private BsonDocument createFilter(final String fieldName, final BsonValue value) } } + + private static class GeometryOperatorFilter implements Bson { + private final String operatorName; + private final String fieldName; + private final TItem geometry; + private final Double maxDistance; + private final Double minDistance; + + public GeometryOperatorFilter(final String operatorName, final String fieldName, final TItem geometry) { + this(operatorName, fieldName, geometry, null, null); + } + + public GeometryOperatorFilter(final String operatorName, final String fieldName, final TItem geometry, + final Double maxDistance, final Double minDistance) { + this.operatorName = operatorName; + this.fieldName = notNull("fieldName", fieldName); + this.geometry = notNull("geometry", geometry); + this.maxDistance = maxDistance; + this.minDistance = minDistance; + } + + @Override + public BsonDocument toBsonDocument(final Class documentClass, final CodecRegistry codecRegistry) { + BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); + writer.writeStartDocument(); + writer.writeName(fieldName); + writer.writeStartDocument(); + writer.writeName(operatorName); + writer.writeStartDocument(); + writer.writeName("$geometry"); + encodeValue(writer, geometry, codecRegistry); + if (maxDistance != null) { + writer.writeDouble("$maxDistance", maxDistance); + } + if (minDistance != null) { + writer.writeDouble("$minDistance", minDistance); + }writer.writeEndDocument(); + writer.writeEndDocument(); + writer.writeEndDocument(); + + return writer.getDocument(); + } + } + } diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystem.java b/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystem.java new file mode 100644 index 00000000000..4005728f8ff --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystem.java @@ -0,0 +1,35 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import com.mongodb.annotations.Immutable; + +/** + * A GeoJSON Coordinate Reference System (CRS). + * + * @since 3.1 + */ +@Immutable +public abstract class CoordinateReferenceSystem { + + /** + * Gets the type of this Coordinate Reference System. + * + * @return the type + */ + public abstract CoordinateReferenceSystemType getType(); +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystemType.java b/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystemType.java new file mode 100644 index 00000000000..2404a633cd1 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/CoordinateReferenceSystemType.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +/** + * An enumeration of the GeoJSON coordinate reference system types. + * + * @since 3.1 + */ +public enum CoordinateReferenceSystemType { + /** + * A coordinate reference system that is specifed by name + */ + NAME("name"), + + /** + * A coordinate reference system that is specifed by a dereferenceable URI + */ + LINK("link"); + + /** + * Gets the GeoJSON-defined name for the type. + * + * @return the GeoJSON-defined type name + */ + public String getTypeName() { + return typeName; + } + + private final String typeName; + + CoordinateReferenceSystemType(final String typeName) { + this.typeName = typeName; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/GeoJsonObjectType.java b/driver-core/src/main/com/mongodb/client/model/geojson/GeoJsonObjectType.java new file mode 100644 index 00000000000..1411b514031 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/GeoJsonObjectType.java @@ -0,0 +1,74 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +/** + * An enumeration of GeoJSON object types. + * + * @since 3.1 + */ +public enum GeoJsonObjectType { + /** + * A GeometryCollection + */ + GEOMETRY_COLLECTION("GeometryCollection"), + + /** + * A LineString + */ + LINE_STRING("LineString"), + + /** + * A MultiLineString + */ + MULTI_LINE_STRING("MultiLineString"), + + /** + * A MultiPoint + */ + MULTI_POINT("MultiPoint"), + + /** + * A MultiPolygon + */ + MULTI_POLYGON("MultiPolygon"), + + /** + * A Point + */ + POINT("Point"), + + /** + * A Polygon + */ + POLYGON("Polygon"); + + /** + * Gets the GeoJSON-defined name for the object type. + * + * @return the GeoJSON-defined type name + */ + public String getTypeName() { + return typeName; + } + + private final String typeName; + + GeoJsonObjectType(final String typeName) { + this.typeName = typeName; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/Geometry.java b/driver-core/src/main/com/mongodb/client/model/geojson/Geometry.java new file mode 100644 index 00000000000..4162d2c9376 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/Geometry.java @@ -0,0 +1,114 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; +import org.bson.codecs.Codec; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistries; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.json.JsonWriter; +import org.bson.json.JsonWriterSettings; + +import java.io.StringWriter; + +/** + * An abstract class for representations of GeoJSON geometry objects. + * + * @since 3.1 + */ +public abstract class Geometry { + + private static final CodecRegistry REGISTRY = CodecRegistries.fromProviders(new GeoJsonCodecProvider()); + + private final CoordinateReferenceSystem coordinateReferenceSystem; + + /** + * Construct an instance with no specified coordinate reference system. + * + */ + protected Geometry() { + this(null); + } + + /** + * Construct an instance with the specified coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + */ + protected Geometry(final CoordinateReferenceSystem coordinateReferenceSystem) { + this.coordinateReferenceSystem = coordinateReferenceSystem; + } + + /** + * Gets the GeoJSON object type. + * + * @return the type + */ + public abstract GeoJsonObjectType getType(); + + /** + * Converts to GeoJSON representation + * + * @return the GeoJSON representation + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public String toJson() { + StringWriter stringWriter = new StringWriter(); + JsonWriter writer = new JsonWriter(stringWriter, new JsonWriterSettings()); + Codec codec = getRegistry().get(getClass()); + codec.encode(writer, this, EncoderContext.builder().build()); + return stringWriter.toString(); + } + + static CodecRegistry getRegistry() { + return REGISTRY; + } + + /** + * Gets the coordinate reference system, which may be null + * + * @return the possibly-null coordinate reference system + */ + public CoordinateReferenceSystem getCoordinateReferenceSystem() { + return coordinateReferenceSystem; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Geometry geometry = (Geometry) o; + + if (coordinateReferenceSystem != null ? !coordinateReferenceSystem.equals(geometry.coordinateReferenceSystem) + : geometry.coordinateReferenceSystem != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return coordinateReferenceSystem != null ? coordinateReferenceSystem.hashCode() : 0; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/GeometryCollection.java b/driver-core/src/main/com/mongodb/client/model/geojson/GeometryCollection.java new file mode 100644 index 00000000000..00e31b6418c --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/GeometryCollection.java @@ -0,0 +1,103 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON GeometryCollection. + * + * @since 3.1 + */ +public final class GeometryCollection extends Geometry { + private final List geometries; + + /** + * Construct an instance with the given list of Geometry objects + * + * @param geometries the list of Geometry objects + */ + public GeometryCollection(final List geometries) { + this(null, geometries); + } + + /** + * Construct an instance with the given list of Geometry objects + * + * @param coordinateReferenceSystem the coordinate reference system + * @param geometries the list of Geometry objects + */ + public GeometryCollection(final CoordinateReferenceSystem coordinateReferenceSystem, + final List geometries) { + super(coordinateReferenceSystem); + notNull("geometries", geometries); + isTrueArgument("geometries contains only non-null elements", !geometries.contains(null)); + this.geometries = Collections.unmodifiableList(geometries); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.GEOMETRY_COLLECTION; + } + + /** + * Gets the list of Geometry objects in this collection. + * + * @return the list + */ + public List getGeometries() { + return geometries; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + GeometryCollection that = (GeometryCollection) o; + + if (!geometries.equals(that.geometries)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + geometries.hashCode(); + return result; + } + + @Override + public String toString() { + return "GeometryCollection{" + + "geometries=" + geometries + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/LineString.java b/driver-core/src/main/com/mongodb/client/model/geojson/LineString.java new file mode 100644 index 00000000000..2afbfd8a85e --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/LineString.java @@ -0,0 +1,108 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON LineString. + * + * @since 3.1 + */ +public final class LineString extends Geometry { + + private final List coordinates; + + /** + * Construct an instance with the given coordinates. + * + * @param coordinates the coordinates + */ + public LineString(final List coordinates) { + this(null, coordinates); + } + + /** + * Construct an instance with the given coordinates and coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinates the coordinates + */ + public LineString(final CoordinateReferenceSystem coordinateReferenceSystem, + final List coordinates) { + super(coordinateReferenceSystem); + notNull("coordinates", coordinates); + isTrueArgument("coordinates must contain at least two positions", coordinates.size() >= 2); + isTrueArgument("coordinates contains only non-null positions", !coordinates.contains(null)); + + this.coordinates = Collections.unmodifiableList(coordinates); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.LINE_STRING; + } + + /** + * Gets the GeoJSON coordinates of this LineString. + * + * @return the coordinates + */ + public List getCoordinates() { + return coordinates; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + LineString lineString = (LineString) o; + + if (!coordinates.equals(lineString.coordinates)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + return 31 * result + coordinates.hashCode(); + } + + @Override + public String toString() { + return "LineString{" + + "coordinates=" + coordinates + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/MultiLineString.java b/driver-core/src/main/com/mongodb/client/model/geojson/MultiLineString.java new file mode 100644 index 00000000000..ea4a9049413 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/MultiLineString.java @@ -0,0 +1,110 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON MultiLineString. + * + * @since 3.1 + */ +public final class MultiLineString extends Geometry { + + private final List> coordinates; + + /** + * Construct an instance with the given coordinates. + * + * @param coordinates the coordinates of each line + */ + public MultiLineString(final List> coordinates) { + this(null, coordinates); + } + + /** + * Construct an instance with the given coordinates and coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinates the coordinates of each line + */ + public MultiLineString(final CoordinateReferenceSystem coordinateReferenceSystem, final List> coordinates) { + super(coordinateReferenceSystem); + + notNull("coordinates", coordinates); + + for (List line : coordinates) { + notNull("line", line); + isTrueArgument("line contains only non-null positions", !line.contains(null)); + } + + this.coordinates = Collections.unmodifiableList(coordinates); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.MULTI_LINE_STRING; + } + + /** + * Gets the GeoJSON coordinates of this MultiLineString + * + * @return the coordinates + */ + public List> getCoordinates() { + return coordinates; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + MultiLineString polygon = (MultiLineString) o; + + if (!coordinates.equals(polygon.coordinates)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + coordinates.hashCode(); + return result; + } + + @Override + public String toString() { + return "MultiLineString{" + + "coordinates=" + coordinates + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/MultiPoint.java b/driver-core/src/main/com/mongodb/client/model/geojson/MultiPoint.java new file mode 100644 index 00000000000..da9138ac1dd --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/MultiPoint.java @@ -0,0 +1,106 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON MultiPoint. + * + * @since 3.1 + */ +public final class MultiPoint extends Geometry { + + private final List coordinates; + + /** + * Construct an instance with the given coordinates. + * + * @param coordinates the coordinates + */ + public MultiPoint(final List coordinates) { + this(null, coordinates); + } + + /** + * Construct an instance with the given coordinates and coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinates the coordinates + */ + public MultiPoint(final CoordinateReferenceSystem coordinateReferenceSystem, final List coordinates) { + super(coordinateReferenceSystem); + notNull("coordinates", coordinates); + isTrueArgument("coordinates contains only non-null positions", !coordinates.contains(null)); + + this.coordinates = Collections.unmodifiableList(coordinates); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.MULTI_POINT; + } + + /** + * Gets the GeoJSON coordinates of this MultiPoint. + * + * @return the coordinates + */ + public List getCoordinates() { + return coordinates; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + MultiPoint multiPoint = (MultiPoint) o; + + if (!coordinates.equals(multiPoint.coordinates)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + return 31 * result + coordinates.hashCode(); + } + + @Override + public String toString() { + return "MultiPoint{" + + "coordinates=" + coordinates + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/MultiPolygon.java b/driver-core/src/main/com/mongodb/client/model/geojson/MultiPolygon.java new file mode 100644 index 00000000000..8addc04fbcb --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/MultiPolygon.java @@ -0,0 +1,103 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON MultiPolygon. + * + * @since 3.1 + */ +public final class MultiPolygon extends Geometry { + + private final List coordinates; + + /** + * Construct an instance. + * + * @param coordinates the coordinates + */ + public MultiPolygon(final List coordinates) { + this(null, coordinates); + } + + /** + * Construct an instance. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinates the coordinates + */ + public MultiPolygon(final CoordinateReferenceSystem coordinateReferenceSystem, final List coordinates) { + super(coordinateReferenceSystem); + notNull("coordinates", coordinates); + isTrueArgument("coordinates has no null elements", !coordinates.contains(null)); + this.coordinates = Collections.unmodifiableList(coordinates); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.MULTI_POLYGON; + } + + /** + * Gets the coordinates. + * + * @return the coordinates + */ + public List getCoordinates() { + return coordinates; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + + MultiPolygon that = (MultiPolygon) o; + + if (!coordinates.equals(that.coordinates)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + coordinates.hashCode(); + return result; + } + + @Override + public String toString() { + return "MultiPolygon{" + + "coordinates=" + coordinates + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/NamedCoordinateReferenceSystem.java b/driver-core/src/main/com/mongodb/client/model/geojson/NamedCoordinateReferenceSystem.java new file mode 100644 index 00000000000..540f3459658 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/NamedCoordinateReferenceSystem.java @@ -0,0 +1,106 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import com.mongodb.annotations.Immutable; + +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A GeoJSON named Coordinate Reference System. + * + * @since 3.1 + */ +@Immutable +public final class NamedCoordinateReferenceSystem extends CoordinateReferenceSystem { + + /** + * The EPSG:4326 Coordinate Reference System. + */ + public static final NamedCoordinateReferenceSystem EPSG_4326 = + new NamedCoordinateReferenceSystem("EPSG:4326"); + + /** + * The urn:ogc:def:crs:OGC:1.3:CRS84 Coordinate Reference System + */ + public static final NamedCoordinateReferenceSystem CRS_84 = + new NamedCoordinateReferenceSystem("urn:ogc:def:crs:OGC:1.3:CRS84"); + + /** + * A custom MongoDB EPSG:4326 Coordinate Reference System that uses a strict counter-clockwise winding order. + * + * @mongodb.driver.manual reference/operator/query/geometry/ Strict Winding + */ + public static final NamedCoordinateReferenceSystem EPSG_4326_STRICT_WINDING = + new NamedCoordinateReferenceSystem("urn:x-mongodb:crs:strictwinding:EPSG:4326"); + + private final String name; + + /** + * Construct an instance + * + * @param name the name + */ + public NamedCoordinateReferenceSystem(final String name) { + this.name = notNull("name", name); + + } + + @Override + public CoordinateReferenceSystemType getType() { + return CoordinateReferenceSystemType.NAME; + } + + /** + * Gets the name of this Coordinate Reference System. + * + * @return the name + */ + public String getName() { + return name; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + NamedCoordinateReferenceSystem that = (NamedCoordinateReferenceSystem) o; + + if (!name.equals(that.name)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return "NamedCoordinateReferenceSystem{" + + "name='" + name + '\'' + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/Point.java b/driver-core/src/main/com/mongodb/client/model/geojson/Point.java new file mode 100644 index 00000000000..a353b90b1f9 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/Point.java @@ -0,0 +1,107 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON Point. + * + * @since 3.1 + */ +public final class Point extends Geometry { + private final Position coordinate; + + /** + * Construct an instance with the given coordinate. + * + * @param coordinate the non-null coordinate of the point + */ + public Point(final Position coordinate) { + this(null, coordinate); + } + + /** + * Construct an instance with the given coordinate and coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinate the non-null coordinate of the point + */ + public Point(final CoordinateReferenceSystem coordinateReferenceSystem, final Position coordinate) { + super(coordinateReferenceSystem); + this.coordinate = notNull("coordinates", coordinate); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.POINT; + } + + /** + * Gets the GeoJSON coordinates of this point. + * + * @return the coordinates + */ + public Position getCoordinates() { + return coordinate; + } + + /** + * Gets the position of this point. + * + * @return the position + */ + public Position getPosition(){ + return coordinate; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + Point point = (Point) o; + + if (!coordinate.equals(point.coordinate)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + return 31 * result + coordinate.hashCode(); + } + + @Override + public String toString() { + return "Point{" + + "coordinate=" + coordinate + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/Polygon.java b/driver-core/src/main/com/mongodb/client/model/geojson/Polygon.java new file mode 100644 index 00000000000..781af27f9fc --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/Polygon.java @@ -0,0 +1,131 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.List; + +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON Polygon. + * + * @since 3.1 + */ +public final class Polygon extends Geometry { + + private final PolygonCoordinates coordinates; + + /** + * Construct an instance with the given coordinates. + * + * @param exterior the exterior ring of the polygon + * @param holes optional interior rings of the polygon + */ + public Polygon(final List exterior, final List... holes) { + this(new PolygonCoordinates(exterior, holes)); + } + + /** + * Construct an instance with the given coordinates. + * + * @param coordinates the coordinates + */ + public Polygon(final PolygonCoordinates coordinates) { + this(null, coordinates); + } + + /** + * Construct an instance with the given coordinates and coordinate reference system. + * + * @param coordinateReferenceSystem the coordinate reference system + * @param coordinates the coordinates + */ + public Polygon(final CoordinateReferenceSystem coordinateReferenceSystem, final PolygonCoordinates coordinates) { + super(coordinateReferenceSystem); + this.coordinates = notNull("coordinates", coordinates); + } + + @Override + public GeoJsonObjectType getType() { + return GeoJsonObjectType.POLYGON; + } + + /** + * Gets the GeoJSON coordinates of the polygon + * + * @return the coordinates, which must have at least one element + */ + public PolygonCoordinates getCoordinates() { + return coordinates; + } + + /** + * Gets the exterior coordinates. + * + * @return the exterior coordinates + */ + public List getExterior() { + return coordinates.getExterior(); + } + + /** + * Get the holes in this polygon. + * + * @return the possibly-empty list of holes + */ + public List> getHoles() { + return coordinates.getHoles(); + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + if (!super.equals(o)) { + return false; + } + + Polygon polygon = (Polygon) o; + + if (!coordinates.equals(polygon.coordinates)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + coordinates.hashCode(); + return result; + } + + @Override + public String toString() { + return "Polygon{" + + "exterior=" + coordinates.getExterior() + + (coordinates.getHoles().isEmpty() ? "" : ", holes=" + coordinates.getHoles()) + + ((getCoordinateReferenceSystem() == null) ? "" : ", coordinateReferenceSystem=" + getCoordinateReferenceSystem()) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/PolygonCoordinates.java b/driver-core/src/main/com/mongodb/client/model/geojson/PolygonCoordinates.java new file mode 100644 index 00000000000..6c1eb09b6a8 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/PolygonCoordinates.java @@ -0,0 +1,112 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * Coordinates for a GeoJSON Polygon. + * + * @since 3.1 + */ +public final class PolygonCoordinates { + private final List exterior; + private final List> holes; + + /** + * Construct an instance. + * + * @param exterior the exterior ring of the polygon + * @param holes optional interior rings of the polygon + */ + public PolygonCoordinates(final List exterior, final List... holes) { + notNull("exteriorRing", exterior); + isTrueArgument("ring contains only non-null positions", !exterior.contains(null)); + isTrueArgument("ring must contain at least four positions", exterior.size() >= 4); + isTrueArgument("first and last position must be the same", exterior.get(0).equals(exterior.get(exterior.size() - 1))); + + this.exterior = Collections.unmodifiableList(exterior); + + List> holesList = new ArrayList>(holes.length); + for (List hole : holes) { + notNull("interiorRing", hole); + isTrueArgument("ring contains only non-null positions", !hole.contains(null)); + isTrueArgument("ring must contain at least four positions", hole.size() >= 4); + isTrueArgument("first and last position must be the same", hole.get(0).equals(hole.get(hole.size() - 1))); + holesList.add(Collections.unmodifiableList(hole)); + } + + this.holes = Collections.unmodifiableList(holesList); + } + + /** + * Gets the exterior of the polygon. + * + * @return the exterior of the polygon + */ + public List getExterior() { + return exterior; + } + + /** + * Gets the holes in the polygon. + * + * @return the holes in the polygon, which will not be null but may be empty + */ + public List> getHoles() { + return holes; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PolygonCoordinates that = (PolygonCoordinates) o; + + if (!exterior.equals(that.exterior)) { + return false; + } + if (!holes.equals(that.holes)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = exterior.hashCode(); + result = 31 * result + holes.hashCode(); + return result; + } + + @Override + public String toString() { + return "PolygonCoordinates{" + + "exterior=" + exterior + + (holes.isEmpty() ? "" : ", holes=" + holes) + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/Position.java b/driver-core/src/main/com/mongodb/client/model/geojson/Position.java new file mode 100644 index 00000000000..5bf136d55e5 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/Position.java @@ -0,0 +1,103 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson; + +import com.mongodb.annotations.Immutable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.mongodb.assertions.Assertions.isTrueArgument; +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a GeoJSON Position. + * + * @since 3.1 + */ +@Immutable +public final class Position { + private final List values; + + /** + * Construct an instance. + * + * @param values the non-null values + */ + public Position(final List values) { + notNull("values", values); + isTrueArgument("value contains only non-null elements", !values.contains(null)); + isTrueArgument("value must contain at least two elements", values.size() >= 2); + this.values = Collections.unmodifiableList(values); + } + + /** + * Construct an instance. + * + * @param first the first value + * @param second the second value + * @param remaining the remaining values + */ + public Position(final double first, final double second, final double... remaining) { + List values = new ArrayList(); + values.add(first); + values.add(second); + for (double cur : remaining) { + values.add(cur); + } + this.values = Collections.unmodifiableList(values); + } + + /** + * Gets the values of this position + * @return the values of the position + */ + public List getValues() { + return values; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Position that = (Position) o; + + if (!values.equals(that.values)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + return values.hashCode(); + } + + @Override + public String toString() { + return "Position{" + + "values=" + values + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeoJsonCodecProvider.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeoJsonCodecProvider.java new file mode 100644 index 00000000000..f553ebd5d4d --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeoJsonCodecProvider.java @@ -0,0 +1,60 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.GeometryCollection; +import com.mongodb.client.model.geojson.LineString; +import com.mongodb.client.model.geojson.MultiLineString; +import com.mongodb.client.model.geojson.MultiPoint; +import com.mongodb.client.model.geojson.MultiPolygon; +import com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem; +import com.mongodb.client.model.geojson.Point; +import com.mongodb.client.model.geojson.Polygon; +import org.bson.codecs.Codec; +import org.bson.codecs.configuration.CodecProvider; +import org.bson.codecs.configuration.CodecRegistry; + +/** + * A provider of codecs for GeoJSON objects. + * + * @since 3.1 + */ +public class GeoJsonCodecProvider implements CodecProvider { + @Override + @SuppressWarnings("unchecked") + public Codec get(final Class clazz, final CodecRegistry registry) { + if (clazz.equals(Polygon.class)) { + return (Codec) new PolygonCodec(registry); + } else if (clazz.equals(Point.class)) { + return (Codec) new PointCodec(registry); + } else if (clazz.equals(LineString.class)) { + return (Codec) new LineStringCodec(registry); + } else if (clazz.equals(MultiPoint.class)) { + return (Codec) new MultiPointCodec(registry); + } else if (clazz.equals(MultiLineString.class)) { + return (Codec) new MultiLineStringCodec(registry); + } else if (clazz.equals(MultiPolygon.class)) { + return (Codec) new MultiPolygonCodec(registry); + } else if (clazz.equals(GeometryCollection.class)) { + return (Codec) new GeometryCollectionCodec(registry); + } else if (clazz.equals(NamedCoordinateReferenceSystem.class)) { + return (Codec) new NamedCoordinateReferenceSystemCodec(); + } + + return null; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCodecHelper.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCodecHelper.java new file mode 100644 index 00000000000..47f4adaeac6 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCodecHelper.java @@ -0,0 +1,89 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.Geometry; +import com.mongodb.client.model.geojson.PolygonCoordinates; +import com.mongodb.client.model.geojson.Position; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import java.util.List; + +final class GeometryCodecHelper { + + static void encodeGeometry(final BsonWriter writer, final Geometry geometry, final EncoderContext encoderContext, + final CodecRegistry registry, final Runnable coordinatesEncoder) { + writer.writeStartDocument(); + encodeType(writer, geometry); + writer.writeName("coordinates"); + + coordinatesEncoder.run(); + + encodeCoordinateReferenceSystem(writer, geometry, encoderContext, registry); + + writer.writeEndDocument(); + } + + static void encodeType(final BsonWriter writer, final Geometry geometry) { + writer.writeString("type", geometry.getType().getTypeName()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static void encodeCoordinateReferenceSystem(final BsonWriter writer, final Geometry geometry, + final EncoderContext encoderContext, final CodecRegistry registry) { + if (geometry.getCoordinateReferenceSystem() != null) { + writer.writeName("crs"); + Codec codec = registry.get(geometry.getCoordinateReferenceSystem().getClass()); + encoderContext.encodeWithChildContext(codec, writer, geometry.getCoordinateReferenceSystem()); + } + } + + static void encodePolygonCoordinates(final BsonWriter writer, final PolygonCoordinates polygonCoordinates) { + writer.writeStartArray(); + encodeLinearRing(polygonCoordinates.getExterior(), writer); + for (List ring : polygonCoordinates.getHoles()) { + encodeLinearRing(ring, writer); + } + writer.writeEndArray(); + } + + private static void encodeLinearRing(final List ring, final BsonWriter writer) { + writer.writeStartArray(); + for (Position position : ring) { + encodePosition(writer, position); + } + writer.writeEndArray(); + } + + + static void encodePosition(final BsonWriter writer, final Position value) { + writer.writeStartArray(); + + for (double number : value.getValues()) { + writer.writeDouble(number); + } + + writer.writeEndArray(); + } + + + private GeometryCodecHelper() { + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodec.java new file mode 100644 index 00000000000..f433aa0bb7c --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodec.java @@ -0,0 +1,79 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.Geometry; +import com.mongodb.client.model.geojson.GeometryCollection; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeCoordinateReferenceSystem; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeType; + +/** + * A Codec for a GeoJSON GeometryCollection. + * + * @since 3.1 + */ +public class GeometryCollectionCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public GeometryCollectionCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final GeometryCollection value, final EncoderContext encoderContext) { + writer.writeStartDocument(); + encodeType(writer, value); + + writer.writeName("geometries"); + + writer.writeStartArray(); + for (Geometry geometry : value.getGeometries()) { + encodeGeometry(writer, geometry, encoderContext); + } + writer.writeEndArray(); + + encodeCoordinateReferenceSystem(writer, value, encoderContext, registry); + writer.writeEndDocument(); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + private void encodeGeometry(final BsonWriter writer, final Geometry geometry, final EncoderContext encoderContext) { + Codec codec = registry.get(geometry.getClass()); + encoderContext.encodeWithChildContext(codec, writer, geometry); + } + + @Override + public Class getEncoderClass() { + return GeometryCollection.class; + } + + @Override + public GeometryCollection decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/LineStringCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/LineStringCodec.java new file mode 100644 index 00000000000..d1efd36d209 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/LineStringCodec.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.LineString; +import com.mongodb.client.model.geojson.Position; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePosition; + +/** + * A Codec for a GeoJSON LineString. + * + * @since 3.1 + */ +public class LineStringCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public LineStringCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final LineString value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + writer.writeStartArray(); + for (Position position : value.getCoordinates()) { + encodePosition(writer, position); + } + writer.writeEndArray(); + } + }); + } + + @Override + public Class getEncoderClass() { + return LineString.class; + } + + @Override + public LineString decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiLineStringCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiLineStringCodec.java new file mode 100644 index 00000000000..1b7f27cf83a --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiLineStringCodec.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.MultiLineString; +import com.mongodb.client.model.geojson.Position; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import java.util.List; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePosition; + +/** + * A Codec for a GeoJSON MultiLineString. + * + * @since 3.1 + */ +public class MultiLineStringCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public MultiLineStringCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final MultiLineString value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + writer.writeStartArray(); + for (List ring : value.getCoordinates()) { + writer.writeStartArray(); + for (Position position : ring) { + encodePosition(writer, position); + } + writer.writeEndArray(); + } + writer.writeEndArray(); + } + }); + } + + @Override + public Class getEncoderClass() { + return MultiLineString.class; + } + + @Override + public MultiLineString decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPointCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPointCodec.java new file mode 100644 index 00000000000..04d634ef5f4 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPointCodec.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.MultiPoint; +import com.mongodb.client.model.geojson.Position; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePosition; + +/** + * A Codec for a GeoJSON MultiPoint. + * + * @since 3.1 + */ +public class MultiPointCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public MultiPointCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final MultiPoint value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + writer.writeStartArray(); + for (Position position : value.getCoordinates()) { + encodePosition(writer, position); + } + writer.writeEndArray(); + } + }); + } + + @Override + public Class getEncoderClass() { + return MultiPoint.class; + } + + @Override + public MultiPoint decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPolygonCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPolygonCodec.java new file mode 100644 index 00000000000..0c0f697310b --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/MultiPolygonCodec.java @@ -0,0 +1,71 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.MultiPolygon; +import com.mongodb.client.model.geojson.PolygonCoordinates; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePolygonCoordinates; + +/** + * A Codec for a GeoJSON MultiPolygon. + * + * @since 3.1 + */ +public class MultiPolygonCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public MultiPolygonCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final MultiPolygon value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + writer.writeStartArray(); + for (PolygonCoordinates polygonCoordinates : value.getCoordinates()) { + encodePolygonCoordinates(writer, polygonCoordinates); + } + writer.writeEndArray(); + } + }); + } + + @Override + public Class getEncoderClass() { + return MultiPolygon.class; + } + + @Override + public MultiPolygon decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/NamedCoordinateReferenceSystemCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/NamedCoordinateReferenceSystemCodec.java new file mode 100644 index 00000000000..5a11392a5a1 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/NamedCoordinateReferenceSystemCodec.java @@ -0,0 +1,52 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; + +/** + * Codec for a GeoJson Coordinate Reference System of type name. + * + * @since 3.1 + */ +public class NamedCoordinateReferenceSystemCodec implements Codec { + @Override + public void encode(final BsonWriter writer, final NamedCoordinateReferenceSystem value, final EncoderContext encoderContext) { + writer.writeStartDocument(); + + writer.writeString("type", value.getType().getTypeName()); + + writer.writeStartDocument("properties"); + writer.writeString("name", value.getName()); + writer.writeEndDocument(); + + writer.writeEndDocument(); + } + + @Override + public Class getEncoderClass() { + return NamedCoordinateReferenceSystem.class; + } + + @Override + public NamedCoordinateReferenceSystem decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PointCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PointCodec.java new file mode 100644 index 00000000000..ab5524d73d3 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PointCodec.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.Point; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePosition; + +/** + * A Codec for a GeoJSON point. + * + * @since 3.1 + */ +public class PointCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs a new instance. + * + * @param registry the registry + */ + public PointCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final Point value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + encodePosition(writer, value.getPosition()); + } + }); + } + + @Override + public Class getEncoderClass() { + return Point.class; + } + + @Override + public Point decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PolygonCodec.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PolygonCodec.java new file mode 100644 index 00000000000..5ebf02a3851 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/PolygonCodec.java @@ -0,0 +1,68 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs; + +import com.mongodb.client.model.geojson.Polygon; +import org.bson.BsonReader; +import org.bson.BsonWriter; +import org.bson.codecs.Codec; +import org.bson.codecs.DecoderContext; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; + +import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodeGeometry; +import static com.mongodb.client.model.geojson.codecs.GeometryCodecHelper.encodePolygonCoordinates; + +/** + * A Codec for a GeoJSON polygon. + * + * @since 3.1 + */ +public class PolygonCodec implements Codec { + private final CodecRegistry registry; + + /** + * Constructs an instance. + * + * @param registry the registry + */ + public PolygonCodec(final CodecRegistry registry) { + this.registry = notNull("registry", registry); + } + + @Override + public void encode(final BsonWriter writer, final Polygon value, final EncoderContext encoderContext) { + encodeGeometry(writer, value, encoderContext, registry, new Runnable() { + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public void run() { + encodePolygonCoordinates(writer, value.getCoordinates()); + } + }); + } + + @Override + public Class getEncoderClass() { + return Polygon.class; + } + + @Override + public Polygon decode(final BsonReader reader, final DecoderContext decoderContext) { + throw new UnsupportedOperationException("Not implemented yet!"); + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/codecs/package-info.java b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/package-info.java new file mode 100644 index 00000000000..01a1bcefbab --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/codecs/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This package contains classes that encode and decode GeoJSON objects. + */ +package com.mongodb.client.model.geojson.codecs; diff --git a/driver-core/src/main/com/mongodb/client/model/geojson/package-info.java b/driver-core/src/main/com/mongodb/client/model/geojson/package-info.java new file mode 100644 index 00000000000..4aa57016d97 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/geojson/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This package contains classes that represent GeoJSON objects. + */ +package com.mongodb.client.model.geojson; diff --git a/driver-core/src/test/functional/com/mongodb/client/model/GeoFiltersFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/GeoFiltersFunctionalSpecification.groovy new file mode 100644 index 00000000000..4ea67df3c64 --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/GeoFiltersFunctionalSpecification.groovy @@ -0,0 +1,77 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.OperationFunctionalSpecification +import org.bson.Document +import org.bson.conversions.Bson +import spock.lang.IgnoreIf + +import static com.mongodb.ClusterFixture.serverVersionAtLeast +import static com.mongodb.client.model.Filters.geoWithinBox +import static com.mongodb.client.model.Filters.geoWithinCenter +import static com.mongodb.client.model.Filters.geoWithinCenterSphere +import static com.mongodb.client.model.Filters.geoWithinPolygon +import static com.mongodb.client.model.Filters.near +import static com.mongodb.client.model.Filters.nearSphere + +class GeoFiltersFunctionalSpecification extends OperationFunctionalSpecification { + def firstPoint = new Document('_id', 1).append('geo', [1d, 1d]) + def secondPoint = new Document('_id', 2).append('geo', [45d, 2d]) + def thirdPoint = new Document('_id', 3).append('geo', [3d, 3d]) + + def setup() { + getCollectionHelper().createIndex(new Document('geo', '2d')) + getCollectionHelper().insertDocuments(firstPoint, secondPoint, thirdPoint) + } + + def 'find'(Bson filter) { + getCollectionHelper().find(filter, new Document('_id', 1)) // sort by _id + } + + def '$near'() { + expect: + find(near('geo', 1.01d, 1.01d, 0.1d, 0.0d)) == [firstPoint] + } + + def '$nearSphere'() { + expect: + find(nearSphere('geo', 1.01d, 1.01d, 0.1d, 0.0d)) == [firstPoint, thirdPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$geoWithin $box'() { + expect: + find(geoWithinBox('geo', 0d, 0d, 4d, 4d)) == [firstPoint, thirdPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$geoWithin $polygon'() { + expect: + find(geoWithinPolygon('geo', [[0d, 0d], [0d, 4d], [4d, 4d], [4d, 0d]])) == [firstPoint, thirdPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$geoWithin $center'() { + expect: + find(geoWithinCenter('geo', 2d, 2d, 4d)) == [firstPoint, thirdPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 6, 0]) }) + def '$geoWithin $centerSphere'() { + expect: + find(geoWithinCenterSphere('geo', 2d, 2d, 4d)) == [firstPoint, secondPoint, thirdPoint] + } +} diff --git a/driver-core/src/test/functional/com/mongodb/client/model/GeoJsonFiltersFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/GeoJsonFiltersFunctionalSpecification.groovy new file mode 100644 index 00000000000..3e124f2329d --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/GeoJsonFiltersFunctionalSpecification.groovy @@ -0,0 +1,81 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.OperationFunctionalSpecification +import com.mongodb.client.model.geojson.Point +import com.mongodb.client.model.geojson.Polygon +import com.mongodb.client.model.geojson.Position +import org.bson.Document +import org.bson.conversions.Bson +import spock.lang.IgnoreIf + +import static com.mongodb.ClusterFixture.serverVersionAtLeast +import static com.mongodb.client.model.Filters.geoIntersects +import static com.mongodb.client.model.Filters.geoWithin +import static com.mongodb.client.model.Filters.near +import static com.mongodb.client.model.Filters.nearSphere +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.CRS_84 +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326 + +class GeoJsonFiltersFunctionalSpecification extends OperationFunctionalSpecification { + def firstPoint = new Document('_id', 1).append('geo', Document.parse(new Point(CRS_84, new Position(1d, 1d)).toJson())) + def secondPoint = new Document('_id', 2).append('geo', Document.parse(new Point(EPSG_4326, new Position(2d, 2d)).toJson())) + def thirdPoint = new Document('_id', 3).append('geo', Document.parse(new Point(new Position(3d, 3d)).toJson())) + def firstPolygon = new Document('_id', 4).append('geo', Document.parse(new Polygon([new Position(2d, 2d), new Position(6d, 2d), + new Position(6d, 6d), new Position(2d, 6d), + new Position(2d, 2d)]).toJson())) + + def setup() { + getCollectionHelper().createIndex(new Document('geo', '2dsphere')) + getCollectionHelper().insertDocuments(firstPoint, secondPoint, thirdPoint, firstPolygon) + } + + def 'find'(Bson filter) { + getCollectionHelper().find(filter, new Document('_id', 1)) // sort by _id + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$geoWithin'() { + given: + def polygon = new Polygon([new Position(0d, 0d), new Position(4d, 0d), new Position(4d, 4d), new Position(0d, 4d), + new Position(0d, 0d)]) + + expect: + find(geoWithin('geo', polygon)) == [firstPoint, secondPoint, thirdPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$geoIntersects'() { + given: + def polygon = new Polygon([new Position(0d, 0d), new Position(4d, 0d), new Position(4d, 4d), new Position(0d, 4d), + new Position(0d, 0d)]) + + expect: + find(geoIntersects('geo', polygon)) == [firstPoint, secondPoint, thirdPoint, firstPolygon] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$near'() { + expect: + find(near('geo', new Point(new Position(1.01d, 1.01d)), 10000d, null)) == [firstPoint] + } + + @IgnoreIf({ !serverVersionAtLeast([2, 4, 0]) }) + def '$nearSphere'() { + expect: + find(nearSphere('geo', new Point(new Position(1.01d, 1.01d)), 10000d, null)) == [firstPoint] + } +} diff --git a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java index 31b55c7239a..040d989b0eb 100644 --- a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java +++ b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java @@ -25,6 +25,7 @@ import com.mongodb.bulk.IndexRequest; import com.mongodb.bulk.InsertRequest; import com.mongodb.client.model.CreateCollectionOptions; +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import com.mongodb.operation.BatchCursor; import com.mongodb.operation.CountOperation; import com.mongodb.operation.CreateCollectionOperation; @@ -36,6 +37,7 @@ import org.bson.BsonDocument; import org.bson.BsonDocumentWrapper; import org.bson.Document; +import org.bson.codecs.BsonTypeClassMap; import org.bson.codecs.BsonValueCodecProvider; import org.bson.codecs.Codec; import org.bson.codecs.Decoder; @@ -58,7 +60,8 @@ public final class CollectionHelper { private Codec codec; private CodecRegistry registry = CodecRegistries.fromProviders(new BsonValueCodecProvider(), new ValueCodecProvider(), - new DocumentCodecProvider()); + new DocumentCodecProvider(), + new GeoJsonCodecProvider()); private MongoNamespace namespace; public CollectionHelper(final Codec codec, final MongoNamespace namespace) { @@ -115,7 +118,7 @@ public void insertDocuments(final List documents, final WriteBindi } public void insertDocuments(final Document... documents) { - insertDocuments(new DocumentCodec(), asList(documents)); + insertDocuments(new DocumentCodec(registry, new BsonTypeClassMap()), asList(documents)); } public void insertDocuments(final Codec iCodec, final I... documents) { diff --git a/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy index 17441212060..d8ed758fe6d 100644 --- a/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/client/model/FiltersSpecification.groovy @@ -16,6 +16,10 @@ package com.mongodb.client.model +import com.mongodb.client.model.geojson.Point +import com.mongodb.client.model.geojson.Polygon +import com.mongodb.client.model.geojson.Position +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider import org.bson.BsonArray import org.bson.BsonDocument import org.bson.BsonInt32 @@ -29,15 +33,21 @@ import spock.lang.Specification import java.util.regex.Pattern import static Filters.and -import static Filters.eq import static Filters.exists -import static Filters.gt -import static Filters.gte -import static Filters.lt -import static Filters.lte import static Filters.or import static com.mongodb.client.model.Filters.all import static com.mongodb.client.model.Filters.elemMatch +import static com.mongodb.client.model.Filters.eq +import static com.mongodb.client.model.Filters.geoIntersects +import static com.mongodb.client.model.Filters.geoWithin +import static com.mongodb.client.model.Filters.geoWithinBox +import static com.mongodb.client.model.Filters.geoWithinCenter +import static com.mongodb.client.model.Filters.geoWithinCenterSphere +import static com.mongodb.client.model.Filters.geoWithinPolygon +import static com.mongodb.client.model.Filters.gt +import static com.mongodb.client.model.Filters.gte +import static com.mongodb.client.model.Filters.lt +import static com.mongodb.client.model.Filters.lte import static com.mongodb.client.model.Filters.mod import static com.mongodb.client.model.Filters.ne import static com.mongodb.client.model.Filters.nin @@ -53,7 +63,7 @@ import static org.bson.BsonDocument.parse import static org.bson.codecs.configuration.CodecRegistries.fromProviders class FiltersSpecification extends Specification { - def registry = fromProviders([new BsonValueCodecProvider(), new ValueCodecProvider()]) + def registry = fromProviders([new BsonValueCodecProvider(), new ValueCodecProvider(), new GeoJsonCodecProvider()]) def 'eq should render without $eq'() { expect: @@ -206,6 +216,346 @@ class FiltersSpecification extends Specification { toBson(where('this.credits == this.debits')) == parse('{$where: "this.credits == this.debits"}') } + def 'should render $geoWithin'() { + given: + def polygon = new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])]) + expect: + toBson(geoWithin('loc', polygon)) == parse('''{ + loc: { + $geoWithin: { + $geometry: { + type: "Polygon", + coordinates: [ + [ + [40.0, 18.0], [40.0, 19.0], [41.0, 19.0], [40.0, 18.0] + ] + ] + } + } + } + }''') + + toBson(geoWithin('loc', parse(polygon.toJson()))) == parse('''{ + loc: { + $geoWithin: { + $geometry: { + type: "Polygon", + coordinates: [ + [ + [40.0, 18.0], [40.0, 19.0], [41.0, 19.0], + [40.0, 18.0] + ] + ] + } + } + } + }''') + } + + def 'should render $geoWithin with $box'() { + expect: + toBson(geoWithinBox('loc', 1d, 2d, 3d, 4d)) == parse('''{ + loc: { + $geoWithin: { + $box: [ + [ 1.0, 2.0 ], [ 3.0, 4.0 ] + ] + } + } + }''') + } + + def 'should render $geoWithin with $polygon'() { + expect: + toBson(geoWithinPolygon('loc', [[0d, 0d], [3d, 6d], [6d, 0d]])) == parse('''{ + loc: { + $geoWithin: { + $polygon: [ + [ 0.0, 0.0 ], [ 3.0, 6.0 ], + [ 6.0, 0.0 ] + ] + } + } + }''') + } + + def 'should render $geoWithin with $center'() { + expect: + toBson(geoWithinCenter('loc', -74d, 40.74d, 10d)) == parse('{ loc: { $geoWithin: { $center: [ [-74.0, 40.74], 10.0 ] } } }') + } + + def 'should render $geoWithin with $centerSphere'() { + expect: + toBson(geoWithinCenterSphere('loc', -74d, 40.74d, 10d)) == parse('''{ + loc: { + $geoWithin: { + $centerSphere: [ + [-74.0, 40.74], 10.0 + ] + } + } + }''') + } + + def 'should render $geoIntersects'() { + given: + def polygon = new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])]) + expect: + toBson(geoIntersects('loc', polygon)) == parse('''{ + loc: { + $geoIntersects: { + $geometry: { + type: "Polygon", + coordinates: [ + [ + [40.0, 18.0], [40.0, 19.0], [41.0, 19.0], + [40.0, 18.0] + ] + ] + } + } + } + }''') + + toBson(geoIntersects('loc', parse(polygon.toJson()))) == parse('''{ + loc: { + $geoIntersects: { + $geometry: { + type: "Polygon", + coordinates: [ + [ + [40.0, 18.0], [40.0, 19.0], [41.0, 19.0], + [40.0, 18.0] + ] + ] + } + } + } + }''') + } + + def 'should render $near'() { + given: + def point = new Point(new Position(-73.9667, 40.78)) + def pointDocument = parse(point.toJson()) + + expect: + toBson(Filters.near('loc', point, 5000d, 1000d)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.near('loc', point, 5000d, null)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.near('loc', point, null, 1000d)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.near('loc', pointDocument, 5000d, 1000d)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.near('loc', pointDocument, 5000d, null)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.near('loc', pointDocument, null, 1000d)) == parse('''{ + loc : { + $near: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.near('loc', -73.9667, 40.78, 5000d, 1000d)) == parse('''{ + loc : { + $near: [-73.9667, 40.78], + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.near('loc', -73.9667, 40.78, 5000d, null)) == parse('''{ + loc : { + $near: [-73.9667, 40.78], + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.near('loc', -73.9667, 40.78, null, 1000d)) == parse('''{ + loc : { + $near: [-73.9667, 40.78], + $minDistance: 1000.0, + } + } + }''') + } + + def 'should render $nearSphere'() { + given: + def point = new Point(new Position(-73.9667, 40.78)) + def pointDocument = parse(point.toJson()) + + expect: + toBson(Filters.nearSphere('loc', point, 5000d, 1000d)) == parse('''{ + loc : { + $nearSphere: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', point, 5000d, null)) == parse('''{ + loc: + { + $nearSphere: + { + $geometry: + { + type: "Point", + coordinates: + [-73.9667, 40.78] + }, + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', point, null, 1000d)) == parse('''{ + loc : { + $nearSphere: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', pointDocument, 5000d, 1000d)) == parse('''{ + loc : { + $nearSphere: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', pointDocument, 5000d, null)) == parse('''{ + loc : { + $nearSphere: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', pointDocument, null, 1000d)) == parse('''{ + loc : { + $nearSphere: { + $geometry: { + type : "Point", + coordinates : [ -73.9667, 40.78 ] + }, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', -73.9667, 40.78, 5000d, 1000d)) == parse('''{ + loc : { + $nearSphere: [-73.9667, 40.78], + $maxDistance: 5000.0, + $minDistance: 1000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', -73.9667, 40.78, 5000d, null)) == parse('''{ + loc : { + $nearSphere: [-73.9667, 40.78], + $maxDistance: 5000.0, + } + } + }''') + + toBson(Filters.nearSphere('loc', -73.9667, 40.78, null, 1000d)) == parse('''{ + loc : { + $nearSphere: [-73.9667, 40.78], + $minDistance: 1000.0, + } + } + }''') + } + def toBson(Bson bson) { bson.toBsonDocument(BsonDocument, registry) } diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/GeometryCollectionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/GeometryCollectionSpecification.groovy new file mode 100644 index 00000000000..e8a73842dd5 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/GeometryCollectionSpecification.groovy @@ -0,0 +1,54 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +class GeometryCollectionSpecification extends Specification { + def geometries = [new Point(new Position(1d, 2d)), new Point(new Position(2d, 2d))] + + def 'constructor should set geometries'() { + expect: + new GeometryCollection(geometries).geometries == geometries + } + + def 'constructors should throw if preconditions are violated'() { + when: + new GeometryCollection(null) + + then: + thrown(IllegalArgumentException) + + when: + new GeometryCollection([new Point(new Position(1d, 2d)), new Position([40.0d, 19.0d]), null]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new GeometryCollection(geometries).type == GeoJsonObjectType.GEOMETRY_COLLECTION + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new GeometryCollection(geometries) == new GeometryCollection(geometries) + new GeometryCollection(geometries).hashCode() == new GeometryCollection(geometries).hashCode() + new GeometryCollection(geometries).toString() == + 'GeometryCollection{geometries=[Point{coordinate=Position{values=[1.0, 2.0]}}, Point{coordinate=Position{values=[2.0, 2.0]}}]}' + + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/LineStringSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/LineStringSpecification.groovy new file mode 100644 index 00000000000..6ac346fa5b4 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/LineStringSpecification.groovy @@ -0,0 +1,77 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + +class LineStringSpecification extends Specification { + def coordinates = [new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])] + + def 'constructor should set coordinates'() { + expect: + new LineString(coordinates).coordinates == coordinates + } + + def 'constructor should set coordinate reference system'() { + expect: + new LineString(coordinates).coordinateReferenceSystem == null + new LineString(EPSG_4326_STRICT_WINDING, coordinates).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new LineString(null) + + then: + thrown(IllegalArgumentException) + + when: + new LineString([new Position([40.0d, 18.0d])]) + + then: + thrown(IllegalArgumentException) + + when: + new LineString([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + null]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new LineString(coordinates).type == GeoJsonObjectType.LINE_STRING + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new LineString(coordinates) == new LineString(coordinates) + new LineString(coordinates).hashCode() == new LineString(coordinates).hashCode() + new LineString(coordinates).toString() == + 'LineString{coordinates=[Position{values=[40.0, 18.0]}, ' + + 'Position{values=[40.0, 19.0]}, ' + + 'Position{values=[41.0, 19.0]}, ' + + 'Position{values=[40.0, 18.0]}]}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiLineStringSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiLineStringSpecification.groovy new file mode 100644 index 00000000000..fe290c61720 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiLineStringSpecification.groovy @@ -0,0 +1,72 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + + +class MultiLineStringSpecification extends Specification { + def coordinates = [[new Position([1.0d, 1.0d]), new Position([2.0d, 2.0d]), new Position([3.0d, 4.0d])], + [new Position([2.0d, 3.0d]), new Position([3.0d, 2.0d]), new Position([4.0d, 4.0d])]] + + def 'constructor should set coordinates'() { + expect: + new MultiLineString(coordinates).coordinates == coordinates + } + + def 'constructor should set coordinate reference system'() { + expect: + new MultiLineString(coordinates).coordinateReferenceSystem == null + new MultiLineString(EPSG_4326_STRICT_WINDING, coordinates).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new MultiLineString(null) + + then: + thrown(IllegalArgumentException) + + when: + new MultiLineString([[new Position([40.0d, 18.0d]), new Position([40.0d, 19.0d])], null]) + + then: + thrown(IllegalArgumentException) + + when: + new MultiLineString([[new Position([40.0d, 18.0d]), new Position([40.0d, 19.0d]), null]]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new MultiLineString(coordinates).type == GeoJsonObjectType.MULTI_LINE_STRING + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new MultiLineString(coordinates) == new MultiLineString(coordinates) + new MultiLineString(coordinates).hashCode() == new MultiLineString(coordinates).hashCode() + new MultiLineString(coordinates).toString() == + 'MultiLineString{coordinates=[' + + '[Position{values=[1.0, 1.0]}, Position{values=[2.0, 2.0]}, Position{values=[3.0, 4.0]}], ' + + '[Position{values=[2.0, 3.0]}, Position{values=[3.0, 2.0]}, Position{values=[4.0, 4.0]}]]}' + + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPointSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPointSpecification.groovy new file mode 100644 index 00000000000..a4c5d3b443a --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPointSpecification.groovy @@ -0,0 +1,71 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + + +class MultiPointSpecification extends Specification { + def coordinates = [new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])] + + def 'constructor should set coordinates'() { + expect: + new MultiPoint(coordinates).coordinates == coordinates + } + + def 'constructor should set coordinate reference system'() { + expect: + new MultiPoint(coordinates).coordinateReferenceSystem == null + new MultiPoint(EPSG_4326_STRICT_WINDING, coordinates).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new MultiPoint(null) + + then: + thrown(IllegalArgumentException) + + when: + new MultiPoint([new Position([40.0d, 18.0d]), + null]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new MultiPoint(coordinates).type == GeoJsonObjectType.MULTI_POINT + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new MultiPoint(coordinates) == new MultiPoint(coordinates) + new MultiPoint(coordinates).hashCode() == new MultiPoint(coordinates).hashCode() + new MultiPoint(coordinates).toString() == + 'MultiPoint{coordinates=[Position{values=[40.0, 18.0]}, ' + + 'Position{values=[40.0, 19.0]}, ' + + 'Position{values=[41.0, 19.0]}, ' + + 'Position{values=[40.0, 18.0]}]}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPolygonSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPolygonSpecification.groovy new file mode 100644 index 00000000000..4c2d24111d7 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/MultiPolygonSpecification.groovy @@ -0,0 +1,76 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + + +class MultiPolygonSpecification extends Specification { + def exteriorOne = [new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])] + def coordinatesOne = new PolygonCoordinates(exteriorOne) + + def exteriorTwo = [new Position([80.0d, 18.0d]), + new Position([80.0d, 19.0d]), + new Position([81.0d, 19.0d]), + new Position([80.0d, 18.0d])] + def coordinatesTwo = new PolygonCoordinates(exteriorTwo) + + def 'constructor should set coordinates'() { + expect: + new MultiPolygon([coordinatesOne, coordinatesTwo]).coordinates == [coordinatesOne, coordinatesTwo] + } + + def 'constructor should set coordinate reference system'() { + expect: + new MultiPolygon([coordinatesOne]).coordinateReferenceSystem == null + new MultiPolygon(EPSG_4326_STRICT_WINDING, [coordinatesOne]).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new MultiPolygon(null) + + then: + thrown(IllegalArgumentException) + + when: + new MultiPolygon([coordinatesOne, null]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new MultiPolygon([coordinatesOne]).type == GeoJsonObjectType.MULTI_POLYGON + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new MultiPolygon([coordinatesOne, coordinatesTwo]) == new MultiPolygon([coordinatesOne, coordinatesTwo]) + new MultiPolygon([coordinatesOne, coordinatesTwo]).hashCode() == new MultiPolygon([coordinatesOne, coordinatesTwo]).hashCode() + new MultiPolygon([coordinatesOne, coordinatesTwo]).toString() == + 'MultiPolygon{coordinates=[' + + 'PolygonCoordinates{exterior=[Position{values=[40.0, 18.0]}, Position{values=[40.0, 19.0]}, Position{values=[41.0, 19.0]}, ' + + 'Position{values=[40.0, 18.0]}]}, ' + + 'PolygonCoordinates{exterior=[Position{values=[80.0, 18.0]}, Position{values=[80.0, 19.0]}, Position{values=[81.0, 19.0]}, ' + + 'Position{values=[80.0, 18.0]}]}]}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/PointSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PointSpecification.groovy new file mode 100644 index 00000000000..b0ac1c04169 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PointSpecification.groovy @@ -0,0 +1,62 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + + +class PointSpecification extends Specification { + def 'constructor should set coordinates'() { + expect: + new Point(new Position(1.0d, 2.0d)).coordinates == new Position(1.0d, 2.0d) + new Point(new Position(1.0d, 2.0d)).position == new Position(1.0d, 2.0d) + } + + def 'constructor should set coordinate reference system'() { + expect: + new Point(new Position(1.0d, 2.0d)).coordinateReferenceSystem == null + new Point(EPSG_4326_STRICT_WINDING, new Position(1.0d, 2.0d)).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new Point(null) + + then: + thrown(IllegalArgumentException) + + when: + new Point(EPSG_4326_STRICT_WINDING, null) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new Point(new Position(1.0d, 2.0d)).type == GeoJsonObjectType.POINT + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new Point(new Position(1.0d, 2.0d)) == new Point(new Position(1.0d, 2.0d)) + new Point(new Position(1.0d, 2.0d)).hashCode() == new Point(new Position(1.0d, 2.0d)).hashCode() + new Point(new Position(1.0d, 2.0d)).toString() == 'Point{coordinate=Position{values=[1.0, 2.0]}}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/PolygonSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PolygonSpecification.groovy new file mode 100644 index 00000000000..a34a7546764 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PolygonSpecification.groovy @@ -0,0 +1,90 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING + + +class PolygonSpecification extends Specification { + def exterior = [new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])] + def coordinates = new PolygonCoordinates(exterior) + + def 'constructor should set coordinates'() { + expect: + new Polygon(exterior).coordinates == coordinates + } + + def 'constructor should set coordinate reference system'() { + expect: + new Polygon(exterior).coordinateReferenceSystem == null + new Polygon(EPSG_4326_STRICT_WINDING, coordinates).coordinateReferenceSystem == EPSG_4326_STRICT_WINDING + } + + def 'constructors should throw if preconditions are violated'() { + when: + new Polygon(null) + + then: + thrown(IllegalArgumentException) + + when: + new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d])]) + + then: + thrown(IllegalArgumentException) + + when: + new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + null]) + + then: + thrown(IllegalArgumentException) + + when: + new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([1.0, 2.0])]) + + then: + thrown(IllegalArgumentException) + } + + def 'should get type'() { + expect: + new Polygon(exterior).type == GeoJsonObjectType.POLYGON + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new Polygon(exterior) == new Polygon(exterior) + new Polygon(exterior).hashCode() == new Polygon(exterior).hashCode() + new Polygon(exterior).toString() == + 'Polygon{exterior=[Position{values=[40.0, 18.0]}, ' + + 'Position{values=[40.0, 19.0]}, ' + + 'Position{values=[41.0, 19.0]}, ' + + 'Position{values=[40.0, 18.0]}]}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/PositionSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PositionSpecification.groovy new file mode 100644 index 00000000000..019489ec209 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/PositionSpecification.groovy @@ -0,0 +1,71 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson + +import spock.lang.Specification + + +class PositionSpecification extends Specification { + def 'constructors should set values'() { + expect: + new Position([1.0d, 2.0d]).values == [1.0d, 2.0d] + new Position(1.0d, 2.0d).values == [1.0d, 2.0d] + new Position(1.0d, 2.0d, 3.0d).values == [1.0d, 2.0d, 3.0d] + new Position(1.0d, 2.0d, 3.0d, 4.0d).values == [1.0d, 2.0d, 3.0d, 4.0d] + } + + def 'constructors should set unmodifiable'() { + when: + new Position([1.0d, 2.0d]).values[0] = 3.0d + + then: + thrown(UnsupportedOperationException) + + when: + new Position(1.0d, 2.0d).values[0] = 3.0d + + then: + thrown(UnsupportedOperationException) + } + + def 'constructor should throw when preconditions are violated'() { + when: + new Position(null) + + then: + thrown(IllegalArgumentException) + + when: + new Position([1.0]) + + then: + thrown(IllegalArgumentException) + + when: + new Position([1.0, null]) + + then: + thrown(IllegalArgumentException) + } + + def 'equals, hashcode and toString should be overridden'() { + expect: + new Position(1.0d, 2.0d) == new Position(1.0d, 2.0d) + new Position(1.0d, 2.0d).hashCode() == new Position(1.0d, 2.0d).hashCode() + new Position(1.0d, 2.0d).toString() == 'Position{values=[1.0, 2.0]}' + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodecSpecification.groovy new file mode 100644 index 00000000000..b6a422d5583 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/GeometryCollectionCodecSpecification.groovy @@ -0,0 +1,69 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.GeometryCollection +import com.mongodb.client.model.geojson.LineString +import com.mongodb.client.model.geojson.Point +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class GeometryCollectionCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(GeometryCollection) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def geometryCollection = new GeometryCollection([new Point(new Position(100d, 0d)), + new LineString([new Position(101d, 0d), new Position(102d, 1d)])]) + + when: + codec.encode(writer, geometryCollection, context) + + then: + writer.document == parse('{ type: "GeometryCollection",' + + ' geometries: [' + + ' { type: "Point", coordinates: [100.0, 0.0]},' + + ' { type: "LineString", coordinates: [ [101.0, 0.0], [102.0, 1.0] ]}' + + ' ]}') + } + + def 'should encode with coordinate reference system'() { + given: + def geometryCollection = new GeometryCollection(EPSG_4326_STRICT_WINDING, + [new Point(new Position(100d, 0d)), + new LineString([new Position(101d, 0d), new Position(102d, 1d)])]) + + when: + codec.encode(writer, geometryCollection, context) + + then: + writer.document == parse('{ type: "GeometryCollection",' + + ' geometries: [' + + ' { type: "Point", coordinates: [100.0, 0.0]},' + + ' { type: "LineString", coordinates: [ [101.0, 0.0], [102.0, 1.0] ]}, ' + + ' ]' + + " crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/LineStringCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/LineStringCodecSpecification.groovy new file mode 100644 index 00000000000..fe45045bb94 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/LineStringCodecSpecification.groovy @@ -0,0 +1,63 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.LineString +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class LineStringCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(LineString) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def polygon = new LineString([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'LineString\', coordinates: [[40.0, 18.0], [40.0, 19.0], [41.0, 19.0]]}') + } + + def 'should encode with coordinate reference system'() { + given: + def polygon = new LineString(EPSG_4326_STRICT_WINDING, + [new Position([40.0d, 20.0d]), + new Position([40.0d, 40.0d]), + new Position([20.0d, 40.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'LineString\', ' + + 'coordinates: ' + + '[[40.0, 20.0], [40.0, 40.0], [20.0, 40.0]],' + + "crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiLineStringCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiLineStringCodecSpecification.groovy new file mode 100644 index 00000000000..0cdcf4c9b3f --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiLineStringCodecSpecification.groovy @@ -0,0 +1,64 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.MultiLineString +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class MultiLineStringCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(MultiLineString) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def multiLineString = new MultiLineString([[new Position([1.0d, 1.0d]), new Position([2.0d, 2.0d]), new Position([3.0d, 4.0d])], + [new Position([2.0d, 3.0d]), new Position([3.0d, 2.0d]), new Position([4.0d, 4.0d])]]) + + when: + codec.encode(writer, multiLineString, context) + + then: + writer.document == parse('{type: \'MultiLineString\', coordinates: [' + + '[[1.0, 1.0], [2.0, 2.0], [3.0, 4.0]], ' + + '[[2.0, 3.0], [3.0, 2.0], [4.0, 4.0]]]}') + } + + def 'should encode with coordinate reference system'() { + given: + def multiLineString = new MultiLineString(EPSG_4326_STRICT_WINDING, + [[new Position([1.0d, 1.0d]), new Position([2.0d, 2.0d]), new Position([3.0d, 4.0d])], + [new Position([2.0d, 3.0d]), new Position([3.0d, 2.0d]), new Position([4.0d, 4.0d])]]) + + when: + codec.encode(writer, multiLineString, context) + + then: + writer.document == parse('{type: \'MultiLineString\', ' + + 'coordinates: [' + + '[[1.0, 1.0], [2.0, 2.0], [3.0, 4.0]], ' + + '[[2.0, 3.0], [3.0, 2.0], [4.0, 4.0]]], ' + + "crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPointCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPointCodecSpecification.groovy new file mode 100644 index 00000000000..278d254ae5d --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPointCodecSpecification.groovy @@ -0,0 +1,63 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.MultiPoint +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class MultiPointCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(MultiPoint) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def polygon = new MultiPoint([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'MultiPoint\', coordinates: [[40.0, 18.0], [40.0, 19.0], [41.0, 19.0]]}') + } + + def 'should encode with coordinate reference system'() { + given: + def polygon = new MultiPoint(EPSG_4326_STRICT_WINDING, + [new Position([40.0d, 20.0d]), + new Position([40.0d, 40.0d]), + new Position([20.0d, 40.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'MultiPoint\', ' + + 'coordinates: ' + + '[[40.0, 20.0], [40.0, 40.0], [20.0, 40.0]],' + + "crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPolygonCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPolygonCodecSpecification.groovy new file mode 100644 index 00000000000..7f5956f8130 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/MultiPolygonCodecSpecification.groovy @@ -0,0 +1,87 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.MultiPolygon +import com.mongodb.client.model.geojson.PolygonCoordinates +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class MultiPolygonCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(MultiPolygon) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def multiMultiPolygon = new MultiPolygon([new PolygonCoordinates([new Position(102.0, 2.0), new Position(103.0, 2.0), + new Position(103.0, 3.0), new Position(102.0, 3.0), + new Position(102.0, 2.0)]), + new PolygonCoordinates([new Position(100.0, 0.0), new Position(101.0, 0.0), + new Position(101.0, 1.0), new Position(100.0, 1.0), + new Position(100.0, 0.0)], + [new Position(100.2, 0.2), new Position(100.8, 0.2), + new Position(100.8, 0.8), new Position(100.2, 0.8), + new Position(100.2, 0.2)])]) + + when: + codec.encode(writer, multiMultiPolygon, context) + + then: + writer.document == parse('{ "type": "MultiPolygon",' + + ' "coordinates": [' + + ' [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],' + + ' [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],' + + ' [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]' + + ' ]' + + ' }') + } + + def 'should encode with coordinate reference system'() { + given: + def multiMultiPolygon = new MultiPolygon(EPSG_4326_STRICT_WINDING, + [new PolygonCoordinates([new Position(102.0, 2.0), new Position(103.0, 2.0), + new Position(103.0, 3.0), new Position(102.0, 3.0), + new Position(102.0, 2.0)]), + new PolygonCoordinates([new Position(100.0, 0.0), new Position(101.0, 0.0), + new Position(101.0, 1.0), new Position(100.0, 1.0), + new Position(100.0, 0.0)], + [new Position(100.2, 0.2), new Position(100.8, 0.2), + new Position(100.8, 0.8), new Position(100.2, 0.8), + new Position(100.2, 0.2)])]) + + when: + codec.encode(writer, multiMultiPolygon, context) + + then: + writer.document == parse('{ "type": "MultiPolygon",' + + ' "coordinates": [' + + ' [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],' + + ' [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],' + + ' [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]' + + ' ]' + + " \"crs\" : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}" + + ' }') + } + +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PointCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PointCodecSpecification.groovy new file mode 100644 index 00000000000..d9b64882fd3 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PointCodecSpecification.groovy @@ -0,0 +1,58 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.Point +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class PointCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(Point) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def point = new Point(new Position([40.0d, 18.0d])) + + when: + codec.encode(writer, point, context) + + then: + writer.document == parse('{type: \'Point\', coordinates: [40.0, 18.0]}') + } + + def 'should encode with coordinate reference system'() { + given: + def point = new Point(EPSG_4326_STRICT_WINDING, new Position([40.0d, 18.0d])) + + when: + codec.encode(writer, point, context) + + then: + writer.document == parse('{type: \'Point\', coordinates: [40.0, 18.0], ' + + "crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PolygonCodecSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PolygonCodecSpecification.groovy new file mode 100644 index 00000000000..574a95a5506 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/geojson/codecs/PolygonCodecSpecification.groovy @@ -0,0 +1,91 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model.geojson.codecs + +import com.mongodb.client.model.geojson.Polygon +import com.mongodb.client.model.geojson.PolygonCoordinates +import com.mongodb.client.model.geojson.Position +import org.bson.BsonDocument +import org.bson.BsonDocumentWriter +import org.bson.codecs.EncoderContext +import spock.lang.Specification + +import static com.mongodb.client.model.geojson.NamedCoordinateReferenceSystem.EPSG_4326_STRICT_WINDING +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class PolygonCodecSpecification extends Specification { + def registry = fromProviders([new GeoJsonCodecProvider()]) + def codec = registry.get(Polygon) + def writer = new BsonDocumentWriter(new BsonDocument()) + def context = EncoderContext.builder().build() + + def 'should encode'() { + given: + def polygon = new Polygon([new Position([40.0d, 18.0d]), + new Position([40.0d, 19.0d]), + new Position([41.0d, 19.0d]), + new Position([40.0d, 18.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'Polygon\', coordinates: [[[40.0, 18.0], [40.0, 19.0], [41.0, 19.0], [40.0, 18.0]]]}') + } + + def 'should encode with coordinate reference system'() { + given: + def polygon = new Polygon(EPSG_4326_STRICT_WINDING, + new PolygonCoordinates([new Position([40.0d, 20.0d]), + new Position([40.0d, 40.0d]), + new Position([20.0d, 40.0d]), + new Position([40.0d, 20.0d])])) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'Polygon\', ' + + 'coordinates: [' + + '[[40.0, 20.0], [40.0, 40.0], [20.0, 40.0], [40.0, 20.0]]],' + + "crs : {type: 'name', properties : {name : '$EPSG_4326_STRICT_WINDING.name'}}}") + } + + def 'should encode with holes'() { + given: + def polygon = new Polygon([new Position([40.0d, 20.0d]), + new Position([40.0d, 40.0d]), + new Position([20.0d, 40.0d]), + new Position([40.0d, 20.0d])], + [new Position([30.0d, 25.0d]), + new Position([30.0d, 35.0d]), + new Position([25.0d, 25.0d]), + new Position([30.0d, 25.0d])]) + + when: + codec.encode(writer, polygon, context) + + then: + writer.document == parse('{type: \'Polygon\', ' + + 'coordinates: [' + + '[[40.0, 20.0], [40.0, 40.0], [20.0, 40.0], [40.0, 20.0]],' + + '[[30.0, 25.0], [30.0, 35.0], [25.0, 25.0], [30.0, 25.0]]' + + ']}') + } + +} diff --git a/driver/src/main/com/mongodb/MongoClient.java b/driver/src/main/com/mongodb/MongoClient.java index af63e65a308..8f361070be9 100644 --- a/driver/src/main/com/mongodb/MongoClient.java +++ b/driver/src/main/com/mongodb/MongoClient.java @@ -19,6 +19,7 @@ import com.mongodb.client.ListDatabasesIterable; import com.mongodb.client.MongoDatabase; import com.mongodb.client.MongoIterable; +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import org.bson.BsonDocument; import org.bson.Document; import org.bson.codecs.BsonValueCodecProvider; @@ -83,7 +84,8 @@ public class MongoClient extends Mongo implements Closeable { new DBRefCodecProvider(), new DocumentCodecProvider(new DocumentToDBRefTransformer()), new DBObjectCodecProvider(), - new BsonValueCodecProvider())); + new BsonValueCodecProvider(), + new GeoJsonCodecProvider())); /** * Gets the default codec registry. It includes the following providers: @@ -92,6 +94,7 @@ public class MongoClient extends Mongo implements Closeable { *
  • {@link org.bson.codecs.DocumentCodecProvider}
  • *
  • {@link com.mongodb.DBObjectCodecProvider}
  • *
  • {@link org.bson.codecs.BsonValueCodecProvider}
  • + *
  • {@link com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider}
  • * * * @return the default codec registry diff --git a/driver/src/test/unit/com/mongodb/MongoClientSpecification.groovy b/driver/src/test/unit/com/mongodb/MongoClientSpecification.groovy new file mode 100644 index 00000000000..44c829d083b --- /dev/null +++ b/driver/src/test/unit/com/mongodb/MongoClientSpecification.groovy @@ -0,0 +1,35 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb + +import com.mongodb.client.model.geojson.MultiPolygon +import org.bson.BsonDocument +import org.bson.Document +import spock.lang.Specification + +class MongoClientSpecification extends Specification { + + def 'default codec registry should contain all supported providers'() { + given: + def codecRegistry = MongoClient.getDefaultCodecRegistry() + + expect: + codecRegistry.get(BsonDocument) + codecRegistry.get(BasicDBObject) + codecRegistry.get(Document) + codecRegistry.get(Integer) + codecRegistry.get(MultiPolygon) + } +} \ No newline at end of file From cee5088775d27805cfc1578851dbdf4f998cea2e Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Tue, 21 Apr 2015 18:22:38 -0400 Subject: [PATCH 0030/1665] Added reference documentation for the Filters builder methods. --- docs/reference/content/builders/filters.md | 205 +++++++++++++++++++++ docs/reference/content/builders/index.md | 14 ++ 2 files changed, 219 insertions(+) create mode 100644 docs/reference/content/builders/filters.md create mode 100644 docs/reference/content/builders/index.md diff --git a/docs/reference/content/builders/filters.md b/docs/reference/content/builders/filters.md new file mode 100644 index 00000000000..f5b2658b1fb --- /dev/null +++ b/docs/reference/content/builders/filters.md @@ -0,0 +1,205 @@ ++++ +date = "2015-03-19T14:27:51-04:00" +title = "Filters" +[menu.main] + parent = "Builders" + weight = 10 + pre = "" ++++ + +## Filters + +The [`Filters`]({{< apiref "com/mongodb/client/model/Filters" >}}) class provides static factory methods for all the MongoDB query +operators. Each method returns an instance of the [`Bson`]({{< relref "bson/documents.md#bson" >}}) type, which can in turn be passed to +any method that expects a query filter. + +For brevity, you may choose to import the methods of the `Filters` class statically: + +```java +import com.mongodb.client.model.Filters.*; +``` + +All the examples below assume this static import. + +### Comparison + +The comparison operator methods include: + +- `eq`: Matches values that are equal to a specified value. +- `gt`: Matches values that are greater than a specified value. +- `gte`: Matches values that are greater than or equal to a specified value. +- `lt`: Matches values that are less than a specified value. +- `lte`: Matches values that are less than or equal to a specified value. +- `ne`: Matches all values that are not equal to a specified value. +- `in`: Matches any of the values specified in an array. +- `nin`: Matches none of the values specified in an array. + +#### Examples + +This example creates a filter that selects all documents where the value of the `qty` field equals `20`: + +```java +eq("qty", 20) +``` + +which will render as: + +```json +{ + "qty" : 20 +} +``` + +This example creates a filter that selects all documents where the value of the `qty` field is either `5` or `20`: + +```java +in("qty", 5, 15) +``` + +### Logical + +The logical operator methods include: + +- `and`: Joins filters with a logical AND and selects all documents that match the conditions of both filters. +- `or`: Joins filters with a logical OR and selects all documents that match the conditions of either filters. +- `not`: Inverts the effect of a query expression and selects documents that do not match the filter. +- `nor`: Joins filters with a logical NOR and selects all documents that fail to match both filters. + +#### Examples + +This example creates a filter that selects all documents where ther value of the `qty` field is greater than `20` and the value of the +`user` field equals `"jdoe"`: + +```java +and(gt("qty", 20), eq("user", "jdoe")) +``` + +The `and` method generates a `$and` operator only if necessary, as the query language implicity ands together all the elements in a +filter. So the above example will render as: + +```json +{ + "qty" : { "$gt" : 20 }, + "user" : "jdoe" +} +``` + +This example creates a filter that selects all documents where the `price` field value equals `0.99` or `1.99`; and the `sale` field value +is equal to `true` or the `qty` field value is less than `20`: + +```java +and(or(eq("price", 0.99), eq("price", 1.99) + or(eq("sale", true), lt("qty", 20))) +``` + +This query cannot be constructed using an implicit and operation, because it uses the `$or` operator more than once. So it will render as: + +```json +{ + "$and" : + [ + { "$or" : [ { "price" : 0.99 }, { "price" : 1.99 } ] }, + { "$or" : [ { "sale" : true }, { "qty" : { "$lt" : 20 } } ] } + ] +} +``` + +### Arrays + +The array operator methods include: + +- `all`: Matches arrays that contain all elements specified in the query +- `elemMatch`: Selects documents if element in the array field matches all the specified $elemMatch conditions +- `size`: Selects documents if the array field is a specified size + +#### Examples + +This example selects documents with a `tags` array containing both `"ssl"` and `"security"`: + +```java +all("tags", Arrays.asList("ssl", "security")) +``` + +### Elements + +The elements operator methods include: + +- `exists`: Selects documents that have the specified field. +- `type`: Selects documents if a field is of the specified type. + +#### Examples + +This example selects documents that have a `qty` field and its value does not equal `5` or `15`: + +```java +and(exists("qty"), nin("qty", 5, 15)) +``` + +### Evaluation + +The evaluation operator methods include: + +- `mod`: Performs a modulo operation on the value of a field and selects documents with a specified result. +- `regex`: Selects documents where values match a specified regular expression. +- `text`: Selects documemts matching a full-text search expression. +- `where`: Matches documents that satisfy a JavaScript expression. + +#### Examples + +This example assumes a collection that has a text index in the field `abstract`. It selects documents that have a `abstract` field +containing the term `coffee`: + +```java +text("abstract", "coffee") +``` + +### Geospatial + +The geospatial operator methods include: + +- `geoWithin`: Selects all documents containing a field whose value is a GeoJSON geometry that falls within within a bounding GeoJSON +geometry. +- `geoWithinBox`: Selects all documents containing a field with grid coordinates data that exist entirely within the specified box. +- `geoWithinPolygon`: Selects all documents containing a field with grid coordinates data that exist entirely within the specified polygon. +- `geoWithinCenter`: Selects all documents containing a field with grid coordinates data that exist entirely within the specified circle. +- `geoWithinCenterSphere`: Selects geometries containing a field with geospatial data (GeoJSON or legacy coordinate pairs) that exist +entirely within the specified circle, using spherical geometry. +- `geoIntersects`: Selects geometries that intersect with a GeoJSON geometry. The 2dsphere index supports $geoIntersects. +- `near`: Returns geospatial objects in proximity to a point. Requires a geospatial index. The 2dsphere and 2d indexes support $near. +- `nearSphere`: Returns geospatial objects in proximity to a point on a sphere. Requires a geospatial index. The 2dsphere and 2d +indexes support $nearSphere. + +To make it easier to construct GeoJSON-based filters, the driver also include a full GeoJSON class hierarchy: + +- [`Point`]({{< apiref "com/mongodb/client/model/geojson/Point" >}}): A representation of a GeoJSON Point. +- [`MultiPoint`]({{< apiref "com/mongodb/client/model/geojson/MultiPoint" >}}): A representation of a GeoJSON MultiPoint. +- [`LineString`]({{< apiref "com/mongodb/client/model/geojson/LineString" >}}): A representation of a GeoJSON LineString. +- [`MultiLineString`]({{< apiref "com/mongodb/client/model/geojson/MultiLineString" >}}): A representation of a GeoJSON MultiLineString. +- [`Polygon`]({{< apiref "com/mongodb/client/model/geojson/Polygon" >}}): A representation of a GeoJSON Polygon. +- [`MultiPolygon`]({{< apiref "com/mongodb/client/model/geojson/MultiPolygon" >}}): A representation of a GeoJSON MultiPolygon. +- [`GeometryCollection`]({{< apiref "com/mongodb/client/model/geojson/GeometryCollection" >}}): A representation of a GeoJSON +GeometryCollection. + + +#### Examples + +This example creates a filter that selects all documents where the `geo` field contains a GeoJSON Geometry object that falls within the +given polygon: + +```java +Polygon polygon = new Polygon(Arrays.asList(new Position(0, 0), + new Position(4, 0), + new Position(4, 4), + new Position(0, 4), + new Position(0, 0))); +geoWithin('geo', polygon)) +``` + +Similarly, this example creates a filter that selects all documents where the `geo` field contains a GeoJSON Geometry object that +intersects the given Point: + +```java +geoIntersects('geo', new Point(new Position(4, 0))) +``` + + diff --git a/docs/reference/content/builders/index.md b/docs/reference/content/builders/index.md new file mode 100644 index 00000000000..a7cc10d4113 --- /dev/null +++ b/docs/reference/content/builders/index.md @@ -0,0 +1,14 @@ ++++ +date = "2015-03-19T12:53:30-04:00" +title = "Builders" +[menu.main] + identifier = "Builders" + weight = 50 + pre = "" ++++ + +## Builders + +The driver provides several classes that make it easier to use the CRUD API. + +- [Filters]({{< relref "filters.md" >}}): Documentation of the driver's support for query filters From 6618d18b5dc8decd96811bda1e049aa40ef97940 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Sat, 11 Apr 2015 20:50:38 -0400 Subject: [PATCH 0031/1665] Added Aggregates class with static factory methods for aggregate pipeline operators. Added Accumulators class with static factory methods for aggregate group accumulators JAVA-1540 --- .../mongodb/client/model/Accumulators.java | 146 ++++++++++++++ .../com/mongodb/client/model/Aggregates.java | 185 ++++++++++++++++++ .../com/mongodb/client/model/BsonField.java | 65 ++++++ .../mongodb/client/model/BuildersHelper.java | 41 ++++ .../com/mongodb/client/model/Filters.java | 15 +- .../com/mongodb/client/model/Projections.java | 14 ++ .../client/model/SimpleExpression.java | 42 ++++ .../AggregatesFunctionalSpecification.groovy | 147 ++++++++++++++ .../mongodb/client/test/CollectionHelper.java | 19 ++ .../model/AggregatesSpecification.groovy | 133 +++++++++++++ .../model/ProjectionsSpecification.groovy | 6 + 11 files changed, 799 insertions(+), 14 deletions(-) create mode 100644 driver-core/src/main/com/mongodb/client/model/Accumulators.java create mode 100644 driver-core/src/main/com/mongodb/client/model/Aggregates.java create mode 100644 driver-core/src/main/com/mongodb/client/model/BsonField.java create mode 100644 driver-core/src/main/com/mongodb/client/model/BuildersHelper.java create mode 100644 driver-core/src/main/com/mongodb/client/model/SimpleExpression.java create mode 100644 driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy create mode 100644 driver-core/src/test/unit/com/mongodb/client/model/AggregatesSpecification.groovy diff --git a/driver-core/src/main/com/mongodb/client/model/Accumulators.java b/driver-core/src/main/com/mongodb/client/model/Accumulators.java new file mode 100644 index 00000000000..dbc873cd217 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/Accumulators.java @@ -0,0 +1,146 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model; + +/** + * Builders for accumulators used in the group pipeline stage of an aggregation pipeline. + * + * @mongodb.driver.manual core/aggregation-pipeline/ Aggregation pipeline + * @mongodb.driver.manual http://docs.mongodb.org/manual/reference/operator/aggregation/group/#accumulator-operator Accumulators + * @mongodb.driver.manual meta/aggregation-quick-reference/#aggregation-expressions Expressions + * @mongodb.server.release 2.2 + * @since 3.1 + */ +public final class Accumulators { + + /** + * Gets a field name for a $group operation representing the sum of the values of the given expression when applied to all members of + * the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/sum/ $sum + */ + public static BsonField sum(final String fieldName, final TExpression expression) { + return accumulator("$sum", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing the average of the values of the given expression when applied to all + * members of the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/avg/ $avg + */ + public static BsonField avg(final String fieldName, final TExpression expression) { + return accumulator("$avg", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing the value of the given expression when applied to the first member of + * the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/first/ $first + */ + public static BsonField first(final String fieldName, final TExpression expression) { + return accumulator("$first", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing the value of the given expression when applied to the last member of + * the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/last/ $last + */ + public static BsonField last(final String fieldName, final TExpression expression) { + return accumulator("$last", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing the maximum of the values of the given expression when applied to all + * members of the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/max/ $max + */ + public static BsonField max(final String fieldName, final TExpression expression) { + return accumulator("$max", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing the minimum of the values of the given expression when applied to all + * members of the group. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/min/ $min + */ + public static BsonField min(final String fieldName, final TExpression expression) { + return accumulator("$min", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing an array of all values that results from applying an expression to each + * document in a group of documents that share the same group by key. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/push/ $push + */ + public static BsonField push(final String fieldName, final TExpression expression) { + return accumulator("$push", fieldName, expression); + } + + /** + * Gets a field name for a $group operation representing all unique values that results from applying the given expression to each + * document in a group of documents that share the same group by key. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the field + * @mongodb.driver.manual reference/operator/aggregation/addToSet/ $addToSet + */ + public static BsonField addToSet(final String fieldName, final TExpression expression) { + return accumulator("$addToSet", fieldName, expression); + } + + private static BsonField accumulator(final String name, final String fieldName, final TExpression expression) { + return new BsonField(fieldName, new SimpleExpression(name, expression)); + } + + private Accumulators() { + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/Aggregates.java b/driver-core/src/main/com/mongodb/client/model/Aggregates.java new file mode 100644 index 00000000000..8b22d21c587 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/Aggregates.java @@ -0,0 +1,185 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model; + +import org.bson.BsonDocument; +import org.bson.BsonDocumentWriter; +import org.bson.BsonInt32; +import org.bson.BsonString; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.conversions.Bson; + +import java.util.Arrays; +import java.util.List; + +/** + * Builders for aggregation pipeline stages. + * + * @mongodb.driver.manual core/aggregation-pipeline/ Aggregation pipeline + * @mongodb.server.release 2.2 + * @since 3.1 + */ +public final class Aggregates { + + /** + * Creates a $match pipeline stage for the specified filter + * + * @param filter the filter to match + * @return the $match pipeline stage + * @see Filters + * @mongodb.driver.manual reference/operator/aggregation/match/ $match + */ + public static Bson match(final Bson filter) { + return new SimplePipelineStage("$match", filter); + } + + /** + * Creates a $project pipeline stage for the specified projection + * + * @param projection the projection + * @return the $project pipeline stage + * @see Projections + * @mongodb.driver.manual reference/operator/aggregation/match/ $match + */ + public static Bson project(final Bson projection) { + return new SimplePipelineStage("$project", projection); + } + + /** + * Creates a $sort pipeline stage for the specified sort specification + * + * @param sort the sort specification + * @return the $sort pipeline stage + * @see Sorts + * @mongodb.driver.manual reference/operator/aggregation/sort/#sort-aggregation $sort + */ + public static Bson sort(final Bson sort) { + return new SimplePipelineStage("$sort", sort); + } + + /** + * Creates a $skip pipeline stage + * + * @param skip the number of documents to skip + * @return the $skip pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/skip/ $skip + */ + public static Bson skip(final int skip) { + return new BsonDocument("$skip", new BsonInt32(skip)); + } + + /** + * Creates a $limit pipeline stage for the specified filter + * + * @param limit the limit + * @return the $limit pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/limit/ $limit + */ + public static Bson limit(final int limit) { + return new BsonDocument("$limit", new BsonInt32(limit)); + } + + /** + * Creates a $group pipeline stage for the specified filter + * + * @param the expression type + * @param id the id expression for the group + * @param fieldAccumulators zero or more field accumulator pairs + * @return the $group pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/group/ $group + * @mongodb.driver.manual meta/aggregation-quick-reference/#aggregation-expressions Expressions + */ + public static Bson group(final TExpression id, final BsonField... fieldAccumulators) { + return group(id, Arrays.asList(fieldAccumulators)); + } + + /** + * Creates a $group pipeline stage for the specified filter + * + * @param the expression type + * @param id the id expression for the group + * @param fieldAccumulators zero or more field accumulator pairs + * @return the $group pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/group/ $group + * @mongodb.driver.manual meta/aggregation-quick-reference/#aggregation-expressions Expressions + */ + public static Bson group(final TExpression id, final List fieldAccumulators) { + return new Bson() { + @Override + public BsonDocument toBsonDocument(final Class tDocumentClass, final CodecRegistry codecRegistry) { + BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); + + writer.writeStartDocument(); + + writer.writeStartDocument("$group"); + + writer.writeName("_id"); + BuildersHelper.encodeValue(writer, id, codecRegistry); + + for (BsonField fieldAccumulator : fieldAccumulators) { + writer.writeName(fieldAccumulator.getName()); + BuildersHelper.encodeValue(writer, fieldAccumulator.getValue(), codecRegistry); + } + + writer.writeEndDocument(); + writer.writeEndDocument(); + + return writer.getDocument(); + } + }; + } + + /** + * Creates a $unwind pipeline stage for the specified field name, which must be prefixed by a {@code '$'} sign. + * + * @param fieldName the field name, prefixed by a {@code '$' sign} + * @return the $group pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/unwind/ $unwind + */ + public static Bson unwind(final String fieldName) { + return new BsonDocument("$unwind", new BsonString(fieldName)); + } + + + /** + * Creates a $limit pipeline stage for the specified filter + * + * @param collectionName the collection name + * @return the $out pipeline stage + * @mongodb.driver.manual reference/operator/aggregation/out/ $out + * @mongodb.server.release 2.6 + */ + public static Bson out(final String collectionName) { + return new BsonDocument("$out", new BsonString(collectionName)); + } + + private static class SimplePipelineStage implements Bson { + private final String name; + private final Bson value; + + public SimplePipelineStage(final String name, final Bson value) { + this.name = name; + this.value = value; + } + + @Override + public BsonDocument toBsonDocument(final Class documentClass, final CodecRegistry codecRegistry) { + return new BsonDocument(name, value.toBsonDocument(documentClass, codecRegistry)); + } + } + + private Aggregates() { + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/BsonField.java b/driver-core/src/main/com/mongodb/client/model/BsonField.java new file mode 100644 index 00000000000..a2add549755 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/BsonField.java @@ -0,0 +1,65 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model; + +import org.bson.conversions.Bson; + +import static com.mongodb.assertions.Assertions.notNull; + +/** + * A representation of a BSON document field whose value is another BSON document. + * + * @since 3.1 + * @see Aggregates#group(Object, BsonField...) + */ +public final class BsonField { + private final String name; + private final Bson value; + + /** + * Construct an instance + * + * @param name the field name + * @param value the field value + */ + public BsonField(final String name, final Bson value) { + this.name = notNull("name", name); + this.value = notNull("value", value); + } + + /** + * Gets the field name + * @return the field name + */ + public String getName() { + return name; + } + + /** + * Gets the field value + * @return the field value + */ + public Bson getValue() { + return value; + } + + @Override + public String toString() { + return "BsonField{" + + "name='" + name + '\'' + + ", value=" + value + + '}'; + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/BuildersHelper.java b/driver-core/src/main/com/mongodb/client/model/BuildersHelper.java new file mode 100644 index 00000000000..7b7468f67be --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/BuildersHelper.java @@ -0,0 +1,41 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model; + +import org.bson.BsonDocument; +import org.bson.BsonDocumentWriter; +import org.bson.codecs.Encoder; +import org.bson.codecs.EncoderContext; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.conversions.Bson; + +final class BuildersHelper { + + @SuppressWarnings("unchecked") + static void encodeValue(final BsonDocumentWriter writer, final TItem value, final CodecRegistry codecRegistry) { + if (value == null) { + writer.writeNull(); + } else if (value instanceof Bson) { + ((Encoder) codecRegistry.get(BsonDocument.class)).encode(writer, + ((Bson) value).toBsonDocument(BsonDocument.class, codecRegistry), + EncoderContext.builder().build()); + } else { + ((Encoder) codecRegistry.get(value.getClass())).encode(writer, value, EncoderContext.builder().build()); + } + } + + private BuildersHelper() { + } +} diff --git a/driver-core/src/main/com/mongodb/client/model/Filters.java b/driver-core/src/main/com/mongodb/client/model/Filters.java index 0f3afdcd197..4cb370787d1 100644 --- a/driver-core/src/main/com/mongodb/client/model/Filters.java +++ b/driver-core/src/main/com/mongodb/client/model/Filters.java @@ -29,8 +29,6 @@ import org.bson.BsonString; import org.bson.BsonType; import org.bson.BsonValue; -import org.bson.codecs.Encoder; -import org.bson.codecs.EncoderContext; import org.bson.codecs.configuration.CodecRegistry; import org.bson.conversions.Bson; @@ -40,6 +38,7 @@ import java.util.regex.Pattern; import static com.mongodb.assertions.Assertions.notNull; +import static com.mongodb.client.model.BuildersHelper.encodeValue; import static java.util.Arrays.asList; /** @@ -929,18 +928,6 @@ public BsonDocument toBsonDocument(final Class documentCl } } - @SuppressWarnings("unchecked") - private static void encodeValue(final BsonDocumentWriter writer, final TItem value, final CodecRegistry codecRegistry) { - if (value == null) { - writer.writeNull(); - } else if (value instanceof Bson) { - ((Encoder) codecRegistry.get(BsonDocument.class)).encode(writer, - ((Bson) value).toBsonDocument(BsonDocument.class, codecRegistry), EncoderContext.builder().build()); - } else { - ((Encoder) codecRegistry.get(value.getClass())).encode(writer, value, EncoderContext.builder().build()); - } - } - private static class NotFilter implements Bson { private final Bson filter; diff --git a/driver-core/src/main/com/mongodb/client/model/Projections.java b/driver-core/src/main/com/mongodb/client/model/Projections.java index 300634ead3c..2f0e2e62a22 100644 --- a/driver-core/src/main/com/mongodb/client/model/Projections.java +++ b/driver-core/src/main/com/mongodb/client/model/Projections.java @@ -43,6 +43,20 @@ public final class Projections { private Projections() { } + /** + * Creates a projection of a field whose value is computed from the given expression. Projection with an expression is only supported + * using the $project aggregation pipeline stage. + * + * @param fieldName the field name + * @param expression the expression + * @param the expression type + * @return the projection + * @see Aggregates#project(Bson) + */ + public static Bson computed(final String fieldName, final TExpression expression) { + return new SimpleExpression(fieldName, expression); + } + /** * Creates a projection that includes all of the given fields. * diff --git a/driver-core/src/main/com/mongodb/client/model/SimpleExpression.java b/driver-core/src/main/com/mongodb/client/model/SimpleExpression.java new file mode 100644 index 00000000000..8ab8b8255f6 --- /dev/null +++ b/driver-core/src/main/com/mongodb/client/model/SimpleExpression.java @@ -0,0 +1,42 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model; + +import org.bson.BsonDocument; +import org.bson.BsonDocumentWriter; +import org.bson.codecs.configuration.CodecRegistry; +import org.bson.conversions.Bson; + +class SimpleExpression implements Bson { + private final String name; + private final TExpression expression; + + public SimpleExpression(final String name, final TExpression expression) { + this.name = name; + this.expression = expression; + } + + @Override + public BsonDocument toBsonDocument(final Class documentClass, final CodecRegistry codecRegistry) { + BsonDocumentWriter writer = new BsonDocumentWriter(new BsonDocument()); + + writer.writeStartDocument(); + writer.writeName(name); + BuildersHelper.encodeValue(writer, expression, codecRegistry); + writer.writeEndDocument(); + + return writer.getDocument(); + } +} diff --git a/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy new file mode 100644 index 00000000000..c2d0e53c11d --- /dev/null +++ b/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy @@ -0,0 +1,147 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.MongoNamespace +import com.mongodb.OperationFunctionalSpecification +import org.bson.Document +import org.bson.conversions.Bson + +import static com.mongodb.client.model.Accumulators.addToSet +import static com.mongodb.client.model.Accumulators.avg +import static com.mongodb.client.model.Accumulators.first +import static com.mongodb.client.model.Aggregates.group +import static com.mongodb.client.model.Accumulators.last +import static com.mongodb.client.model.Aggregates.limit +import static com.mongodb.client.model.Aggregates.match +import static com.mongodb.client.model.Accumulators.max +import static com.mongodb.client.model.Accumulators.min +import static com.mongodb.client.model.Aggregates.out +import static com.mongodb.client.model.Aggregates.project +import static com.mongodb.client.model.Accumulators.push +import static com.mongodb.client.model.Aggregates.skip +import static com.mongodb.client.model.Aggregates.sort +import static com.mongodb.client.model.Accumulators.sum +import static com.mongodb.client.model.Aggregates.unwind +import static com.mongodb.client.model.Filters.exists +import static com.mongodb.client.model.Projections.computed +import static com.mongodb.client.model.Projections.excludeId +import static com.mongodb.client.model.Projections.fields +import static com.mongodb.client.model.Projections.include +import static com.mongodb.client.model.Sorts.descending + +class AggregatesFunctionalSpecification extends OperationFunctionalSpecification { + + def a = new Document('_id', 1).append('x', 1) + .append('y', 'a') + .append('z', false) + .append('a', [1, 2, 3]) + .append('a1', [new Document('c', 1).append('d', 2), new Document('c', 2).append('d', 3)]) + + def b = new Document('_id', 2).append('x', 2) + .append('y', 'b') + .append('z', true) + .append('a', [3, 4, 5, 6]) + .append('a1', [new Document('c', 2).append('d', 3), new Document('c', 3).append('d', 4)]) + + def c = new Document('_id', 3).append('x', 3) + .append('y', 'c') + .append('z', true) + + def setup() { + getCollectionHelper().insertDocuments(a, b, c) + } + + + def aggregate(List pipeline) { + getCollectionHelper().aggregate(pipeline) + } + + def '$match'() { + expect: + aggregate([match(exists('a1'))]) == [a, b] + } + + def '$project'() { + expect: + aggregate([project(fields(include('x'), computed('c', '$y')))]) == [new Document('_id', 1).append('x', 1).append('c', 'a'), + new Document('_id', 2).append('x', 2).append('c', 'b'), + new Document('_id', 3).append('x', 3).append('c', 'c')] + } + + def '$sort'() { + expect: + aggregate([sort(descending('x'))]) == [c, b, a] + } + + def '$skip'() { + expect: + aggregate([skip(1)]) == [b, c] + } + + def '$limit'() { + expect: + aggregate([limit(2)]) == [a, b] + } + + def '$unwind'() { + expect: + aggregate([project(fields(include('a'), excludeId())), unwind('$a')]) == [new Document('a', 1), + new Document('a', 2), + new Document('a', 3), + new Document('a', 3), + new Document('a', 4), + new Document('a', 5), + new Document('a', 6)] + } + + def '$group'() { + expect: + aggregate([group(null)]) == [new Document('_id', null)] + + aggregate([group('$z')]) == [new Document('_id', true), + new Document('_id', false)] + + aggregate([group(null, sum('acc', '$x'))]) == [new Document('_id', null).append('acc', 6)] + + aggregate([group(null, avg('acc', '$x'))]) == [new Document('_id', null).append('acc', 2)] + + aggregate([group(null, first('acc', '$x'))]) == [new Document('_id', null).append('acc', 1)] + + aggregate([group(null, last('acc', '$x'))]) == [new Document('_id', null).append('acc', 3)] + + aggregate([group(null, max('acc', '$x'))]) == [new Document('_id', null).append('acc', 3)] + + aggregate([group(null, min('acc', '$x'))]) == [new Document('_id', null).append('acc', 1)] + + aggregate([group('$z', push('acc', '$z'))]) == [new Document('_id', true).append('acc', [true, true]), + new Document('_id', false).append('acc', [false])] + + aggregate([group('$z', addToSet('acc', '$z'))]) == [new Document('_id', true).append('acc', [true]), + new Document('_id', false).append('acc', [false])] + } + + def '$out'() { + given: + def outCollectionName = getCollectionName() + '.out' + + when: + aggregate([out(outCollectionName)]) + + then: + getCollectionHelper(new MongoNamespace(getDatabaseName(), outCollectionName)).find() == [a, b, c] + } + +} diff --git a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java index 040d989b0eb..d4ed44f1df4 100644 --- a/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java +++ b/driver-core/src/test/functional/com/mongodb/client/test/CollectionHelper.java @@ -26,6 +26,7 @@ import com.mongodb.bulk.InsertRequest; import com.mongodb.client.model.CreateCollectionOptions; import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; +import com.mongodb.operation.AggregateOperation; import com.mongodb.operation.BatchCursor; import com.mongodb.operation.CountOperation; import com.mongodb.operation.CreateCollectionOperation; @@ -158,6 +159,24 @@ public List find(final Bson filter) { return find(filter, null); } + public List aggregate(final List pipeline) { + return aggregate(pipeline, codec); + } + + public List aggregate(final List pipeline, final Decoder decoder) { + List bsonDocumentPipeline = new ArrayList(); + for (Bson cur : pipeline) { + bsonDocumentPipeline.add(cur.toBsonDocument(Document.class, registry)); + } + BatchCursor cursor = new AggregateOperation(namespace, bsonDocumentPipeline, decoder) + .execute(getBinding()); + List results = new ArrayList(); + while (cursor.hasNext()) { + results.addAll(cursor.next()); + } + return results; + } + public List find(final Bson filter, final Bson sort) { return find(filter != null ? filter.toBsonDocument(Document.class, registry) : null, sort != null ? sort.toBsonDocument(Document.class, registry) : null, diff --git a/driver-core/src/test/unit/com/mongodb/client/model/AggregatesSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/AggregatesSpecification.groovy new file mode 100644 index 00000000000..e9e047b31e0 --- /dev/null +++ b/driver-core/src/test/unit/com/mongodb/client/model/AggregatesSpecification.groovy @@ -0,0 +1,133 @@ +/* + * Copyright 2015 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.mongodb.client.model + +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider +import org.bson.BsonDocument +import org.bson.codecs.BsonValueCodecProvider +import org.bson.codecs.ValueCodecProvider +import org.bson.conversions.Bson +import spock.lang.Specification + +import static com.mongodb.client.model.Accumulators.addToSet +import static com.mongodb.client.model.Accumulators.avg +import static com.mongodb.client.model.Accumulators.first +import static com.mongodb.client.model.Aggregates.group +import static com.mongodb.client.model.Accumulators.last +import static com.mongodb.client.model.Aggregates.limit +import static com.mongodb.client.model.Aggregates.match +import static com.mongodb.client.model.Accumulators.max +import static com.mongodb.client.model.Accumulators.min +import static com.mongodb.client.model.Aggregates.out +import static com.mongodb.client.model.Aggregates.project +import static com.mongodb.client.model.Accumulators.push +import static com.mongodb.client.model.Aggregates.skip +import static com.mongodb.client.model.Aggregates.sort +import static com.mongodb.client.model.Accumulators.sum +import static com.mongodb.client.model.Aggregates.unwind +import static com.mongodb.client.model.Filters.eq +import static com.mongodb.client.model.Projections.computed +import static com.mongodb.client.model.Projections.fields +import static com.mongodb.client.model.Projections.include +import static com.mongodb.client.model.Sorts.ascending +import static org.bson.BsonDocument.parse +import static org.bson.codecs.configuration.CodecRegistries.fromProviders + +class AggregatesSpecification extends Specification { + def registry = fromProviders([new BsonValueCodecProvider(), new ValueCodecProvider(), new GeoJsonCodecProvider()]) + + def 'should render $match'() { + expect: + toBson(match(eq('author', 'dave'))) == parse('{ $match : { author : "dave" } }') + } + + def 'should render $project'() { + expect: + toBson(project(fields(include('title', 'author'), computed('lastName', '$author.last')))) == + parse('{ $project : { title : 1 , author : 1, lastName : "$author.last" } }') + } + + def 'should render $sort'() { + expect: + toBson(sort(ascending('title', 'author'))) == parse('{ $sort : { title : 1 , author : 1 } }') + } + + def 'should render $limit'() { + expect: + toBson(limit(5)) == parse('{ $limit : 5 }') + } + + def 'should render $skip'() { + expect: + toBson(skip(5)) == parse('{ $skip : 5 }') + } + + def 'should render $unwind'() { + expect: + toBson(unwind('$sizes')) == parse('{ $unwind : "$sizes" }') + } + + def 'should render $out'() { + expect: + toBson(out('authors')) == parse('{ $out : "authors" }') + } + + def 'should render $group'() { + expect: + toBson(group('$customerId')) == parse('{ $group : { _id : "$customerId" } }') + toBson(group(null)) == parse('{ $group : { _id : null } }') + + toBson(group(parse('{ month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } }'))) == + parse('{ $group : { _id : { month: { $month: "$date" }, day: { $dayOfMonth: "$date" }, year: { $year: "$date" } } } }') + + + def groupDocument = parse('''{ + $group : { + _id : null, + sum: { $sum: { $multiply: [ "$price", "$quantity" ] } }, + avg: { $avg: "$quantity" }, + min: { $min: "$quantity" } + max: { $max: "$quantity" } + first: { $first: "$quantity" } + last: { $last: "$quantity" } + all: { $push: "$quantity" } + unique: { $addToSet: "$quantity" } + } + }''') + toBson(group(null, + sum('sum', parse('{ $multiply: [ "$price", "$quantity" ] }')), + avg('avg', '$quantity'), + min('min', '$quantity'), + max('max', '$quantity'), + first('first', '$quantity'), + last('last', '$quantity'), + push('all', '$quantity'), + addToSet('unique', '$quantity'))) == groupDocument + + toBson(group(null, + [sum('sum', parse('{ $multiply: [ "$price", "$quantity" ] }')), + avg('avg', '$quantity'), + min('min', '$quantity'), + max('max', '$quantity'), + first('first', '$quantity'), + last('last', '$quantity'), + push('all', '$quantity'), + addToSet('unique', '$quantity')])) == groupDocument + } + + def toBson(Bson bson) { + bson.toBsonDocument(BsonDocument, registry) + } +} diff --git a/driver-core/src/test/unit/com/mongodb/client/model/ProjectionsSpecification.groovy b/driver-core/src/test/unit/com/mongodb/client/model/ProjectionsSpecification.groovy index e1e6f7c89b1..3899d46f586 100644 --- a/driver-core/src/test/unit/com/mongodb/client/model/ProjectionsSpecification.groovy +++ b/driver-core/src/test/unit/com/mongodb/client/model/ProjectionsSpecification.groovy @@ -24,6 +24,7 @@ import spock.lang.Specification import static com.mongodb.client.model.Filters.and import static com.mongodb.client.model.Filters.eq +import static com.mongodb.client.model.Projections.computed import static com.mongodb.client.model.Projections.elemMatch import static com.mongodb.client.model.Projections.exclude import static com.mongodb.client.model.Projections.excludeId @@ -78,6 +79,11 @@ class ProjectionsSpecification extends Specification { toBson(metaTextScore('x')) == parse('{x : {$meta : "textScore"}}') } + def 'computed'() { + expect: + toBson(computed('c', '$y')) == parse('{c : "$y"}') + } + def 'combine fields'() { expect: toBson(fields(include('x', 'y'), exclude('_id'))) == parse('{x : 1, y : 1, _id : 0}') From 074be83efa4d0160172635c997ec68ab5532f23f Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Wed, 22 Apr 2015 13:59:25 -0400 Subject: [PATCH 0032/1665] Added aggregation builder reference documentation. JAVA-1540 --- .../reference/content/builders/aggregation.md | 155 ++++++++++++++++++ docs/reference/content/builders/index.md | 4 +- 2 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 docs/reference/content/builders/aggregation.md diff --git a/docs/reference/content/builders/aggregation.md b/docs/reference/content/builders/aggregation.md new file mode 100644 index 00000000000..9253f9a625c --- /dev/null +++ b/docs/reference/content/builders/aggregation.md @@ -0,0 +1,155 @@ ++++ +date = "2015-03-19T14:27:51-04:00" +title = "Aggregation" +[menu.main] + parent = "Builders" + weight = 20 + pre = "" ++++ + +## Aggregation + +The [`Aggregates`]({{< apiref "com/mongodb/client/model/Aggregates" >}}) class provides static factory methods that build [aggregation +pipeline operators](http://docs.mongodb.org/manual/reference/operator/aggregation/). Each method returns an instance of the +[`Bson`]({{< relref "bson/documents.md#bson" >}}) type, which can in turn be passed to the `aggregate` method of `MongoCollection`. + +For brevity, you may choose to import the methods of the `Aggregates` class statically: + +```java +import com.mongodb.client.model.Aggregates.*; +``` + +All the examples below assume this static import. + +### Match + +The [`$match`](http://docs.mongodb.org/manual/reference/operator/aggregation/match/) pipeline stage passes all documents matching the +specified filter to the next stage. Though the filter can be an instance of any class that implements `Bson`, it's convenient to +combine with use of the [`Filters`]({{< apiref "com/mongodb/client/model/Filters" >}}) class. In the example below, it's assumed that the +`eq` method of the `Filters` class has been statically imported. + +This example creates a pipeline stage that matches all documents where the `author` field is equal to `"Dave"`: + +```java +match(eq("author", "Dave")) +``` + +### Project + +The [`$project`](http://docs.mongodb.org/manual/reference/operator/aggregation/project/) pipeline stage passes the projected fields of all +documents to the next stage. Though the projection can be an instance of any class that implements `Bson`, it's convenient to combine +with use of the [`Projections`]({{< apiref "com/mongodb/client/model/Projections" >}}) class. In the example below, it's assumed that the +`include`, `excludeId`, and `fields` methods of the `Projections` class have been statically imported. + +This example creates a pipeline stage that excludes the `_id` field but includes the `title` and `author` fields: + +```java +project(fields(include("title", "author"), excludeId())) +``` + +#### Projecting Computed Fields + +The `$project` stage can project computed fields as well. + +This example simply projects the `qty` field into a new field called `quantity`. In other words, it renames the field: + +```java +project(computed("quantity", "$qty")) +``` + +### Sort + +The [`$sort`](http://docs.mongodb.org/manual/reference/operator/aggregation/sort/) pipeline stage passes all documents to the next stage, +sorted by the specified sort criteria. Though the sort criteria can be an instance of any class that implements `Bson`, it's convenient to +combine with use of the [`Sorts`]({{< apiref "com/mongodb/client/model/Sorts" >}}) class. In the example below, it's assumed that the +`descending`, `ascending`, and `orderBy` methods of the `Sorts` class have been statically imported. + +This example creates a pipeline stage that sorts in descending order according to the value of the `age` field and then in ascending order +according to the value of the `posts` field: + +```java +sort(orderBy(descending("age"), ascending("posts"))) +``` + +### Skip + +The [`$skip`](http://docs.mongodb.org/manual/reference/operator/aggregation/skip/) pipeline stage skips over the specified number of +documents that pass into the stage and passes the remaining documents to the next stage. + +This example skips the first `5` documents: + +```java +skip(5) +``` + +### Limit + +The [`$limit`](http://docs.mongodb.org/manual/reference/operator/aggregation/limit/) pipeline stage limits the number of documents passed +to the next stage. + +This example limits the number of documents to `10`: + +```java +limit(10) +``` + +### Group + +The [`$group`](http://docs.mongodb.org/manual/reference/operator/aggregation/group/) pipeline stage groups documents by some specified +expression and outputs to the next stage a document for each distinct grouping. A group consists of an `_id` which specifies the +expression on which to group, and zero or more +[accumulators](http://docs.mongodb.org/manual/reference/operator/aggregation/group/#accumulator-operator) which are evaluated for each +grouping. To simplify the expression of accumulators, the driver includes an +[`Accumulators`]({{< apiref "com/mongodb/client/model/Aggregates" >}}) class with static factory methods for each of the supported +accumulators. In the example below, it's assumed that the `sum` and `avg` methods of the `Accumulators` class have been statically +imported. + +This example groups documents by the value of the `customerId` field, and for each group accumulates the sum and average of the values of +the `quantity` field into the `totalQuantity` and `averageQuantity` fields, respectively. + +```java +group("$customerId", sum('totalQuantity', '$quantity'), avg('averageQuantity', '$quantity')) +``` + +### Unwind + +The [`$unwind`](http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/) pipeline stage deconstructs an array field from the +input documents to output a document for each element. + +This example outputs, for each document, a document for each element in the `sizes` array: + +```java +unwind("$sizes") +``` + +### Out + +The [`$out`](http://docs.mongodb.org/manual/reference/operator/aggregation/out/) pipeline stage outputs all documents to the specified +collection. It must be the last stage in any aggregate pipeline: + +This example writes the pipeline to the `authors` collection: + +```java +out("authors") +``` + +### Creating a Pipeline + +The above pipeline operators are typically combined into a list and passed to the `aggregate` method of a `MongoCollection`. For instance: + +```java +collection.aggregate(Arrays.asList(match(eq("author", "Dave")), + group("$customerId", sum('totalQuantity', '$quantity'), + avg('averageQuantity', '$quantity')) + out("authors"))); +``` + + + + + + + + + + diff --git a/docs/reference/content/builders/index.md b/docs/reference/content/builders/index.md index a7cc10d4113..b8bff03dbcf 100644 --- a/docs/reference/content/builders/index.md +++ b/docs/reference/content/builders/index.md @@ -11,4 +11,6 @@ title = "Builders" The driver provides several classes that make it easier to use the CRUD API. -- [Filters]({{< relref "filters.md" >}}): Documentation of the driver's support for query filters +- [Filters]({{< relref "filters.md" >}}): Documentation of the driver's support for building query filters +- [Aggregation]({{< relref "aggregation.md" >}}): Documentation of the driver's support for building aggregation pipelines + From 374ab5fdab71a6c531f754f74092b50d49a116e5 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 23 Apr 2015 14:42:26 -0400 Subject: [PATCH 0033/1665] Replaced full docs.mongodb.org hyperlinks with docsref shorttag JAVA-1540 --- .../reference/content/builders/aggregation.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/reference/content/builders/aggregation.md b/docs/reference/content/builders/aggregation.md index 9253f9a625c..467271e4fbd 100644 --- a/docs/reference/content/builders/aggregation.md +++ b/docs/reference/content/builders/aggregation.md @@ -10,7 +10,7 @@ title = "Aggregation" ## Aggregation The [`Aggregates`]({{< apiref "com/mongodb/client/model/Aggregates" >}}) class provides static factory methods that build [aggregation -pipeline operators](http://docs.mongodb.org/manual/reference/operator/aggregation/). Each method returns an instance of the +pipeline operators]({{< docsref "reference/operator/aggregation/" >}}). Each method returns an instance of the [`Bson`]({{< relref "bson/documents.md#bson" >}}) type, which can in turn be passed to the `aggregate` method of `MongoCollection`. For brevity, you may choose to import the methods of the `Aggregates` class statically: @@ -23,7 +23,7 @@ All the examples below assume this static import. ### Match -The [`$match`](http://docs.mongodb.org/manual/reference/operator/aggregation/match/) pipeline stage passes all documents matching the +The [`$match`]({{< docsref "reference/operator/aggregation/match/" >}}) pipeline stage passes all documents matching the specified filter to the next stage. Though the filter can be an instance of any class that implements `Bson`, it's convenient to combine with use of the [`Filters`]({{< apiref "com/mongodb/client/model/Filters" >}}) class. In the example below, it's assumed that the `eq` method of the `Filters` class has been statically imported. @@ -36,7 +36,7 @@ match(eq("author", "Dave")) ### Project -The [`$project`](http://docs.mongodb.org/manual/reference/operator/aggregation/project/) pipeline stage passes the projected fields of all +The [`$project`]({{< docsref "reference/operator/aggregation/project/" >}}) pipeline stage passes the projected fields of all documents to the next stage. Though the projection can be an instance of any class that implements `Bson`, it's convenient to combine with use of the [`Projections`]({{< apiref "com/mongodb/client/model/Projections" >}}) class. In the example below, it's assumed that the `include`, `excludeId`, and `fields` methods of the `Projections` class have been statically imported. @@ -59,7 +59,7 @@ project(computed("quantity", "$qty")) ### Sort -The [`$sort`](http://docs.mongodb.org/manual/reference/operator/aggregation/sort/) pipeline stage passes all documents to the next stage, +The [`$sort`]({{< docsref "reference/operator/aggregation/sort/" >}}) pipeline stage passes all documents to the next stage, sorted by the specified sort criteria. Though the sort criteria can be an instance of any class that implements `Bson`, it's convenient to combine with use of the [`Sorts`]({{< apiref "com/mongodb/client/model/Sorts" >}}) class. In the example below, it's assumed that the `descending`, `ascending`, and `orderBy` methods of the `Sorts` class have been statically imported. @@ -73,7 +73,7 @@ sort(orderBy(descending("age"), ascending("posts"))) ### Skip -The [`$skip`](http://docs.mongodb.org/manual/reference/operator/aggregation/skip/) pipeline stage skips over the specified number of +The [`$skip`]({{< docsref "reference/operator/aggregation/skip/" >}}) pipeline stage skips over the specified number of documents that pass into the stage and passes the remaining documents to the next stage. This example skips the first `5` documents: @@ -84,7 +84,7 @@ skip(5) ### Limit -The [`$limit`](http://docs.mongodb.org/manual/reference/operator/aggregation/limit/) pipeline stage limits the number of documents passed +The [`$limit`]({{< docsref "reference/operator/aggregation/limit/" >}}) pipeline stage limits the number of documents passed to the next stage. This example limits the number of documents to `10`: @@ -95,10 +95,10 @@ limit(10) ### Group -The [`$group`](http://docs.mongodb.org/manual/reference/operator/aggregation/group/) pipeline stage groups documents by some specified +The [`$group`]({{< docsref "reference/operator/aggregation/group/" >}}) pipeline stage groups documents by some specified expression and outputs to the next stage a document for each distinct grouping. A group consists of an `_id` which specifies the expression on which to group, and zero or more -[accumulators](http://docs.mongodb.org/manual/reference/operator/aggregation/group/#accumulator-operator) which are evaluated for each +[accumulators]({{< docsref "reference/operator/aggregation/group/#accumulator-operator" >}}) which are evaluated for each grouping. To simplify the expression of accumulators, the driver includes an [`Accumulators`]({{< apiref "com/mongodb/client/model/Aggregates" >}}) class with static factory methods for each of the supported accumulators. In the example below, it's assumed that the `sum` and `avg` methods of the `Accumulators` class have been statically @@ -113,7 +113,7 @@ group("$customerId", sum('totalQuantity', '$quantity'), avg('averageQuantity', ' ### Unwind -The [`$unwind`](http://docs.mongodb.org/manual/reference/operator/aggregation/unwind/) pipeline stage deconstructs an array field from the +The [`$unwind`]({{< docsref "reference/operator/aggregation/unwind/" >}}) pipeline stage deconstructs an array field from the input documents to output a document for each element. This example outputs, for each document, a document for each element in the `sizes` array: @@ -124,7 +124,7 @@ unwind("$sizes") ### Out -The [`$out`](http://docs.mongodb.org/manual/reference/operator/aggregation/out/) pipeline stage outputs all documents to the specified +The [`$out`]({{< docsref "reference/operator/aggregation/out/" >}}) pipeline stage outputs all documents to the specified collection. It must be the last stage in any aggregate pipeline: This example writes the pipeline to the `authors` collection: From d79e6fcc2d245bc7a6c904023b548fbf1984d861 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 23 Apr 2015 18:02:55 -0400 Subject: [PATCH 0034/1665] Ignore aggregate $out functional specification for server versions that don't support it JAVA-1540 --- .../client/model/AggregatesFunctionalSpecification.groovy | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy b/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy index c2d0e53c11d..248c13097c7 100644 --- a/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy +++ b/driver-core/src/test/functional/com/mongodb/client/model/AggregatesFunctionalSpecification.groovy @@ -18,7 +18,9 @@ import com.mongodb.MongoNamespace import com.mongodb.OperationFunctionalSpecification import org.bson.Document import org.bson.conversions.Bson +import spock.lang.IgnoreIf +import static com.mongodb.ClusterFixture.serverVersionAtLeast import static com.mongodb.client.model.Accumulators.addToSet import static com.mongodb.client.model.Accumulators.avg import static com.mongodb.client.model.Accumulators.first @@ -41,6 +43,7 @@ import static com.mongodb.client.model.Projections.excludeId import static com.mongodb.client.model.Projections.fields import static com.mongodb.client.model.Projections.include import static com.mongodb.client.model.Sorts.descending +import static java.util.Arrays.asList class AggregatesFunctionalSpecification extends OperationFunctionalSpecification { @@ -133,6 +136,7 @@ class AggregatesFunctionalSpecification extends OperationFunctionalSpecification new Document('_id', false).append('acc', [false])] } + @IgnoreIf({ !serverVersionAtLeast(asList(2, 6, 0)) }) def '$out'() { given: def outCollectionName = getCollectionName() + '.out' From bf62469ad9a127a321549047840298ca712361a5 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Thu, 23 Apr 2015 16:29:31 +0100 Subject: [PATCH 0035/1665] Added the required filter parameter to MongoCollection.distinct() --- .../async/client/DistinctIterableImpl.java | 3 ++- .../mongodb/async/client/MongoCollection.java | 14 ++++++++++++- .../async/client/MongoCollectionImpl.java | 7 ++++++- .../com/mongodb/async/client/CrudTest.java | 3 +-- .../DistinctIterableSpecification.groovy | 11 ++++++---- .../MongoCollectionSpecification.groovy | 21 ++++++++++++------- .../com/mongodb/DistinctIterableImpl.java | 3 ++- .../main/com/mongodb/MongoCollectionImpl.java | 7 ++++++- .../com/mongodb/client/MongoCollection.java | 14 ++++++++++++- .../core/CollectionAcceptanceTest.java | 5 +++++ .../DistinctIterableSpecification.groovy | 11 ++++++---- .../MongoCollectionSpecification.groovy | 17 ++++++++++++++- 12 files changed, 92 insertions(+), 24 deletions(-) diff --git a/driver-async/src/main/com/mongodb/async/client/DistinctIterableImpl.java b/driver-async/src/main/com/mongodb/async/client/DistinctIterableImpl.java index 1c193f96565..493cd235065 100644 --- a/driver-async/src/main/com/mongodb/async/client/DistinctIterableImpl.java +++ b/driver-async/src/main/com/mongodb/async/client/DistinctIterableImpl.java @@ -47,7 +47,7 @@ class DistinctIterableImpl implements DistinctIterable documentClass, final Class resultClass, final CodecRegistry codecRegistry, final ReadPreference readPreference, final AsyncOperationExecutor executor, - final String fieldName) { + final String fieldName, final Bson filter) { this.namespace = notNull("namespace", namespace); this.documentclass = notNull("documentClass", documentClass); this.resultClass = notNull("resultClass", resultClass); @@ -55,6 +55,7 @@ class DistinctIterableImpl implements DistinctIterable { */ DistinctIterable distinct(String fieldName, Class resultClass); + /** + * Gets the distinct values of the specified field name. + * + * @param fieldName the field name + * @param filter the query filter + * @param resultClass the default class to cast any distinct items into. + * @param the target type of the iterable. + * @return an iterable of distinct values + * @mongodb.driver.manual reference/command/distinct/ Distinct + */ + DistinctIterable distinct(String fieldName, Bson filter, Class resultClass); + /** * Finds all documents in the collection. * diff --git a/driver-async/src/main/com/mongodb/async/client/MongoCollectionImpl.java b/driver-async/src/main/com/mongodb/async/client/MongoCollectionImpl.java index 400745f1dcf..9bd5935fff1 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoCollectionImpl.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoCollectionImpl.java @@ -172,8 +172,13 @@ public void count(final Bson filter, final CountOptions options, final SingleRes @Override public DistinctIterable distinct(final String fieldName, final Class resultClass) { + return distinct(fieldName, new BsonDocument(), resultClass); + } + + @Override + public DistinctIterable distinct(final String fieldName, final Bson filter, final Class resultClass) { return new DistinctIterableImpl(namespace, documentClass, resultClass, codecRegistry, readPreference, executor, - fieldName); + fieldName, filter); } @Override diff --git a/driver-async/src/test/functional/com/mongodb/async/client/CrudTest.java b/driver-async/src/test/functional/com/mongodb/async/client/CrudTest.java index e4604b3549e..56fb3339158 100644 --- a/driver-async/src/test/functional/com/mongodb/async/client/CrudTest.java +++ b/driver-async/src/test/functional/com/mongodb/async/client/CrudTest.java @@ -258,8 +258,7 @@ void execute() { } private DistinctIterable getDistinctMongoOperation(final BsonDocument arguments) { - return collection.distinct(arguments.getString("fieldName").getValue(), BsonInt32.class) - .filter(arguments.getDocument("filter")); + return collection.distinct(arguments.getString("fieldName").getValue(), arguments.getDocument("filter"), BsonInt32.class); } private FindIterable getFindMongoOperation(final BsonDocument arguments) { diff --git a/driver-async/src/test/unit/com/mongodb/async/client/DistinctIterableSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/DistinctIterableSpecification.groovy index e54f83e06a3..3286e996a1d 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/DistinctIterableSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/DistinctIterableSpecification.groovy @@ -53,7 +53,8 @@ class DistinctIterableSpecification extends Specification { } } def executor = new TestOperationExecutor([cursor, cursor]); - def distinctIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field') + def distinctIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field', + new BsonDocument()) when: 'default input should be as expected' distinctIterable.into([]) { result, t -> } @@ -61,7 +62,7 @@ class DistinctIterableSpecification extends Specification { def readPreference = executor.getReadPreference() then: - expect operation, isTheSameAs(new DistinctOperation(namespace, 'field', new DocumentCodec())); + expect operation, isTheSameAs(new DistinctOperation(namespace, 'field', new DocumentCodec()).filter(new BsonDocument())); readPreference == secondary() when: 'overriding initial options' @@ -79,7 +80,8 @@ class DistinctIterableSpecification extends Specification { given: def codecRegistry = fromProviders([new ValueCodecProvider(), new BsonValueCodecProvider()]) def executor = new TestOperationExecutor([new MongoException('failure')]) - def distinctIterable = new DistinctIterableImpl(namespace, Document, BsonDocument, codecRegistry, readPreference, executor, 'field') + def distinctIterable = new DistinctIterableImpl(namespace, Document, BsonDocument, codecRegistry, readPreference, executor, + 'field', new BsonDocument()) def futureResultCallback = new FutureResultCallback() @@ -119,7 +121,8 @@ class DistinctIterableSpecification extends Specification { } } def executor = new TestOperationExecutor([cursor(), cursor(), cursor(), cursor(), cursor()]); - def mongoIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field') + def mongoIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field', + new BsonDocument()) when: def results = new FutureResultCallback() diff --git a/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy index 874ab4ff763..777834f0bfa 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy @@ -213,13 +213,13 @@ class MongoCollectionSpecification extends Specification { def asyncCursor = Stub(AsyncBatchCursor) { next(_) >> { args -> args[0].onResult(null, null) } } - def executor = new TestOperationExecutor([asyncCursor, asyncCursor]) + def executor = new TestOperationExecutor([asyncCursor, asyncCursor, asyncCursor]) def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, writeConcern, executor) - def filter = new BsonDocument() + def filter = new BsonDocument('a', new BsonInt32(1)) def futureResultCallback = new FutureResultCallback>() when: - collection.distinct('test', String).filter(filter).into([], futureResultCallback) + collection.distinct('test', String).into([], futureResultCallback) futureResultCallback.get() def operation = executor.getReadOperation() as DistinctOperation @@ -228,8 +228,16 @@ class MongoCollectionSpecification extends Specification { when: futureResultCallback = new FutureResultCallback>() - filter = new BsonDocument('a', new BsonInt32(1)) - collection.distinct('test', String).filter(filter).maxTime(100, MILLISECONDS).into([], futureResultCallback) + collection.distinct('test', String).filter(filter).into([], futureResultCallback) + futureResultCallback.get() + operation = executor.getReadOperation() as DistinctOperation + + then: + expect operation, isTheSameAs(new DistinctOperation(namespace, 'test', codec).filter(filter)) + + when: + futureResultCallback = new FutureResultCallback>() + collection.distinct('test', filter, String).maxTime(100, MILLISECONDS).into([], futureResultCallback) futureResultCallback.get() operation = executor.getReadOperation() as DistinctOperation @@ -247,8 +255,7 @@ class MongoCollectionSpecification extends Specification { then: expect distinctIterable, isTheSameAs(new DistinctIterableImpl(namespace, Document, String, codecRegistry, - readPreference, - executor, 'field')) + readPreference, executor, 'field', new BsonDocument())) } def 'should create FindIterable correctly'() { diff --git a/driver/src/main/com/mongodb/DistinctIterableImpl.java b/driver/src/main/com/mongodb/DistinctIterableImpl.java index f9f26357240..6004ca422a7 100644 --- a/driver/src/main/com/mongodb/DistinctIterableImpl.java +++ b/driver/src/main/com/mongodb/DistinctIterableImpl.java @@ -45,7 +45,7 @@ class DistinctIterableImpl implements DistinctIterable documentClass, final Class resultClass, final CodecRegistry codecRegistry, final ReadPreference readPreference, final OperationExecutor executor, - final String fieldName) { + final String fieldName, final Bson filter) { this.namespace = notNull("namespace", namespace); this.documentClass = notNull("documentClass", documentClass); this.resultClass = notNull("resultClass", resultClass); @@ -53,6 +53,7 @@ class DistinctIterableImpl implements DistinctIterable DistinctIterable distinct(final String fieldName, final Class resultClass) { + return distinct(fieldName, new BsonDocument(), resultClass); + } + + @Override + public DistinctIterable distinct(final String fieldName, final Bson filter, final Class resultClass) { return new DistinctIterableImpl(namespace, documentClass, resultClass, codecRegistry, readPreference, executor, - fieldName); + fieldName, filter); } @Override diff --git a/driver/src/main/com/mongodb/client/MongoCollection.java b/driver/src/main/com/mongodb/client/MongoCollection.java index 94e353e63f8..49b21f81c6c 100644 --- a/driver/src/main/com/mongodb/client/MongoCollection.java +++ b/driver/src/main/com/mongodb/client/MongoCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2014 MongoDB, Inc. + * Copyright (c) 2008-2015 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -154,6 +154,18 @@ public interface MongoCollection { */ DistinctIterable distinct(String fieldName, Class resultClass); + /** + * Gets the distinct values of the specified field name. + * + * @param fieldName the field name + * @param filter the query filter + * @param resultClass the class to cast any distinct items into. + * @param the target type of the iterable. + * @return an iterable of distinct values + * @mongodb.driver.manual reference/command/distinct/ Distinct + */ + DistinctIterable distinct(String fieldName, Bson filter, Class resultClass); + /** * Finds all documents in the collection. * diff --git a/driver/src/test/acceptance/com/mongodb/acceptancetest/core/CollectionAcceptanceTest.java b/driver/src/test/acceptance/com/mongodb/acceptancetest/core/CollectionAcceptanceTest.java index 942cccf6931..22152d785bd 100644 --- a/driver/src/test/acceptance/com/mongodb/acceptancetest/core/CollectionAcceptanceTest.java +++ b/driver/src/test/acceptance/com/mongodb/acceptancetest/core/CollectionAcceptanceTest.java @@ -303,6 +303,11 @@ public void shouldBeAbleToUseBsonValueToDistinctDocumentsOfVaryingTypes() { assertTrue(distinct.containsAll(asList(new BsonString("a"), new BsonInt32(1), new BsonDocument("b", new BsonString("c")), new BsonDocument("list", new BsonArray(asList(new BsonInt32(2), new BsonString("d"), new BsonDocument("e", new BsonInt32(3)))))))); + + distinct = collection.distinct("id", new Document("id", new Document("$ne", 1)), BsonValue.class).into(new ArrayList()); + assertTrue(distinct.containsAll(asList(new BsonString("a"), new BsonDocument("b", new BsonString("c")), + new BsonDocument("list", new BsonArray(asList(new BsonInt32(2), new BsonString("d"), + new BsonDocument("e", new BsonInt32(3)))))))); } private void initialiseCollectionWithDocuments(final int numberOfDocuments) { diff --git a/driver/src/test/unit/com/mongodb/DistinctIterableSpecification.groovy b/driver/src/test/unit/com/mongodb/DistinctIterableSpecification.groovy index 9dc4326683c..0fd0346df0c 100644 --- a/driver/src/test/unit/com/mongodb/DistinctIterableSpecification.groovy +++ b/driver/src/test/unit/com/mongodb/DistinctIterableSpecification.groovy @@ -43,7 +43,8 @@ class DistinctIterableSpecification extends Specification { def 'should build the expected DistinctOperation'() { given: def executor = new TestOperationExecutor([null, null]); - def distinctIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field') + def distinctIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field', + new BsonDocument()) when: 'default input should be as expected' distinctIterable.iterator() @@ -52,7 +53,7 @@ class DistinctIterableSpecification extends Specification { def readPreference = executor.getReadPreference() then: - expect operation, isTheSameAs(new DistinctOperation(namespace, 'field', new DocumentCodec())); + expect operation, isTheSameAs(new DistinctOperation(namespace, 'field', new DocumentCodec()).filter(new BsonDocument())); readPreference == secondary() when: 'overriding initial options' @@ -70,7 +71,8 @@ class DistinctIterableSpecification extends Specification { given: def codecRegistry = fromProviders([new ValueCodecProvider(), new BsonValueCodecProvider()]) def executor = new TestOperationExecutor([new MongoException('failure')]) - def distinctIterable = new DistinctIterableImpl(namespace, Document, BsonDocument, codecRegistry, readPreference, executor, 'field') + def distinctIterable = new DistinctIterableImpl(namespace, Document, BsonDocument, codecRegistry, readPreference, executor, 'field', + new BsonDocument()) when: 'The operation fails with an exception' distinctIterable.iterator() @@ -106,7 +108,8 @@ class DistinctIterableSpecification extends Specification { } } def executor = new TestOperationExecutor([cursor(), cursor(), cursor(), cursor()]); - def mongoIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field') + def mongoIterable = new DistinctIterableImpl(namespace, Document, Document, codecRegistry, readPreference, executor, 'field', + new BsonDocument()) when: def results = mongoIterable.first() diff --git a/driver/src/test/unit/com/mongodb/MongoCollectionSpecification.groovy b/driver/src/test/unit/com/mongodb/MongoCollectionSpecification.groovy index fd25e874ea9..693790947d0 100644 --- a/driver/src/test/unit/com/mongodb/MongoCollectionSpecification.groovy +++ b/driver/src/test/unit/com/mongodb/MongoCollectionSpecification.groovy @@ -188,13 +188,28 @@ class MongoCollectionSpecification extends Specification { given: def executor = new TestOperationExecutor([]) def collection = new MongoCollectionImpl(namespace, Document, codecRegistry, readPreference, writeConcern, executor) + def filter = new Document('a', 1) when: def distinctIterable = collection.distinct('field', String) then: expect distinctIterable, isTheSameAs(new DistinctIterableImpl(namespace, Document, String, codecRegistry, readPreference, - executor, 'field')) + executor, 'field', new BsonDocument())) + + when: + distinctIterable = collection.distinct('field', String).filter(filter) + + then: + expect distinctIterable, isTheSameAs(new DistinctIterableImpl(namespace, Document, String, codecRegistry, readPreference, + executor, 'field', filter)) + + when: + distinctIterable = collection.distinct('field', filter, String).maxTime(100, MILLISECONDS) + + then: + expect distinctIterable, isTheSameAs(new DistinctIterableImpl(namespace, Document, String, codecRegistry, readPreference, + executor, 'field', filter).maxTime(100, MILLISECONDS)) } def 'should create FindIterable correctly'() { From f79b95388d306d458d0fedd43e733fa23bcff98a Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Thu, 23 Apr 2015 17:54:37 -0400 Subject: [PATCH 0036/1665] Added reference documentation for Sorts and Projections. JAVA-1776, JAVA-1777 --- .../reference/content/builders/aggregation.md | 2 +- docs/reference/content/builders/index.md | 2 + .../reference/content/builders/projections.md | 133 ++++++++++++++++++ docs/reference/content/builders/sorts.md | 79 +++++++++++ 4 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 docs/reference/content/builders/projections.md create mode 100644 docs/reference/content/builders/sorts.md diff --git a/docs/reference/content/builders/aggregation.md b/docs/reference/content/builders/aggregation.md index 467271e4fbd..6ca306abfb7 100644 --- a/docs/reference/content/builders/aggregation.md +++ b/docs/reference/content/builders/aggregation.md @@ -3,7 +3,7 @@ date = "2015-03-19T14:27:51-04:00" title = "Aggregation" [menu.main] parent = "Builders" - weight = 20 + weight = 40 pre = "" +++ diff --git a/docs/reference/content/builders/index.md b/docs/reference/content/builders/index.md index b8bff03dbcf..6a33c69033a 100644 --- a/docs/reference/content/builders/index.md +++ b/docs/reference/content/builders/index.md @@ -12,5 +12,7 @@ title = "Builders" The driver provides several classes that make it easier to use the CRUD API. - [Filters]({{< relref "filters.md" >}}): Documentation of the driver's support for building query filters +- [Projections]({{< relref "projections.md" >}}): Documentation of the driver's support for building projections +- [Sorts]({{< relref "sorts.md" >}}): Documentation of the driver's support for building sort criteria - [Aggregation]({{< relref "aggregation.md" >}}): Documentation of the driver's support for building aggregation pipelines diff --git a/docs/reference/content/builders/projections.md b/docs/reference/content/builders/projections.md new file mode 100644 index 00000000000..b530b966187 --- /dev/null +++ b/docs/reference/content/builders/projections.md @@ -0,0 +1,133 @@ ++++ +date = "2015-03-19T14:27:51-04:00" +title = "Projections" +[menu.main] + parent = "Builders" + weight = 20 + pre = "" ++++ + +## Filters + +The [`Projections`]({{< apiref "com/mongodb/client/model/Projections" >}}) class provides static factory methods for all the MongoDB +projection opererators. Each method returns an instance of the [`Bson`]({{< relref "bson/documents.md#bson" >}}) type, which can in turn +be passed to any method that expects a projection. + +For brevity, you may choose to import the methods of the `Projections` class statically: + +```java +import com.mongodb.client.model.Projections.*; +``` + +All the examples below assume this static import. + +### Inclusion + +By default, all fields of each document are projected. To specify the inclusion of one or more fields (which implicitly excludes all +other fields except `_id`), use the `include` method. + +This example includes the `quantity` field and (implicitly) the `_id` field: + +```java +include("quantity") +``` + +This example includes the `quantity` and `totalAmount` fields and (implicitly) the `_id` field: + +```java +include("quantity", "totalAmount") +``` + +### Exclusion + +To specify the exclusion of one or more fields (which implicitly includes all other fields), use the `exclude` method. + +This example excludes the `quantity` field: + +```java +exclude("quantity") +``` + +This example excludes the `quantity` and `totalAmount` fields: + +```java +exclude("quantity", "totalAmount") +``` + +### Exclusion of _id + +To specify the exclusion of the `_id` field, use the `excludeId` method: + +```java +excludeId() +``` + +which is just shorthand for: + +```java +exclude("_id") +``` + +### Array Element Match with a Supplied Filter + +To specify a projection that includes only the first element of an array that matches a supplied query filter (the +[elemMatch]({{< docsref "reference/operator/projection/elemMatch" >}}) operator), use the `elemMatch` method that takes a +field name and a filter. + +This example projects the first element of the `orders` array where the `quantity` field is greater that `3`: + +```java +elemMatch("orders", Filters.gt("quantity", 3)) +``` + +### Array Element Match with an Implicit Filter + +To specify a projection that includes only the first element of an array that matches the filter supplied as part of the query (the +[positional $ operator]({{< docsref "reference/operator/projection/positional/#projection" >}})), use the `elemMatch` method that takes +just a field name. + +This example projects the first element of the `orders` array that matches the query filter: + +```java +elemMatch("orders") +``` + +### Slice + +To project [a slice of an array]({{< docsref "reference/operator/projection/slice" >}}), use one of the `slice` methods. + +This example projects the first `7` elements of the `tags` array: + +```java +slice("tags", 7) +``` + +This example skips the first `2` elements of the `tags` array and projects the next `5`: + +```java +slice("tags", 2, 5) +``` + +### Text Score + +To specify a projection of [the score of a `$text` query]({{< docsref "reference/operator/query/text/#return-the-text-search-score" >}}), +use the `metaTextScore` method to specify the name of the projected field. + +This example projects the text score as the value of the `score` field: + +```java +metaTextScore("score") +``` + + +### Combining Projections + +To combine multiple projections, use the `fields` method. + +This example includes the `quantity` and `totalAmount` fields and excludes the `_id` field: + +```java +fields(include("quantity", "totalAmount"), excludeId()) +``` + + diff --git a/docs/reference/content/builders/sorts.md b/docs/reference/content/builders/sorts.md new file mode 100644 index 00000000000..d8db686ca11 --- /dev/null +++ b/docs/reference/content/builders/sorts.md @@ -0,0 +1,79 @@ ++++ +date = "2015-03-19T14:27:51-04:00" +title = "Sort Criteria " +[menu.main] + parent = "Builders" + weight = 30 + pre = "" ++++ + +## Sorts + +The [`Sorts`]({{< apiref "com/mongodb/client/model/Sorts" >}}) class provides static factory methods for all the MongoDB sort criteria +operators. Each method returns an instance of the [`Bson`]({{< relref "bson/documents.md#bson" >}}) type, which can in turn be passed to +any method that expects sort criteria. + +For brevity, you may choose to import the methods of the `Sorts` class statically: + +```java +import com.mongodb.client.model.Sorts.*; +``` + +All the examples below assume this static import. + +### Ascending + +To specify an ascending sort, use one of the `ascending` methods. + +This example specifies an ascending sort on the `quantity` field: + +```java +ascending("quantity") +``` + +This example specifies an ascending sort on the `quantity` field, followed by an ascending sort on the `totalAmount` field: + +```java +ascending("quantity", "totalAmount") +``` + +### Descending + +To specify a descending sort, use one of the `descending` methods. + +This example specifies a descending sort on the `quantity` field: + +```java +descending("quantity") +``` + +This example specifies a descending sort on the `quantity` field, followed by a descending sort on the `totalAmount` field: + + +```java +descending("quantity", "totalAmount") +``` + +### Text Score + +To specify a sort by [the score of a `$text` query]({{< docsref "reference/operator/query/text/#sort-by-text-search-score" >}}), use the +`metaTextScore` method to specify the name of the projected field. + +This example specifies a sort on the score of a `$text` query that will be projected into the `scoreValue` field in a projection on the +same query: + +```java +metaTextScore("scoreValue") +``` + +### Combining sort criteria + +To specify the combination of multiple sort criteria, use the `orderBy` method. + +This example specifies an ascending sort on the `quantity` field, followed by an ascending sort on the `totalAmount` field, followed by a +descending sort on the `orderDate` field: + +```java +orderBy(ascending("quantity", "totalAmount"), descending("orderDate")) +``` + From 6fed97901c371d3b20bba84f3d54ed93cb16ccb8 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 24 Apr 2015 11:46:28 +0100 Subject: [PATCH 0037/1665] Added default CodecRegistry for async driver JAVA-1756 --- .../mongodb/async/client/MongoClientImpl.java | 34 ++----------------- .../async/client/MongoClientSettings.java | 2 +- .../mongodb/async/client/MongoClients.java | 31 +++++++++++++++++ .../async/client/MongoDatabaseImpl.java | 5 ++- .../client/MongoClientSpecification.groovy | 8 ++--- .../MongoCollectionSpecification.groovy | 2 +- .../client/MongoDatabaseSpecification.groovy | 2 +- 7 files changed, 40 insertions(+), 44 deletions(-) diff --git a/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java b/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java index 3a11318aec3..8ffbe45881e 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoClientImpl.java @@ -23,51 +23,21 @@ import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.AsyncReadWriteBinding; import com.mongodb.binding.AsyncWriteBinding; -import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import com.mongodb.connection.Cluster; import com.mongodb.operation.AsyncOperationExecutor; import com.mongodb.operation.AsyncReadOperation; import com.mongodb.operation.AsyncWriteOperation; import org.bson.BsonDocument; import org.bson.Document; -import org.bson.codecs.BsonValueCodecProvider; -import org.bson.codecs.DocumentCodecProvider; -import org.bson.codecs.ValueCodecProvider; -import org.bson.codecs.configuration.CodecRegistry; import static com.mongodb.assertions.Assertions.notNull; import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback; -import static java.util.Arrays.asList; -import static org.bson.codecs.configuration.CodecRegistries.fromProviders; class MongoClientImpl implements MongoClient { private final Cluster cluster; private final MongoClientSettings settings; private final AsyncOperationExecutor executor; - private static final CodecRegistry DEFAULT_CODEC_REGISTRY = fromProviders(asList(new ValueCodecProvider(), - new DocumentCodecProvider(), - new BsonValueCodecProvider(), - new GeoJsonCodecProvider())); - - /** - * Gets the default codec registry. It includes the following providers: - * - *
      - *
    • {@link org.bson.codecs.ValueCodecProvider}
    • - *
    • {@link org.bson.codecs.DocumentCodecProvider}
    • - *
    • {@link org.bson.codecs.BsonValueCodecProvider}
    • - *
    • {@link com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider}
    • - *
    - * - * @return the default codec registry - * @see MongoClientSettings#getCodecRegistry() - * @since 3.0 - */ - public static CodecRegistry getDefaultCodecRegistry() { - return DEFAULT_CODEC_REGISTRY; - } - MongoClientImpl(final MongoClientSettings settings, final Cluster cluster) { this(settings, cluster, createOperationExecutor(settings, cluster)); } @@ -95,8 +65,8 @@ public MongoClientSettings getSettings() { @Override public MongoIterable listDatabaseNames() { - return new ListDatabasesIterableImpl(BsonDocument.class, getDefaultCodecRegistry(), ReadPreference.primary(), - executor).map(new Function() { + return new ListDatabasesIterableImpl(BsonDocument.class, MongoClients.getDefaultCodecRegistry(), + ReadPreference.primary(), executor).map(new Function() { @Override public String apply(final BsonDocument document) { return document.getString("name").getValue(); diff --git a/driver-async/src/main/com/mongodb/async/client/MongoClientSettings.java b/driver-async/src/main/com/mongodb/async/client/MongoClientSettings.java index a761c4e755c..78c9bac3c61 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoClientSettings.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoClientSettings.java @@ -79,7 +79,7 @@ public static Builder builder(final MongoClientSettings settings) { public static final class Builder { private ReadPreference readPreference = ReadPreference.primary(); private WriteConcern writeConcern = WriteConcern.ACKNOWLEDGED; - private CodecRegistry codecRegistry = MongoClientImpl.getDefaultCodecRegistry(); + private CodecRegistry codecRegistry = MongoClients.getDefaultCodecRegistry(); private ClusterSettings clusterSettings; private SocketSettings socketSettings = SocketSettings.builder().build(); diff --git a/driver-async/src/main/com/mongodb/async/client/MongoClients.java b/driver-async/src/main/com/mongodb/async/client/MongoClients.java index 66b939f89d1..22549d69c15 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoClients.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoClients.java @@ -17,6 +17,7 @@ package com.mongodb.async.client; import com.mongodb.ConnectionString; +import com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider; import com.mongodb.connection.AsynchronousSocketChannelStreamFactory; import com.mongodb.connection.Cluster; import com.mongodb.connection.ClusterSettings; @@ -28,6 +29,13 @@ import com.mongodb.connection.StreamFactory; import com.mongodb.connection.netty.NettyStreamFactory; import com.mongodb.management.JMXConnectionPoolListener; +import org.bson.codecs.BsonValueCodecProvider; +import org.bson.codecs.DocumentCodecProvider; +import org.bson.codecs.ValueCodecProvider; +import org.bson.codecs.configuration.CodecRegistry; + +import static java.util.Arrays.asList; +import static org.bson.codecs.configuration.CodecRegistries.fromProviders; /** * A factory for MongoClient instances. @@ -90,6 +98,29 @@ public static MongoClient create(final ConnectionString connectionString) { .build()); } + /** + * Gets the default codec registry. It includes the following providers: + * + *
      + *
    • {@link org.bson.codecs.ValueCodecProvider}
    • + *
    • {@link org.bson.codecs.DocumentCodecProvider}
    • + *
    • {@link org.bson.codecs.BsonValueCodecProvider}
    • + *
    • {@link com.mongodb.client.model.geojson.codecs.GeoJsonCodecProvider}
    • + *
    + * + * @return the default codec registry + * @see MongoClientSettings#getCodecRegistry() + * @since 3.1 + */ + public static CodecRegistry getDefaultCodecRegistry() { + return MongoClients.DEFAULT_CODEC_REGISTRY; + } + + private static final CodecRegistry DEFAULT_CODEC_REGISTRY = + fromProviders(asList(new ValueCodecProvider(), + new DocumentCodecProvider(), + new BsonValueCodecProvider(), + new GeoJsonCodecProvider())); private static Cluster createCluster(final MongoClientSettings settings, final StreamFactory streamFactory) { StreamFactory heartbeatStreamFactory = getHeartbeatStreamFactory(settings); diff --git a/driver-async/src/main/com/mongodb/async/client/MongoDatabaseImpl.java b/driver-async/src/main/com/mongodb/async/client/MongoDatabaseImpl.java index a1068ec35f1..5a3f84d6081 100644 --- a/driver-async/src/main/com/mongodb/async/client/MongoDatabaseImpl.java +++ b/driver-async/src/main/com/mongodb/async/client/MongoDatabaseImpl.java @@ -33,7 +33,6 @@ import org.bson.conversions.Bson; import static com.mongodb.assertions.Assertions.notNull; -import static com.mongodb.async.client.MongoClientImpl.getDefaultCodecRegistry; class MongoDatabaseImpl implements MongoDatabase { private final String name; @@ -88,8 +87,8 @@ public MongoDatabase withWriteConcern(final WriteConcern writeConcern) { @Override public MongoIterable listCollectionNames() { - return new ListCollectionsIterableImpl(name, BsonDocument.class, getDefaultCodecRegistry(), ReadPreference.primary(), - executor).map(new Function() { + return new ListCollectionsIterableImpl(name, BsonDocument.class, MongoClients.getDefaultCodecRegistry(), + ReadPreference.primary(), executor).map(new Function() { @Override public String apply(final BsonDocument result) { return result.getString("name").getValue(); diff --git a/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy index 84c0bc7302f..739a145794a 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/MongoClientSpecification.groovy @@ -38,7 +38,7 @@ class MongoClientSpecification extends Specification { def cluster = Stub(Cluster) def executor = new TestOperationExecutor([null, null, null]) def client = new MongoClientImpl(settings, cluster, executor) - def codecRegistry = client.getDefaultCodecRegistry() + def codecRegistry = MongoClients.getDefaultCodecRegistry() when: def listDatabasesIterable = client.listDatabases() @@ -89,11 +89,7 @@ class MongoClientSpecification extends Specification { def 'default codec registry should contain all supported providers'() { given: - def settings = MongoClientSettings.builder().build() - def cluster = Stub(Cluster) - def executor = new TestOperationExecutor([null, null, null]) - def client = new MongoClientImpl(settings, cluster, executor) - def codecRegistry = client.getDefaultCodecRegistry() + def codecRegistry = MongoClients.getDefaultCodecRegistry() expect: codecRegistry.get(BsonDocument) diff --git a/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy index 777834f0bfa..62c7c48cfa3 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/MongoCollectionSpecification.groovy @@ -97,7 +97,7 @@ import static spock.util.matcher.HamcrestSupport.expect class MongoCollectionSpecification extends Specification { def namespace = new MongoNamespace('databaseName', 'collectionName') - def codecRegistry = MongoClientImpl.getDefaultCodecRegistry() + def codecRegistry = MongoClients.getDefaultCodecRegistry() def readPreference = secondary() def writeConcern = WriteConcern.ACKNOWLEDGED diff --git a/driver-async/src/test/unit/com/mongodb/async/client/MongoDatabaseSpecification.groovy b/driver-async/src/test/unit/com/mongodb/async/client/MongoDatabaseSpecification.groovy index 955b8d2b81c..f8270f6fc41 100644 --- a/driver-async/src/test/unit/com/mongodb/async/client/MongoDatabaseSpecification.groovy +++ b/driver-async/src/test/unit/com/mongodb/async/client/MongoDatabaseSpecification.groovy @@ -41,7 +41,7 @@ import static spock.util.matcher.HamcrestSupport.expect class MongoDatabaseSpecification extends Specification { def name = 'databaseName' - def codecRegistry = MongoClientImpl.getDefaultCodecRegistry() + def codecRegistry = MongoClients.getDefaultCodecRegistry() def readPreference = secondary() def writeConcern = WriteConcern.ACKNOWLEDGED From d09ff2be62e9db7d42a9dfbe183c23df04ddd82a Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 24 Apr 2015 13:41:11 +0100 Subject: [PATCH 0038/1665] Open external site links in a new window --- docs/reference/themes/mongodb/static/js/scripts.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/reference/themes/mongodb/static/js/scripts.js b/docs/reference/themes/mongodb/static/js/scripts.js index 8e32d4da142..7d31a68aad7 100644 --- a/docs/reference/themes/mongodb/static/js/scripts.js +++ b/docs/reference/themes/mongodb/static/js/scripts.js @@ -17,4 +17,10 @@ jQuery(document).ready(function(){ jQuery('[data-toggle="tooltip"]').tooltip(); jQuery("body").addClass("hljsCode"); hljs.initHighlightingOnLoad(); + var linkRegex = new RegExp('/' + window.location.host + '/'); + jQuery('a').not('[href*="mailto:"]').each(function () { + if ( ! linkRegex.test(this.href) ) { + $(this).attr('target', '_blank'); + } + }); }); From 1aac668c76f4cbd6cbcff79495f5781ba574bd38 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 24 Apr 2015 14:16:17 +0100 Subject: [PATCH 0039/1665] Added table styling to markdown tables --- docs/reference/themes/mongodb/static/js/scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/themes/mongodb/static/js/scripts.js b/docs/reference/themes/mongodb/static/js/scripts.js index 7d31a68aad7..7a7589de0ac 100644 --- a/docs/reference/themes/mongodb/static/js/scripts.js +++ b/docs/reference/themes/mongodb/static/js/scripts.js @@ -23,4 +23,5 @@ jQuery(document).ready(function(){ $(this).attr('target', '_blank'); } }); + jQuery('.body table').addClass('table').addClass('table-striped'); }); From 9e01178fa487e928b4438c3dcf5bcf01cd95783b Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 24 Apr 2015 14:18:22 +0100 Subject: [PATCH 0040/1665] Bson documentation tweaks --- docs/reference/content/bson/codecs.md | 14 +++++++------- docs/reference/content/bson/documents.md | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/reference/content/bson/codecs.md b/docs/reference/content/bson/codecs.md index 587cfaae50f..b46a2b06737 100644 --- a/docs/reference/content/bson/codecs.md +++ b/docs/reference/content/bson/codecs.md @@ -145,13 +145,13 @@ to determine with type to decode each BSON value to, then use the `CodecRegistry Finally, we create a `CodecRegistry` instance -```java - CodecRegistry defaultCodecRegistry = ... - DocumentCodecProvider documentCodecProvider = ... - Codec instantCodec = ... - codecRegistry = CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(instantCodec), - CodecRegistries.fromProviders(documentCodecProvider), - defaultCodecRegistry); +```bash +CodecRegistry defaultCodecRegistry = ... +DocumentCodecProvider documentCodecProvider = ... +Codec instantCodec = ... +codecRegistry = CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(instantCodec), + CodecRegistries.fromProviders(documentCodecProvider), + defaultCodecRegistry); ``` using two additional static factory methods from the `CodecRegistries` class: one that takes a list of `CodecProvider`s and one which diff --git a/docs/reference/content/bson/documents.md b/docs/reference/content/bson/documents.md index 216e300dfb9..772e74ab521 100644 --- a/docs/reference/content/bson/documents.md +++ b/docs/reference/content/bson/documents.md @@ -50,8 +50,8 @@ There is less code to write, but runtime errors are possible if you inadvertentl The most commonly used value types are: -| BSON type | Java type | -|-----------|-------------------------| +| BSON type | Java type | +|-----------|---------------------------| | Document | `org.bson.Document` | | Array | `java.util.List` | | Date | `java.util.Date` | From 9646ff228417fe9f9081a8e04f41315ffffbc3aa Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 24 Apr 2015 16:00:04 +0100 Subject: [PATCH 0041/1665] Fix documentation favicon --- docs/landing/layouts/index.html | 2 +- docs/landing/static/s/img/favicon.png | Bin 0 -> 6092 bytes docs/reference/content/builders/index.md | 2 +- .../themes/mongodb/static/img/favicon.png | Bin 0 -> 6092 bytes 4 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 docs/landing/static/s/img/favicon.png create mode 100644 docs/reference/themes/mongodb/static/img/favicon.png diff --git a/docs/landing/layouts/index.html b/docs/landing/layouts/index.html index f011a42d59b..b47a66a7c20 100644 --- a/docs/landing/layouts/index.html +++ b/docs/landing/layouts/index.html @@ -2,7 +2,7 @@ {{ partial "meta.html"}} - + {{.Title}} diff --git a/docs/landing/static/s/img/favicon.png b/docs/landing/static/s/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f54468dd51c955b24f0900e760ba22863295f0 GIT binary patch literal 6092 zcmY*dbzIcnw*Ah~F?0+A=)g#Khk$^z2uMjwcMLE{%h1wDt4K+Qq%;UfBQ+o)jR+_x zEj?WQ-TUr)?|eSzoPE|=d#%0CpC?8~OBF&4BL)BfqOPW-`)8N`I|=dstmRIg%YQap z2Ze_U08pDma%F}0=M1+|(|rg40qg*PjsSp*KM;Bw0DJ@i;D;puNM`{6JuqI%(|F4s~_kY^@)1biL8v!AHL4p5j z|4Ehki%M&IIobVj{;Mx1B=ZmR|6%{}krDW7{(p-3cc=fLe_E9zmJ#^xv&j)__HY;j z0PT{xl7hY;sKb;fnfbF%NA=~+y(0(gZpCk(2{4$KBu+V&nKM(}fS9nkhwAYf_h1Q`Y8p^=ikin4@9O8zANP1l{a#=5*)Njs7a=TsjIyTzIougm3`TI zd72ws_*`P@x^*w`v@`HmhsXEX>xArX)RyZlP0 z=dgycG>8#~86>xXEgvI1#1n^LHh|pVda241&34zQZIFgCtG(=}|c z{u#v;fx;f-4pd(5%Upe-=;R_tNaN4j`aNYibgt+Rm!~e@j8x;M@s%Y66;g5Qs1iIR z-p#|#>V)^hpDxaRE&ccch-r(Z(O(4Z76xYUj1DMM4hSZ)K-VP??+dP4O#2N9jjFY{?{^Bdrk8K3SR3LK>=G6fTSpF&!s`7C zhaPHg+ML_MOjOh&h&t3R@&~MRER?(T952PHw@>dTQty7jI_i7O$YhA?Rb5)N8ebJi ze&?}J_sM?Q)ohYSw|bJ!LJ8XaD* zLV3zgjqm-QMzJS4=C2QJzpT`T-f?zptbU{$NA$kd#OuLMp__NxM#ikmbScwd<;3Gc z#vlnR^o7%{k|k4~1d6hPpK^YOshFc>dnMfo;+~|?udH|A3$6B`!?}tQ{Q|3Xp5W~Gh2CbdP(?C^9sZC@# zL3sY_3Ajc69fWGM-Nsx^(D8^3rn5*d!=hCa5uw6{e-K$egV!9~y2qTjVuus)Wg*Hu z^hD+!B+eX1LtM8+Fe}qH*H4e^p0C>dH>jT#>Ucap2}UIw`mb(PyAKY(8X3>H;A5uK z-2KVLt4H{#VFKQs*vg1F{OItEXHO2Bp|hoAZDdAE6RvOROuga9#_l!Sv{&c*&M7i% zt0qGn*D`qTczB{);RHjoO1p0VfvAH;tV&AiGD=(h=*!cgcP=T%!kb3gPGPMnDC;VlplEunfDEw=O;gnW<*y)9jVXPgVSu@^9LUeTEQJ{?%69{sQ^86$}&d2%Lj*p;t9jQS4aa-H@ zb(V($J??nlr^A(j6qZ`Wz zK|++JW;JEp5H zX7Bo;xz#+NSzE!%0iK>3@HE|0R7?fG9QGqvz2ZEvqg9d-nIrCrRjz zi1X=hhhZ+yOx2PmV#V3q7*aNeyK>D9ImFB%wF4hlqo1|MsyJCgZX6p-Dt}qxrgnqn z4DH|br+j+~>izY4L)Am=rKlj7M@Xa$^t*YX_AC0~OLI(}grpi0PDv9+)hq>@jS>ln&8?`%c&8 z=huRC+0Hcb__w=LTf@^pPi0gB3bH^-5M+TbCljxb3>?e@-~+M)h5tqYNrn z{lOWPN+gvTqW4oFe%2ZHMw{hP^EZ}K8|oRA))U*k($&QnfI;fJvhm&V3;RXI)&|;0r$KLLXU?qi@|<0>P|M~^0He$gA8<5jN8;mfyAPR@Q-qGWK>__ewp;~7QCYsMB6RwT zeAclwmg2B5(4jJUDA^~?TKx<5Z_U)eibEVSO03RLZOwgGk!mZ1=;H^{9AwYEX4V4g z;yx#qh0A0WDq^Wrq_mk@!PugeA*Efvd$dRP{vvgeQMnC9m(yR_hzK9fIDr@u)&Kq* z)hp8GOoNJ=<`d7hvc0Mi3ECKvJ`6ko$-LU zhkK`cdt9sPGFr7Dvt68$a*-g_Q+{|J!va-gVeNJH1eblz0c#}wup6!JD zK39R%sNDe8PyxLCmrV4C<`_s>kw`8){UMdc;-0@MT4O*E8u}i$C@L~zUN^1qr&s+` zxtP!Jdf44QzgBIp{rpWrl8S>^F^yW#D_C@1n!7L-AM$&Emg3nwS(`cSsWzVGD+OcwcDnuVt63C-V7=H`6L84W?AK$bHhgy4*4m>Ww==rgqlOv zTX5t?QSq2kRTn?398ukGr8Qbo^lhxr%NH6*&b549#rN8Jc@9`<-?XYwqv+DzL{}+1 zb)}Fug6-{y8mDyR{L;j$?bzHxAaSLMWXhEuSh>JB)mviTe!`K44ATEw^*J`-U_ zeBvbx!-IR2ViD+ucSnsM=Nx&H>5+lLsbcBntK{nkxB^C78fhPuO&2y3n{VE7h@7nZMN{v8Icnl!kv4#?+WF5% z6@+W+#_u+LMV|zWv{c2|dG^YQCHZL(sIn2JvzKnTCY#Z7n&2f+^Q_l|%#h)JV`h#! zJu7L<%0s`Yo?$dR3WUTKSd#75k-rF;TUCl5(zikne6pES4NuPg_-#KVuOOHoo$YFx zFkS7)Nv@*Km0E4(vp3g#cE1ldYvM?wcG!tSrz;&?>Wf119%y|rHYTVaF4z0@in8o; z`X2rMtHmq9bT1VR3XQ+g0A2g_AKqo05oUYB$rL7I`jCK^V^uSC>Oy+e;X*-7 zlaTRz&O@$q-kJ$$b4;6jONLi+-1X9J&aPzI%S$~*1c9yRD8_%1^>g~EC{!r#Z0m~C zX5~dFSGykRM8J(6p#*UndDpeB%nya!D6s@g4e^?os_(Qr`cYerhy2wfk{2(ej!{P; z>{Q*>TKpUxj{#L`_bi!LNlX#7^D&whk*yGyW_xwWo=JYiv370|UnJtoG#CRH-Xp5G z8#m1l^$&|y_yJOv-Lm$!J^xmL(zt^*rtXNI;Jbc`d!dizLZ&mo;51@*_vCu^$&#E! z>Lc&@tm*AwMhv%COO_qZprjl9LAR#@xR!EsT~mE>s6ds-y;mOL3~Pu@1KaUKlTl&_ z1K!Wv27x4dkuVid5C4rut{)Q#ToI&bOd=YO-hL(=F!5jy9%dOauUq)hx;?Pe^yPjh zKkvp0unzeVGTs_pOe<0aG7^z^(L)H;luzaa}GElaibQvcU$b`yazqldlmo{O8U# zr+C)qF>wr#{q&V!!W9q2JdbC1`zzsHNGFHeqK4O47^(ErDFjRPI)*!ub8c3k59ed; z)@O=ln|P_Y=Zz}0_%p&mD1)F5ZSY2YD2I_;)w@<}K03J}3H8>N%e*JaH*0=Ar;$^E zxx-_Q0NrwQb$Lz9bNb=K(}@!?h|38KKh1l=mZ*wsr<7wz@FB))cRcByucAg4>^+Y> z{s2e>=Qu5{1R((%t#LGzJi?cm&$mm z+=xT&=7+g+=39gBAO00DSHpo|W$yExigzXz-XCB}3u4MO!6ez^Em^0(S~hZvr;5YG zOF%|}1IkGg2wW@>zpq)zwC`2DTDc>x#%B>)|6$ZN;(5v0S}E!EMh#6;ygIcU|6aK% zKXaK1SLY0(D0utSNKVyuz8UklMCi+iuV#MC)Z7n59-S$w^ZHN|ON z&ZTUJ2#FoHGD`eVP0;|GkXQ_qR^#>WdCTrvj*5&f0H+pL$?nCQy}=}W%S7i)^wtO@ zf&CJ_xCSJLVVcnDLr!Hh821Tig&A_2v3KBcCsT0s>wJ;6ElTtEZ={TU5pq?g%ul75 zIR-hS;irkZoo6}Wp5I&+&O&#tFzpa|&$cF6_P2{-ho8o4I#Bc`n`oN^^kK2jXdSlS z`%binf0b|EqG*iDD({3h_=y+DC}z(kc{sS`6OHP8O2GVnpErtyZpeONVokDc;XrOj znf^)Z&$(FTMKC6eRKDddfBz3?M|X2siQug(DVl9-!%6R&I&gVM7IQW~1 zX6D&3WXcTJj5%@Y>@4CqM@d4hv|GCJby;=F``jlSE^;AsotIUy=kvi6bQznQja@=U z`4`J$BKjb)w0c)A8GS!{v zL&$ELnjX}N_DyYV*MZ$`HhdD}K|Cwk>oflJ)#59ebd~+&@!x8uGelk{yxI_IFbZcH;3VY8VQt!B~!#$kjt z)xFgHN|1RH#3CilgX-8F+*2zZxupoo?c=GCd!5?+*BCr#gdx+j{J?!F;8#RuYhGnV z4t{8xm|2IIC31rx-aqKsxX(Rm3G)RB-yiG6kfbkHEu>)Ow)ijOSu%%v`6WRu`JG>X z#`M(ee))a&orjF5WC<_DBmuw5V^yf_Qj5qyF>QcI~O;fffwv;Pdd{xgJjzw z&lVx~%}5d3I!S{y_Nx84bNd;SRecLC`8Dz30HwZ4yXM|a06ZfcSSk(b(7XHFyZw_aVzo?Q zH^hGGSEdJxJw1A?FCIxyutwZ4N8uA!>f^%H-X(f?pV#%4Qek_7G*(Nq$wByyCyvfJ z^F6Fy*{@#xtu+ZL1tg1FQ#VB>%RncLYGo02L^^y6_w4Z-couX_Z19O&fPCEe#&;Vb zdEC{U4v7)#_9xo{`>Hcp+{*6qW1ZMw*QC7)cZ~!{NLHqY8P>MftN$qJGeG(3ZU`!z zcVU|I{s70B-bG%qkb#V+r6zXs$DWFTT;tUZ(38lfyh>2K`}faWU0F-%ouXyfzW~V5 BN5%jE literal 0 HcmV?d00001 diff --git a/docs/reference/content/builders/index.md b/docs/reference/content/builders/index.md index 6a33c69033a..9c5c50b02fc 100644 --- a/docs/reference/content/builders/index.md +++ b/docs/reference/content/builders/index.md @@ -4,7 +4,7 @@ title = "Builders" [menu.main] identifier = "Builders" weight = 50 - pre = "" + pre = "" +++ ## Builders diff --git a/docs/reference/themes/mongodb/static/img/favicon.png b/docs/reference/themes/mongodb/static/img/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f54468dd51c955b24f0900e760ba22863295f0 GIT binary patch literal 6092 zcmY*dbzIcnw*Ah~F?0+A=)g#Khk$^z2uMjwcMLE{%h1wDt4K+Qq%;UfBQ+o)jR+_x zEj?WQ-TUr)?|eSzoPE|=d#%0CpC?8~OBF&4BL)BfqOPW-`)8N`I|=dstmRIg%YQap z2Ze_U08pDma%F}0=M1+|(|rg40qg*PjsSp*KM;Bw0DJ@i;D;puNM`{6JuqI%(|F4s~_kY^@)1biL8v!AHL4p5j z|4Ehki%M&IIobVj{;Mx1B=ZmR|6%{}krDW7{(p-3cc=fLe_E9zmJ#^xv&j)__HY;j z0PT{xl7hY;sKb;fnfbF%NA=~+y(0(gZpCk(2{4$KBu+V&nKM(}fS9nkhwAYf_h1Q`Y8p^=ikin4@9O8zANP1l{a#=5*)Njs7a=TsjIyTzIougm3`TI zd72ws_*`P@x^*w`v@`HmhsXEX>xArX)RyZlP0 z=dgycG>8#~86>xXEgvI1#1n^LHh|pVda241&34zQZIFgCtG(=}|c z{u#v;fx;f-4pd(5%Upe-=;R_tNaN4j`aNYibgt+Rm!~e@j8x;M@s%Y66;g5Qs1iIR z-p#|#>V)^hpDxaRE&ccch-r(Z(O(4Z76xYUj1DMM4hSZ)K-VP??+dP4O#2N9jjFY{?{^Bdrk8K3SR3LK>=G6fTSpF&!s`7C zhaPHg+ML_MOjOh&h&t3R@&~MRER?(T952PHw@>dTQty7jI_i7O$YhA?Rb5)N8ebJi ze&?}J_sM?Q)ohYSw|bJ!LJ8XaD* zLV3zgjqm-QMzJS4=C2QJzpT`T-f?zptbU{$NA$kd#OuLMp__NxM#ikmbScwd<;3Gc z#vlnR^o7%{k|k4~1d6hPpK^YOshFc>dnMfo;+~|?udH|A3$6B`!?}tQ{Q|3Xp5W~Gh2CbdP(?C^9sZC@# zL3sY_3Ajc69fWGM-Nsx^(D8^3rn5*d!=hCa5uw6{e-K$egV!9~y2qTjVuus)Wg*Hu z^hD+!B+eX1LtM8+Fe}qH*H4e^p0C>dH>jT#>Ucap2}UIw`mb(PyAKY(8X3>H;A5uK z-2KVLt4H{#VFKQs*vg1F{OItEXHO2Bp|hoAZDdAE6RvOROuga9#_l!Sv{&c*&M7i% zt0qGn*D`qTczB{);RHjoO1p0VfvAH;tV&AiGD=(h=*!cgcP=T%!kb3gPGPMnDC;VlplEunfDEw=O;gnW<*y)9jVXPgVSu@^9LUeTEQJ{?%69{sQ^86$}&d2%Lj*p;t9jQS4aa-H@ zb(V($J??nlr^A(j6qZ`Wz zK|++JW;JEp5H zX7Bo;xz#+NSzE!%0iK>3@HE|0R7?fG9QGqvz2ZEvqg9d-nIrCrRjz zi1X=hhhZ+yOx2PmV#V3q7*aNeyK>D9ImFB%wF4hlqo1|MsyJCgZX6p-Dt}qxrgnqn z4DH|br+j+~>izY4L)Am=rKlj7M@Xa$^t*YX_AC0~OLI(}grpi0PDv9+)hq>@jS>ln&8?`%c&8 z=huRC+0Hcb__w=LTf@^pPi0gB3bH^-5M+TbCljxb3>?e@-~+M)h5tqYNrn z{lOWPN+gvTqW4oFe%2ZHMw{hP^EZ}K8|oRA))U*k($&QnfI;fJvhm&V3;RXI)&|;0r$KLLXU?qi@|<0>P|M~^0He$gA8<5jN8;mfyAPR@Q-qGWK>__ewp;~7QCYsMB6RwT zeAclwmg2B5(4jJUDA^~?TKx<5Z_U)eibEVSO03RLZOwgGk!mZ1=;H^{9AwYEX4V4g z;yx#qh0A0WDq^Wrq_mk@!PugeA*Efvd$dRP{vvgeQMnC9m(yR_hzK9fIDr@u)&Kq* z)hp8GOoNJ=<`d7hvc0Mi3ECKvJ`6ko$-LU zhkK`cdt9sPGFr7Dvt68$a*-g_Q+{|J!va-gVeNJH1eblz0c#}wup6!JD zK39R%sNDe8PyxLCmrV4C<`_s>kw`8){UMdc;-0@MT4O*E8u}i$C@L~zUN^1qr&s+` zxtP!Jdf44QzgBIp{rpWrl8S>^F^yW#D_C@1n!7L-AM$&Emg3nwS(`cSsWzVGD+OcwcDnuVt63C-V7=H`6L84W?AK$bHhgy4*4m>Ww==rgqlOv zTX5t?QSq2kRTn?398ukGr8Qbo^lhxr%NH6*&b549#rN8Jc@9`<-?XYwqv+DzL{}+1 zb)}Fug6-{y8mDyR{L;j$?bzHxAaSLMWXhEuSh>JB)mviTe!`K44ATEw^*J`-U_ zeBvbx!-IR2ViD+ucSnsM=Nx&H>5+lLsbcBntK{nkxB^C78fhPuO&2y3n{VE7h@7nZMN{v8Icnl!kv4#?+WF5% z6@+W+#_u+LMV|zWv{c2|dG^YQCHZL(sIn2JvzKnTCY#Z7n&2f+^Q_l|%#h)JV`h#! zJu7L<%0s`Yo?$dR3WUTKSd#75k-rF;TUCl5(zikne6pES4NuPg_-#KVuOOHoo$YFx zFkS7)Nv@*Km0E4(vp3g#cE1ldYvM?wcG!tSrz;&?>Wf119%y|rHYTVaF4z0@in8o; z`X2rMtHmq9bT1VR3XQ+g0A2g_AKqo05oUYB$rL7I`jCK^V^uSC>Oy+e;X*-7 zlaTRz&O@$q-kJ$$b4;6jONLi+-1X9J&aPzI%S$~*1c9yRD8_%1^>g~EC{!r#Z0m~C zX5~dFSGykRM8J(6p#*UndDpeB%nya!D6s@g4e^?os_(Qr`cYerhy2wfk{2(ej!{P; z>{Q*>TKpUxj{#L`_bi!LNlX#7^D&whk*yGyW_xwWo=JYiv370|UnJtoG#CRH-Xp5G z8#m1l^$&|y_yJOv-Lm$!J^xmL(zt^*rtXNI;Jbc`d!dizLZ&mo;51@*_vCu^$&#E! z>Lc&@tm*AwMhv%COO_qZprjl9LAR#@xR!EsT~mE>s6ds-y;mOL3~Pu@1KaUKlTl&_ z1K!Wv27x4dkuVid5C4rut{)Q#ToI&bOd=YO-hL(=F!5jy9%dOauUq)hx;?Pe^yPjh zKkvp0unzeVGTs_pOe<0aG7^z^(L)H;luzaa}GElaibQvcU$b`yazqldlmo{O8U# zr+C)qF>wr#{q&V!!W9q2JdbC1`zzsHNGFHeqK4O47^(ErDFjRPI)*!ub8c3k59ed; z)@O=ln|P_Y=Zz}0_%p&mD1)F5ZSY2YD2I_;)w@<}K03J}3H8>N%e*JaH*0=Ar;$^E zxx-_Q0NrwQb$Lz9bNb=K(}@!?h|38KKh1l=mZ*wsr<7wz@FB))cRcByucAg4>^+Y> z{s2e>=Qu5{1R((%t#LGzJi?cm&$mm z+=xT&=7+g+=39gBAO00DSHpo|W$yExigzXz-XCB}3u4MO!6ez^Em^0(S~hZvr;5YG zOF%|}1IkGg2wW@>zpq)zwC`2DTDc>x#%B>)|6$ZN;(5v0S}E!EMh#6;ygIcU|6aK% zKXaK1SLY0(D0utSNKVyuz8UklMCi+iuV#MC)Z7n59-S$w^ZHN|ON z&ZTUJ2#FoHGD`eVP0;|GkXQ_qR^#>WdCTrvj*5&f0H+pL$?nCQy}=}W%S7i)^wtO@ zf&CJ_xCSJLVVcnDLr!Hh821Tig&A_2v3KBcCsT0s>wJ;6ElTtEZ={TU5pq?g%ul75 zIR-hS;irkZoo6}Wp5I&+&O&#tFzpa|&$cF6_P2{-ho8o4I#Bc`n`oN^^kK2jXdSlS z`%binf0b|EqG*iDD({3h_=y+DC}z(kc{sS`6OHP8O2GVnpErtyZpeONVokDc;XrOj znf^)Z&$(FTMKC6eRKDddfBz3?M|X2siQug(DVl9-!%6R&I&gVM7IQW~1 zX6D&3WXcTJj5%@Y>@4CqM@d4hv|GCJby;=F``jlSE^;AsotIUy=kvi6bQznQja@=U z`4`J$BKjb)w0c)A8GS!{v zL&$ELnjX}N_DyYV*MZ$`HhdD}K|Cwk>oflJ)#59ebd~+&@!x8uGelk{yxI_IFbZcH;3VY8VQt!B~!#$kjt z)xFgHN|1RH#3CilgX-8F+*2zZxupoo?c=GCd!5?+*BCr#gdx+j{J?!F;8#RuYhGnV z4t{8xm|2IIC31rx-aqKsxX(Rm3G)RB-yiG6kfbkHEu>)Ow)ijOSu%%v`6WRu`JG>X z#`M(ee))a&orjF5WC<_DBmuw5V^yf_Qj5qyF>QcI~O;fffwv;Pdd{xgJjzw z&lVx~%}5d3I!S{y_Nx84bNd;SRecLC`8Dz30HwZ4yXM|a06ZfcSSk(b(7XHFyZw_aVzo?Q zH^hGGSEdJxJw1A?FCIxyutwZ4N8uA!>f^%H-X(f?pV#%4Qek_7G*(Nq$wByyCyvfJ z^F6Fy*{@#xtu+ZL1tg1FQ#VB>%RncLYGo02L^^y6_w4Z-couX_Z19O&fPCEe#&;Vb zdEC{U4v7)#_9xo{`>Hcp+{*6qW1ZMw*QC7)cZ~!{NLHqY8P>MftN$qJGeG(3ZU`!z zcVU|I{s70B-bG%qkb#V+r6zXs$DWFTT;tUZ(38lfyh>2K`}faWU0F-%ouXyfzW~V5 BN5%jE literal 0 HcmV?d00001 From d2eb3b628e0a7129befda3a2eb93f16f99137625 Mon Sep 17 00:00:00 2001 From: Jeff Yemin Date: Fri, 24 Apr 2015 15:30:45 -0400 Subject: [PATCH 0042/1665] Reference documentation copy edit to the sync and async quick tours --- .../content/driver-async/getting-started/quick-tour.md | 2 -- docs/reference/content/driver/getting-started/quick-tour.md | 2 -- 2 files changed, 4 deletions(-) diff --git a/docs/reference/content/driver-async/getting-started/quick-tour.md b/docs/reference/content/driver-async/getting-started/quick-tour.md index 7f79a5af006..a79ff8670ab 100644 --- a/docs/reference/content/driver-async/getting-started/quick-tour.md +++ b/docs/reference/content/driver-async/getting-started/quick-tour.md @@ -202,8 +202,6 @@ method to query the collection. ### Find the First Document in a Collection -call the first() method on the result of the find() of method - To get the first document in the collection, call the [first()]({{< apiref "com/mongodb/async/client/MongoIterable.html#first--">}}) method on the [find()]({{< apiref "com/mongodb/async/client/MongoCollection.html#find--">}}) diff --git a/docs/reference/content/driver/getting-started/quick-tour.md b/docs/reference/content/driver/getting-started/quick-tour.md index f2eead862b4..ec4d8242bf2 100644 --- a/docs/reference/content/driver/getting-started/quick-tour.md +++ b/docs/reference/content/driver/getting-started/quick-tour.md @@ -159,8 +159,6 @@ method to query the collection. ### Find the First Document in a Collection -call the first() method on the result of the find() of method - To get the first document in the collection, call the [`first()`]({{< apiref "com/mongodb/client/MongoIterable.html#first--">}}) method on the [`find()`]({{< apiref "com/mongodb/client/MongoCollection.html#find--">}}) From 8b11f8db26b796e78f1b9481d8884fc098951058 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Mon, 27 Apr 2015 09:57:30 +0100 Subject: [PATCH 0043/1665] Added 3.1 release to the documentation JAVA-1773 --- docs/landing/data/releases.toml | 15 +++++-- docs/landing/layouts/partials/quickStart.html | 43 ++++++++++++++++++- docs/landing/static/versions.json | 2 +- docs/reference/config.toml | 6 +-- docs/reference/data/mongodb.toml | 6 +-- 5 files changed, 59 insertions(+), 13 deletions(-) diff --git a/docs/landing/data/releases.toml b/docs/landing/data/releases.toml index ddefabc8e19..556e12aa747 100644 --- a/docs/landing/data/releases.toml +++ b/docs/landing/data/releases.toml @@ -1,4 +1,11 @@ current = "3.0.0" + +[[versions]] + version = "3.1.0-SNAPSHOT" + status = "snapshot" + docs = "./3.1" + api = "http://api.mongodb.org/java/3.1" + [[versions]] version = "3.0.0" status = "current" @@ -14,19 +21,19 @@ current = "3.0.0" [[drivers]] name = "mongodb-driver" description = "The synchronous driver, new in 3.0, for older versions select the: `mongo-java-driver`" - versions = "3.0.0" + versions = "3.1.0-SNAPSHOT,3.0.0" [[drivers]] name = "mongo-java-driver" description = "An uber jar containing the bson library, the core library and the mongodb-driver." - versions = "3.0.0,2.13.1" + versions = "3.1.0-SNAPSHOT,3.0.0,2.13.1" [[drivers]] name = "mongodb-driver-async" description = "The new asynchronous driver, new in 3.0" - versions = "3.0.0" + versions = "3.1.0-SNAPSHOT,3.0.0" [[drivers]] name = "mongodb-driver-core" description = "The core library, new in 3.0" - versions = "3.0.0" + versions = "3.1.0-SNAPSHOT,3.0.0" diff --git a/docs/landing/layouts/partials/quickStart.html b/docs/landing/layouts/partials/quickStart.html index 293a339369c..30f407be702 100644 --- a/docs/landing/layouts/partials/quickStart.html +++ b/docs/landing/layouts/partials/quickStart.html @@ -34,7 +34,7 @@

    Quick Start

    {{ with $.Site.Data.releases.versions }} @@ -69,7 +69,8 @@

    Quick Start

    {{ $driverPos := $.Scratch.Get "qs.driverPos" }} {{ $versionPos := $.Scratch.Get "qs.versionPos" }} {{ if in $currentDriver.versions $currentVersion.version }} -
    +
    +{{ if eq $currentVersion.status "snapshot" }}
    
     <dependencies>
         <dependency>
    @@ -78,18 +79,56 @@ 

    Quick Start

    <version>{{$currentVersion.version}}</version> </dependency> </dependencies> +<repositories> + <repository> + <id>sonatype-snapshots</id> + <name>Sontatype Snapshots</name> + <url>https://oss.sonatype.org/content/repositories/snapshots</url> + <snapshots> + <enabled>true</enabled> + </snapshots> + </repository> +</repositories>
    +{{ else }} +
    
    +<dependencies>
    +    <dependency>
    +        <groupId>org.mongodb</groupId>
    +        <artifactId>{{$currentDriver.name}}</artifactId>
    +        <version>{{$currentVersion.version}}</version>
    +    </dependency>
    +</dependencies>
    +
    +
    +{{ end }}
    + {{ if eq $currentVersion.status "current" }} {{ $.Scratch.Set "qs.firstDriver" false }} + {{end}} {{ $.Scratch.Add "qs.versionPos" 1 }} {{ end }} {{ end }} diff --git a/docs/landing/static/versions.json b/docs/landing/static/versions.json index 4e894e91c98..718c2f780ba 100644 --- a/docs/landing/static/versions.json +++ b/docs/landing/static/versions.json @@ -1 +1 @@ -[{"version": "3.0"}, {"version": "2.13"}] +[{"version": "3.1"}, {"version": "3.0"}, {"version": "2.13"}] diff --git a/docs/reference/config.toml b/docs/reference/config.toml index bdee6baf56f..ebb3020681c 100644 --- a/docs/reference/config.toml +++ b/docs/reference/config.toml @@ -1,4 +1,4 @@ -baseurl = "/mongo-java-driver/3.0" +baseurl = "/mongo-java-driver/3.1" languageCode = "en-us" title = "MongoDB Java Driver" theme = "mongodb" @@ -14,11 +14,11 @@ canonifyurls = false pre = "" weight = 90 identifier = "apiDocs" - url = "http://api.mongodb.org/java/3.0" + url = "http://api.mongodb.org/java/3.1" [[menu.main]] name = "Source Code" pre = "" weight = 90 identifier = "githubLink" - url = "https://github.com/mongodb/mongo-java-driver/tree/3.0.x" + url = "https://github.com/mongodb/mongo-java-driver/tree/master" diff --git a/docs/reference/data/mongodb.toml b/docs/reference/data/mongodb.toml index d5eabf5af6b..f3c73897667 100644 --- a/docs/reference/data/mongodb.toml +++ b/docs/reference/data/mongodb.toml @@ -1,6 +1,6 @@ # Update versions in config.toml as well githubRepo = "mongo-java-driver" -githubBranch = "3.0.x" -currentVersion = "3.0" +githubBranch = "master" +currentVersion = "3.1" highlightTheme = "idea.css" -apiUrl = "http://api.mongodb.org/java/3.0/" +apiUrl = "http://api.mongodb.org/java/3.1/" From 4a69aa4f1bd2806230fb261e44d6384e1a01181d Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Mon, 27 Apr 2015 16:42:08 +0100 Subject: [PATCH 0044/1665] Added search box to google JAVA-1752 --- .../mongodb/layouts/partials/header/main.html | 2 +- .../layouts/partials/header/search.html | 8 +++++ .../layouts/partials/header/topRight.html | 1 + .../themes/mongodb/static/css/overrides.css | 31 +++++++++++++++++-- .../themes/mongodb/static/js/scripts.js | 5 ++- 5 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 docs/reference/themes/mongodb/layouts/partials/header/search.html diff --git a/docs/reference/themes/mongodb/layouts/partials/header/main.html b/docs/reference/themes/mongodb/layouts/partials/header/main.html index cd3f514594f..11c373e0ff4 100644 --- a/docs/reference/themes/mongodb/layouts/partials/header/main.html +++ b/docs/reference/themes/mongodb/layouts/partials/header/main.html @@ -11,6 +11,6 @@
    - {{ partial "header/topRight.html" }} + {{ partial "header/topRight.html" . }} diff --git a/docs/reference/themes/mongodb/layouts/partials/header/search.html b/docs/reference/themes/mongodb/layouts/partials/header/search.html new file mode 100644 index 00000000000..477b6654bb3 --- /dev/null +++ b/docs/reference/themes/mongodb/layouts/partials/header/search.html @@ -0,0 +1,8 @@ + diff --git a/docs/reference/themes/mongodb/layouts/partials/header/topRight.html b/docs/reference/themes/mongodb/layouts/partials/header/topRight.html index 38c1618b4c9..b64a6f1c67c 100644 --- a/docs/reference/themes/mongodb/layouts/partials/header/topRight.html +++ b/docs/reference/themes/mongodb/layouts/partials/header/topRight.html @@ -5,5 +5,6 @@ Community Docs Blog + {{ partial "header/search.html" . }} diff --git a/docs/reference/themes/mongodb/static/css/overrides.css b/docs/reference/themes/mongodb/static/css/overrides.css index 95acdf70669..bd7f42e083e 100644 --- a/docs/reference/themes/mongodb/static/css/overrides.css +++ b/docs/reference/themes/mongodb/static/css/overrides.css @@ -23,8 +23,8 @@ margin-left: 5px; } -.hljsCode pre { padding: 0px; overflow: auto; word-wrap: normal; white-space: nowrap;} -.hljsCode pre code { padding: 24px 12px; overflow: auto; white-space: pre;} +.jsEnabled pre { padding: 0px; overflow: auto; word-wrap: normal; white-space: nowrap;} +.jsEnabled pre code { padding: 24px 12px; overflow: auto; white-space: pre;} .body blockquote { background-color: #edf4e8; @@ -88,3 +88,30 @@ code { a code { color: #006cbc; } + +#search { + visibility: hidden; + display: inline-block; + background-color: rgba(255,255,255,0.3); + border-radius: 6px; + border: 1px solid #3b2920; + font-weight: 300; + font-size: 15px; + padding: 2px; +} + +#search label { + padding-right: 5px; +} + +#search input[name="searchQuery"] { + background-color: transparent !important; + color: white; + border: none; + padding: 2px 0 0 4px; + outline: none; +} + +.jsEnabled #search { + visibility: visible; +} diff --git a/docs/reference/themes/mongodb/static/js/scripts.js b/docs/reference/themes/mongodb/static/js/scripts.js index 7a7589de0ac..d9be4be4e50 100644 --- a/docs/reference/themes/mongodb/static/js/scripts.js +++ b/docs/reference/themes/mongodb/static/js/scripts.js @@ -15,7 +15,7 @@ function initializeJS() { jQuery(document).ready(function(){ initializeJS(); jQuery('[data-toggle="tooltip"]').tooltip(); - jQuery("body").addClass("hljsCode"); + jQuery("body").addClass("jsEnabled"); hljs.initHighlightingOnLoad(); var linkRegex = new RegExp('/' + window.location.host + '/'); jQuery('a').not('[href*="mailto:"]').each(function () { @@ -24,4 +24,7 @@ jQuery(document).ready(function(){ } }); jQuery('.body table').addClass('table').addClass('table-striped'); + jQuery("#search form").submit(function() { + $('#search input[name="q"]').attr("value", $('#search input[name="searchQuery"]').val() + ' ' + $('#search input[name="site"]').val()); + }); }); From 90d386e4d67750accf953df1df9f089e3f51a754 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Mon, 27 Apr 2015 17:11:40 +0100 Subject: [PATCH 0045/1665] Add site to search correctly JAVA-1752 --- .../themes/mongodb/layouts/partials/header/search.html | 2 +- docs/reference/themes/mongodb/static/js/scripts.js | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/reference/themes/mongodb/layouts/partials/header/search.html b/docs/reference/themes/mongodb/layouts/partials/header/search.html index 477b6654bb3..2570e110f7b 100644 --- a/docs/reference/themes/mongodb/layouts/partials/header/search.html +++ b/docs/reference/themes/mongodb/layouts/partials/header/search.html @@ -1,7 +1,7 @@