diff --git a/README.md b/README.md index 3516bc787..b4c7605b8 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,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.12.0' +implementation 'com.google.cloud:google-cloud-datastore:2.12.1' ``` If you are using SBT, add this to your dependencies: ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.12.0" +libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "2.12.1" ``` ## Authentication @@ -234,6 +234,13 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tre | --------------------------- | --------------------------------- | ------ | | Native Image Datastore Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/native-image-sample/src/main/java/com/example/datastore/NativeImageDatastoreSample.java) | | Quickstart Sample | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java) | +| Count Aggregation In Transaction | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationInTransaction.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationInTransaction.java) | +| Count Aggregation On Kind | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationOnKind.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationOnKind.java) | +| Count Aggregation With Gql Query | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithGqlQuery.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithGqlQuery.java) | +| Count Aggregation With Limit | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithLimit.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithLimit.java) | +| Count Aggregation With Order By | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithOrderBy.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithOrderBy.java) | +| Count Aggregation With Property Filter | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithPropertyFilter.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithPropertyFilter.java) | +| Count Aggregation With Stale Read | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithStaleRead.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithStaleRead.java) | | Task List | [source code](https://github.com/googleapis/java-datastore/blob/main/samples/snippets/src/main/java/com/google/datastore/snippets/TaskList.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-datastore&page=editor&open_in_editor=samples/snippets/src/main/java/com/google/datastore/snippets/TaskList.java) | diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationInTransaction.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationInTransaction.java new file mode 100644 index 000000000..ca62e2cab --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationInTransaction.java @@ -0,0 +1,85 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_in_transaction] + +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.Datastore.TransactionCallable; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.EntityQuery; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.StructuredQuery.PropertyFilter; +import com.google.common.collect.Iterables; + +public class CountAggregationInTransaction { + + public static void invoke() { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("owner", "john").build(), + Entity.newBuilder(task2Key).set("owner", "john").build()); + + // Using transactions to maintain consistent application state. + datastore.runInTransaction( + (TransactionCallable) + transaction -> { + // Create a query to get the count of all tasks of owner 'John'. + EntityQuery tasksOfJohn = + Query.newEntityQueryBuilder() + .setKind(kind) + .setFilter(PropertyFilter.eq("owner", "john")) + .build(); + AggregationQuery totalTasksQuery = + Query.newAggregationQueryBuilder() + .over(tasksOfJohn) + .addAggregation(count().as("tasks_count")) + .build(); + + // Executing aggregation query in the ongoing transaction. + Long tasksCount = + Iterables.getOnlyElement(transaction.runAggregation(totalTasksQuery)) + .get("tasks_count"); + + if (tasksCount < 2) { + Key newTaskKey = datastore.newKeyFactory().setKind(kind).newKey("task3"); + Entity newTask = Entity.newBuilder(newTaskKey).set("owner", "john").build(); + // Inserting a new entity in the transaction. + transaction.put(newTask); + } else { + System.out.printf("Found existing %d tasks, rolling back", tasksCount); + throw new Exception("User 'John' cannot have more than 2 tasks"); + } + return null; + }); + } +} +// [END datastore_count_aggregation_query_in_transaction] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationOnKind.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationOnKind.java new file mode 100644 index 000000000..b2673653a --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationOnKind.java @@ -0,0 +1,90 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_on_kind] +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +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.Key; +import com.google.cloud.datastore.Query; +import com.google.common.collect.Iterables; + +public class CountAggregationOnKind { + // Instantiates a client. + private static final Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + private static final String kind = "Task"; + + // Setting up Tasks in database + private static void setUpTasks() { + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).build(), + Entity.newBuilder(task2Key).set("done", false).build(), + Entity.newBuilder(task3Key).set("done", true).build()); + } + + // Accessing aggregation result by the generated alias. + private static void usageWithGeneratedAlias() { + EntityQuery selectAllTasks = Query.newEntityQueryBuilder().setKind(kind).build(); + // Creating an aggregation query to get the count of all tasks. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder().over(selectAllTasks).addAggregation(count()).build(); + // Executing aggregation query. + AggregationResult aggregationResult = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + + System.out.printf( + "Total tasks (accessible from default alias) is %d", + aggregationResult.get("property_1")); // 3 + } + + // Accessing aggregation result by the provided custom alias. + private static void usageWithCustomAlias() { + EntityQuery selectAllTasks = Query.newEntityQueryBuilder().setKind(kind).build(); + // Creating an aggregation query to get the count of all tasks. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(selectAllTasks) + // passing 'total_count' as alias in the aggregation query. + .addAggregation(count().as("total_count")) + .build(); + // Executing aggregation query. + AggregationResult aggregationResult = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + + System.out.printf("Total tasks count is %d", aggregationResult.get("total_count")); // 3 + } + + public static void invoke() { + setUpTasks(); + usageWithGeneratedAlias(); + usageWithCustomAlias(); + } +} +// [END datastore_count_aggregation_query_on_kind] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithGqlQuery.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithGqlQuery.java new file mode 100644 index 000000000..fd2bf8cc4 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithGqlQuery.java @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_gql] +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.GqlQuery; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.Query; +import com.google.common.collect.Iterables; + +public class CountAggregationWithGqlQuery { + + public static void invoke() { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).build(), + Entity.newBuilder(task2Key).set("done", false).build(), + Entity.newBuilder(task3Key).set("done", true).build()); + + // Create a GQL query to get the count of all tasks. + GqlQuery selectAllTasks = + Query.newGqlQueryBuilder( + "AGGREGATE COUNT(*) AS total_count, COUNT_UP_TO(2) AS count_with_limit " + + "OVER (SELECT * FROM Task)") + .setAllowLiteral(true) + .build(); + // Create the aggregation query builder and set the query. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder().over(selectAllTasks).build(); + // Executing aggregation query. + AggregationResult allTasksCountQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + + System.out.printf( + "We have at least %d tasks", allTasksCountQueryResult.get("count_with_limit")); // 2 + System.out.printf("Total tasks count is %d", allTasksCountQueryResult.get("total_count")); // 3 + + // Create a query to get the count of all completed tasks. + GqlQuery completedTasks = + Query.newGqlQueryBuilder( + "AGGREGATE COUNT(*) AS total_completed_count " + + "OVER (SELECT * FROM Task WHERE done = true)") + .setAllowLiteral(true) + .build(); + // Create the aggregation query builder and set the query. + AggregationQuery completedTasksCountQuery = + Query.newAggregationQueryBuilder().over(completedTasks).build(); + + // Executing aggregation query. + AggregationResult completedTasksCountQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(completedTasksCountQuery)); + + System.out.printf( + "Total completed tasks count is %d", + completedTasksCountQueryResult.get("total_completed_count")); // 2 + } +} +// [END datastore_count_aggregation_query_gql] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithLimit.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithLimit.java new file mode 100644 index 000000000..a6a1a4c55 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithLimit.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_with_limit] + +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +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.Key; +import com.google.cloud.datastore.Query; +import com.google.common.collect.Iterables; + +public class CountAggregationWithLimit { + public static void invoke() { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).build(), + Entity.newBuilder(task2Key).set("done", false).build(), + Entity.newBuilder(task3Key).set("done", true).build()); + + EntityQuery selectAllTasks = Query.newEntityQueryBuilder().setKind(kind).setLimit(2).build(); + // Creating an aggregation query to get the count of all tasks. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(selectAllTasks) + .addAggregation(count().as("at_least")) + .build(); + // Executing aggregation query. + AggregationResult limitQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + + System.out.printf("We have at least %d tasks", limitQueryResult.get("at_least")); // 2 + } +} +// [END datastore_count_aggregation_query_with_limit] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithOrderBy.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithOrderBy.java new file mode 100644 index 000000000..247bbdefe --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithOrderBy.java @@ -0,0 +1,70 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_with_order_by] + +import static com.google.cloud.datastore.StructuredQuery.OrderBy.asc; +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +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.Key; +import com.google.cloud.datastore.Query; +import com.google.common.collect.Iterables; + +public class CountAggregationWithOrderBy { + public static void invoke() { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).set("priority", 1).build(), + // Priority not specified. + Entity.newBuilder(task2Key).set("done", false).build(), + Entity.newBuilder(task3Key).set("done", true).set("priority", 2).build()); + + // OrderBy acts as an existence filter. + EntityQuery selectAllTasks = + Query.newEntityQueryBuilder().setKind(kind).addOrderBy(asc("priority")).build(); + // Creating an aggregation query to get the count of all tasks. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(selectAllTasks) + .addAggregation(count().as("count")) + .build(); + // Executing aggregation query. + AggregationResult limitQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + + System.out.printf( + "Total %d tasks found with priority field", limitQueryResult.get("count")); // 2 + } +} +// [END datastore_count_aggregation_query_with_order_by] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithPropertyFilter.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithPropertyFilter.java new file mode 100644 index 000000000..ecc53b496 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithPropertyFilter.java @@ -0,0 +1,90 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_with_filters] + +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +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.Key; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.StructuredQuery.PropertyFilter; +import com.google.common.collect.Iterables; + +public class CountAggregationWithPropertyFilter { + + public static void invoke() { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + + // Save all the tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).build(), + Entity.newBuilder(task2Key).set("done", false).build(), + Entity.newBuilder(task3Key).set("done", true).build()); + + EntityQuery completedTasks = + Query.newEntityQueryBuilder() + .setKind(kind) + .setFilter(PropertyFilter.eq("done", true)) + .build(); + EntityQuery remainingTasks = + Query.newEntityQueryBuilder() + .setKind(kind) + .setFilter(PropertyFilter.eq("done", false)) + .build(); + // Creating an aggregation query to get the count of all completed tasks. + AggregationQuery completedTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(completedTasks) + .addAggregation(count().as("total_completed_count")) + .build(); + // Creating an aggregation query to get the count of all remaining tasks. + AggregationQuery remainingTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(remainingTasks) + .addAggregation(count().as("total_remaining_count")) + .build(); + + // Executing aggregation query. + AggregationResult completedTasksCountQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(completedTasksCountQuery)); + AggregationResult remainingTasksCountQueryResult = + Iterables.getOnlyElement(datastore.runAggregation(remainingTasksCountQuery)); + + System.out.printf( + "Total completed tasks count is %d", + completedTasksCountQueryResult.get("total_completed_count")); // 2 + System.out.printf( + "Total remaining tasks count is %d", + remainingTasksCountQueryResult.get("total_remaining_count")); // 1 + } +} +// [END datastore_count_aggregation_query_with_filters] diff --git a/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithStaleRead.java b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithStaleRead.java new file mode 100644 index 000000000..e46670b98 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/aggregation/CountAggregationWithStaleRead.java @@ -0,0 +1,80 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore.aggregation; + +// [START datastore_count_aggregation_query_stale_read] + +import static com.google.cloud.datastore.aggregation.Aggregation.count; + +import com.google.cloud.Timestamp; +import com.google.cloud.datastore.AggregationQuery; +import com.google.cloud.datastore.AggregationResult; +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.Key; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.ReadOption; +import com.google.common.collect.Iterables; + +public class CountAggregationWithStaleRead { + + public static void invoke() throws InterruptedException { + // Instantiates a client. + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity. + String kind = "Task"; + + Key task1Key = datastore.newKeyFactory().setKind(kind).newKey("task1"); + Key task2Key = datastore.newKeyFactory().setKind(kind).newKey("task2"); + + // Saving only two tasks. + datastore.put( + Entity.newBuilder(task1Key).set("done", true).build(), + Entity.newBuilder(task2Key).set("done", false).build()); + Thread.sleep(1000); + final Timestamp pastTimestamp = Timestamp.now(); // we have two tasks in database at this time. + + Thread.sleep(1000); + // Saving third tasks. + Key task3Key = datastore.newKeyFactory().setKind(kind).newKey("task3"); + datastore.put(Entity.newBuilder(task3Key).set("done", false).build()); + + EntityQuery selectAllTasks = Query.newEntityQueryBuilder().setKind(kind).build(); + + // Creating an aggregation query to get the count of all tasks. + AggregationQuery allTasksCountQuery = + Query.newAggregationQueryBuilder() + .over(selectAllTasks) + .addAggregation(count().as("total_count")) + .build(); + + // Executing aggregation query. + AggregationResult tasksCountLatest = + Iterables.getOnlyElement(datastore.runAggregation(allTasksCountQuery)); + System.out.printf("Latest tasks count is %d", tasksCountLatest.get("total_count")); // 3 + + // Executing aggregation query with past timestamp. + AggregationResult tasksCountInPast = + Iterables.getOnlyElement( + datastore.runAggregation(allTasksCountQuery, ReadOption.readTime(pastTimestamp))); + System.out.printf("Stale tasks count is %d", tasksCountInPast.get("total_count")); // 2 + } +} +// [END datastore_count_aggregation_query_stale_read] diff --git a/samples/snippets/src/test/java/com/example/datastore/AggregationQuerySampleTestIT.java b/samples/snippets/src/test/java/com/example/datastore/AggregationQuerySampleTestIT.java new file mode 100644 index 000000000..662802e51 --- /dev/null +++ b/samples/snippets/src/test/java/com/example/datastore/AggregationQuerySampleTestIT.java @@ -0,0 +1,101 @@ +/* + * Copyright 2022 Google LLC + * + * 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.example.datastore; + +import static org.junit.Assert.assertThrows; + +import com.example.datastore.aggregation.CountAggregationInTransaction; +import com.example.datastore.aggregation.CountAggregationOnKind; +import com.example.datastore.aggregation.CountAggregationWithGqlQuery; +import com.example.datastore.aggregation.CountAggregationWithLimit; +import com.example.datastore.aggregation.CountAggregationWithOrderBy; +import com.example.datastore.aggregation.CountAggregationWithPropertyFilter; +import com.example.datastore.aggregation.CountAggregationWithStaleRead; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.KeyQuery; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.QueryResults; +import com.google.common.collect.ImmutableList; +import com.rule.SystemsOutRule; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class AggregationQuerySampleTestIT { + + private final Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + @Rule public final SystemsOutRule systemsOutRule = new SystemsOutRule(); + + @Before + public void setUp() throws Exception { + // Retrieving and deleting all the 'Task' entities. + KeyQuery allKeysQuery = Query.newKeyQueryBuilder().setKind("Task").build(); + QueryResults allKeys = datastore.run(allKeysQuery); + Key[] keysToDelete = ImmutableList.copyOf(allKeys).toArray(new Key[0]); + datastore.delete(keysToDelete); + } + + @Test + public void testAggregationQueryAndCountAggregationSample() { + CountAggregationOnKind.invoke(); + systemsOutRule.assertContains("Total tasks count is 3"); + systemsOutRule.assertContains("Total tasks (accessible from default alias) is 3"); + } + + @Test + public void testAggregationQueryAndCountAggregationWithLimitSample() { + CountAggregationWithLimit.invoke(); + systemsOutRule.assertContains("We have at least 2 tasks"); + } + + @Test + public void testAggregationQueryAndCountAggregationWithOrderBySample() { + CountAggregationWithOrderBy.invoke(); + systemsOutRule.assertContains("Total 2 tasks found with priority field"); + } + + @Test + public void testAggregationQueryAndCountAggregationWithPropertyFilterSample() { + CountAggregationWithPropertyFilter.invoke(); + systemsOutRule.assertContains("Total completed tasks count is 2"); + systemsOutRule.assertContains("Total remaining tasks count is 1"); + } + + @Test + public void testAggregationQueryAndCountAggregationSampleWithGqlQuery() { + CountAggregationWithGqlQuery.invoke(); + systemsOutRule.assertContains("We have at least 2 tasks"); + systemsOutRule.assertContains("Total tasks count is 3"); + systemsOutRule.assertContains("Total completed tasks count is 2"); + } + + @Test + public void testAggregationQueryAndCountWithStaleRead() throws InterruptedException { + CountAggregationWithStaleRead.invoke(); + systemsOutRule.assertContains("Latest tasks count is 3"); + systemsOutRule.assertContains("Stale tasks count is 2"); + } + + @Test + public void testAggregationQueryAndCountWithTransaction() throws InterruptedException { + assertThrows(Exception.class, CountAggregationInTransaction::invoke); + systemsOutRule.assertContains("Found existing 2 tasks, rolling back"); + } +} diff --git a/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java b/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java index 1d46f20a4..09823479f 100644 --- a/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java +++ b/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java @@ -16,15 +16,13 @@ package com.example.datastore; -import static com.google.common.truth.Truth.assertThat; - import com.google.cloud.datastore.Datastore; import com.google.cloud.datastore.DatastoreOptions; import com.google.cloud.datastore.Key; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; +import com.rule.SystemsOutRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -33,8 +31,8 @@ @RunWith(JUnit4.class) @SuppressWarnings("checkstyle:abbreviationaswordinname") public class QuickstartSampleIT { - private ByteArrayOutputStream bout; - private PrintStream out; + + @Rule public final SystemsOutRule systemsOutRule = new SystemsOutRule(); private static final void deleteTestEntity() { Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); @@ -47,10 +45,6 @@ private static final void deleteTestEntity() { @Before public void setUp() { deleteTestEntity(); - - bout = new ByteArrayOutputStream(); - out = new PrintStream(bout); - System.setOut(out); } @After @@ -62,8 +56,7 @@ public void tearDown() { @Test public void testQuickstart() throws Exception { QuickstartSample.main(); - String got = bout.toString(); - assertThat(got).contains("Saved sampletask1: Buy milk"); - assertThat(got).contains("Retrieved sampletask1: Buy milk"); + systemsOutRule.assertContains("Saved sampletask1: Buy milk"); + systemsOutRule.assertContains("Retrieved sampletask1: Buy milk"); } } diff --git a/samples/snippets/src/test/java/com/rule/SystemsOutRule.java b/samples/snippets/src/test/java/com/rule/SystemsOutRule.java new file mode 100644 index 000000000..9cdb2744e --- /dev/null +++ b/samples/snippets/src/test/java/com/rule/SystemsOutRule.java @@ -0,0 +1,53 @@ +/* + * Copyright 2022 Google LLC + * + * 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.rule; + +import static com.google.common.truth.Truth.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public class SystemsOutRule implements TestRule { + private ByteArrayOutputStream currentOut; + + @Override + public Statement apply(Statement statement, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + // Setting up customized PrintStream + final PrintStream originalOut = System.out; + currentOut = new ByteArrayOutputStream(); + System.setOut(new PrintStream(currentOut)); + + // Running tests + statement.evaluate(); + + // Restoring original PrintStream + System.setOut(originalOut); + currentOut = null; + } + }; + } + + public void assertContains(String content) { + assertThat(currentOut.toString()).contains(content); + } +}