Repository: googleapis/java-datastore (java)

Issue:
AggregationQuery doesn't respect namespace from `com.google.cloud.datastore.Datastore` object
#### Given
I have `2 entities` stored for `Task` kind under the namespace `ns1` and i configure a `com.google.cloud.datastore.Datastore` service with `ns1` namespace.

#### Scenario
When I try to run **entity** query with or without namespace through the `com.google.cloud.datastore.Datastore` object configured with namespace, i get same results, whereas in case of `AggregationQuery` i don't.

#### Code example

```java
import static com.google.cloud.datastore.aggregation.Aggregation.count;
import static com.google.common.collect.Iterables.getOnlyElement;

import com.google.cloud.datastore.AggregationQuery;
import com.google.cloud.datastore.Datastore;
import com.google.cloud.datastore.DatastoreOptions;
import com.google.cloud.datastore.Entity;
import com.google.cloud.datastore.EntityQuery;
import com.google.cloud.datastore.Query;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Playground {

  public static void main(String[] args) {
    DatastoreOptions datastoreOptions = DatastoreOptions.newBuilder()
        .setNamespace("ns1")
        .build();
    Datastore datastore = datastoreOptions.getService();

    EntityQuery entityQueryWithNamespace = Query.newEntityQueryBuilder()
        .setKind("Task")
        .setNamespace("ns1")
        .build();

    EntityQuery entityQueryWithoutNamespace = Query.newEntityQueryBuilder()
        .setKind("Task")
        .build();

    AggregationQuery aggregationQueryWithNamespace = Query.newAggregationQueryBuilder()
        .over(Query.newKeyQueryBuilder().setKind("Task").build())
        .addAggregation(count().as("my_count"))
        .setNamespace("ns1")
        .build();

    AggregationQuery aggregationQueryWithoutNamespace = Query.newAggregationQueryBuilder()
        .over(Query.newKeyQueryBuilder().setKind("Task").build())
        .addAggregation(count().as("my_count"))
        .build();

    System.out.println("Total elements from entity query with namespace " + toList(
        datastore.run(entityQueryWithNamespace)).size());  // 2
    System.out.println("Total elements from entity query without namespace " + toList(
        datastore.run(entityQueryWithoutNamespace)).size()); // 2

    System.out.println("Total elements from aggregation query with namespace " + getOnlyElement(
        datastore.runAggregation(aggregationQueryWithNamespace)).get("my_count")); // 2
    System.out.println("Total elements from aggregation query without namespace " + getOnlyElement(
        datastore.runAggregation(aggregationQueryWithoutNamespace)).get("my_count")); // 0
  }

  private static List<Entity> toList(Iterator<Entity> results) {
    ArrayList<Entity> list = new ArrayList<>();
    while (results.hasNext()) {
      list.add(results.next());
    }
    return list;
  }

}

```
#### Problem
last query execution of `aggregationQueryWithoutNamespace` returns 0 count.

#### Explanation
If a namespace is configured in `AggragationQuery` the library will use that namespace to run that query, and if it's not present, it'll completely ignore the one configured in `com.google.cloud.datastore.Datastore` service and simply run the query in default namespace and hence the diff in output.

https://github.com/googleapis/java-datastore/blob/412be617db28a97d38883bd6e26ddbc7d1c434fa/google-cloud-datastore/src/main/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparer.java#L92-L99

This part of code needs to be changed, where we can give priority to the namespace from `AggregationQuery` followed by `com.google.cloud.datastore.Datastore` service to keep it consistent with the Entity query.

Thanks!


Pull request:
fix: Using namespace from DatastoreOptions if aggregation query is not configured with one.
fix #1054 

Patch:
diff --git a/README.md b/README.md
index 6b61cb06..de738f5a 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ If you are using Maven without the BOM, add this to your dependencies:
 <dependency>
   <groupId>com.google.cloud</groupId>
   <artifactId>google-cloud-datastore</artifactId>
-  <version>2.14.3</version>
+  <version>2.14.4</version>
 </dependency>
 
 ```
@@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-datastore'
 If you are using Gradle without BOM, add this to your dependencies:
 
 ```Groovy
-implementation 'com.google.cloud:google-cloud-datastore:2.14.3'
+implementation 'com.google.cloud:google-cloud-datastore:2.14.4'
 ```
 
 If you are using SBT, add this to your dependencies:
 
 ```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.14.3"
+libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.14.4"
 ```
 <!-- {x-version-update-end} -->
 
@@ -370,7 +370,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
 [kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java11.html
 [stability-image]: https://img.shields.io/badge/stability-stable-green
 [maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-datastore.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.14.3
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-datastore/2.14.4
 [authentication]: https://github.com/googleapis/google-cloud-java#authentication
 [auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
 [predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparer.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparer.java
index b5da8d9f..8f4e51d6 100644
--- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparer.java
+++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparer.java
@@ -26,6 +26,7 @@ import com.google.cloud.datastore.ReadOption.QueryAndReadOptions;
 import com.google.cloud.datastore.ReadOptionProtoPreparer;
 import com.google.cloud.datastore.StructuredQueryProtoPreparer;
 import com.google.cloud.datastore.aggregation.Aggregation;
+import com.google.common.base.MoreObjects;
 import com.google.datastore.v1.GqlQuery;
 import com.google.datastore.v1.PartitionId;
 import com.google.datastore.v1.Query;
@@ -92,9 +93,9 @@ public class AggregationQueryRequestProtoPreparer
   private PartitionId getPartitionId(AggregationQuery aggregationQuery) {
     PartitionId.Builder builder =
         PartitionId.newBuilder().setProjectId(datastoreOptions.getProjectId());
-    if (aggregationQuery.getNamespace() != null) {
-      builder.setNamespaceId(aggregationQuery.getNamespace());
-    }
+    String namespace =
+        MoreObjects.firstNonNull(aggregationQuery.getNamespace(), datastoreOptions.getNamespace());
+    builder.setNamespaceId(namespace);
     return builder.build();
   }
 }
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index f2714fa7..60c4f8c4 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -29,7 +29,7 @@
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>google-cloud-datastore</artifactId>
-      <version>2.14.3</version>
+      <version>2.14.4</version>
     </dependency>
     <!-- [END datastore_install_without_bom] -->
 
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 21bcd42b..f9a10361 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -28,7 +28,7 @@
     <dependency>
       <groupId>com.google.cloud</groupId>
       <artifactId>google-cloud-datastore</artifactId>
-      <version>2.14.3</version>
+      <version>2.14.4</version>
     </dependency>
 
     <dependency>


Test patch:
diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparerTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparerTest.java
index 6301ebef..934e3a4c 100644
--- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparerTest.java
+++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/execution/request/AggregationQueryRequestProtoPreparerTest.java
@@ -154,7 +154,7 @@ public class AggregationQueryRequestProtoPreparerTest {
   }
 
   @Test
-  public void shouldPrepareAggregationQueryWithoutNamespace() {
+  public void shouldPrepareAggregationQueryWithNamespaceFromDatastoreOptions() {
     AggregationQuery structuredQueryWithoutNamespace =
         Query.newAggregationQueryBuilder()
             .addAggregation(count().as("total"))
@@ -169,8 +169,9 @@ public class AggregationQueryRequestProtoPreparerTest {
         protoPreparer.prepare(QueryAndReadOptions.create(gqlQueryWithoutNamespace));
 
     assertThat(runAggregationQueryFromStructuredQuery.getPartitionId().getNamespaceId())
-        .isEqualTo("");
-    assertThat(runAggregationQueryFromGqlQuery.getPartitionId().getNamespaceId()).isEqualTo("");
+        .isEqualTo(NAMESPACE);
+    assertThat(runAggregationQueryFromGqlQuery.getPartitionId().getNamespaceId())
+        .isEqualTo(NAMESPACE);
   }
 
   private RunAggregationQueryRequest prepareQuery(AggregationQuery query, ReadOption readOption) {