diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6137bef2a..538bf5f09 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,5 +4,8 @@ # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax +# The @googleapis/firestore-dpe is the default owner for changes in this repo +**/*.java @googleapis/firestore-dpe + # The java-samples-reviewers team is the default owner for samples changes samples/**/*.java @googleapis/java-samples-reviewers diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 445b4bf82..683022075 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -36,11 +36,14 @@ jobs: JOB_TYPE: test dependencies: runs-on: ubuntu-latest + strategy: + matrix: + java: [8, 11] steps: - uses: actions/checkout@v2 - uses: actions/setup-java@v1 with: - java-version: 8 + java-version: ${{matrix.java}} - run: java -version - run: .kokoro/dependencies.sh linkage-monitor: diff --git a/.github/workflows/samples.yaml b/.github/workflows/samples.yaml new file mode 100644 index 000000000..a1d500730 --- /dev/null +++ b/.github/workflows/samples.yaml @@ -0,0 +1,14 @@ +on: + pull_request: +name: samples +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-java@v1 + with: + java-version: 8 + - name: Run checkstyle + run: mvn -P lint --quiet --batch-mode checkstyle:check + working-directory: samples/snippets diff --git a/.kokoro/continuous/dependencies.cfg b/.kokoro/continuous/dependencies.cfg deleted file mode 100644 index 8908efe02..000000000 --- a/.kokoro/continuous/dependencies.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/java-datastore/.kokoro/dependencies.sh" -} diff --git a/.kokoro/continuous/integration.cfg b/.kokoro/continuous/integration.cfg deleted file mode 100644 index 3b017fc80..000000000 --- a/.kokoro/continuous/integration.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} diff --git a/.kokoro/continuous/java11.cfg b/.kokoro/continuous/java11.cfg deleted file mode 100644 index 709f2b4c7..000000000 --- a/.kokoro/continuous/java11.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java11" -} diff --git a/.kokoro/continuous/java7.cfg b/.kokoro/continuous/java7.cfg deleted file mode 100644 index cb24f44ee..000000000 --- a/.kokoro/continuous/java7.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java7" -} diff --git a/.kokoro/continuous/java8-osx.cfg b/.kokoro/continuous/java8-osx.cfg deleted file mode 100644 index 3ba7de0b1..000000000 --- a/.kokoro/continuous/java8-osx.cfg +++ /dev/null @@ -1,3 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -build_file: "java-datastore/.kokoro/build.sh" diff --git a/.kokoro/continuous/java8-win.cfg b/.kokoro/continuous/java8-win.cfg deleted file mode 100644 index 85494f810..000000000 --- a/.kokoro/continuous/java8-win.cfg +++ /dev/null @@ -1,3 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -build_file: "java-datastore/.kokoro/build.bat" diff --git a/.kokoro/continuous/lint.cfg b/.kokoro/continuous/lint.cfg deleted file mode 100644 index 6d323c8ae..000000000 --- a/.kokoro/continuous/lint.cfg +++ /dev/null @@ -1,13 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. - -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} - -env_vars: { - key: "JOB_TYPE" - value: "lint" -} \ No newline at end of file diff --git a/.kokoro/continuous/propose_release.cfg b/.kokoro/continuous/propose_release.cfg deleted file mode 100644 index 8ca7ae7f7..000000000 --- a/.kokoro/continuous/propose_release.cfg +++ /dev/null @@ -1,53 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "java-datastore/.kokoro/trampoline.sh" - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/node:10-user" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/java-datastore/.kokoro/continuous/propose_release.sh" -} - -# tokens used by release-please to keep an up-to-date release PR. -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "github-magic-proxy-key-release-please" - } - } -} - -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "github-magic-proxy-token-release-please" - } - } -} - -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "github-magic-proxy-url-release-please" - } - } -} diff --git a/.kokoro/continuous/samples.cfg b/.kokoro/continuous/samples.cfg deleted file mode 100644 index fa7b493d0..000000000 --- a/.kokoro/continuous/samples.cfg +++ /dev/null @@ -1,31 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} - -env_vars: { - key: "JOB_TYPE" - value: "samples" -} - -env_vars: { - key: "GCLOUD_PROJECT" - value: "gcloud-devel" -} - -env_vars: { - key: "GOOGLE_APPLICATION_CREDENTIALS" - value: "keystore/73713_java_it_service_account" -} - -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "java_it_service_account" - } - } -} diff --git a/.kokoro/dependencies.sh b/.kokoro/dependencies.sh index cf3bb4347..c91e5a569 100755 --- a/.kokoro/dependencies.sh +++ b/.kokoro/dependencies.sh @@ -41,12 +41,15 @@ echo "****************** DEPENDENCY LIST COMPLETENESS CHECK *******************" ## Run dependency list completeness check function completenessCheck() { # Output dep list with compile scope generated using the original pom + # Running mvn dependency:list on Java versions that support modules will also include the module of the dependency. + # This is stripped from the output as it is not present in the flattened pom. + # Only dependencies with 'compile' or 'runtime' scope are included from original dependency list. msg "Generating dependency list using original pom..." - mvn dependency:list -f pom.xml -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' | grep -v ':test$' >.org-list.txt + mvn dependency:list -f pom.xml -DincludeScope=runtime -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' | sed -e s/\\s--\\smodule.*// >.org-list.txt - # Output dep list generated using the flattened pom (test scope deps are ommitted) + # Output dep list generated using the flattened pom (only 'compile' and 'runtime' scopes) msg "Generating dependency list using flattened pom..." - mvn dependency:list -f .flattened-pom.xml -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' >.new-list.txt + mvn dependency:list -f .flattened-pom.xml -DincludeScope=runtime -Dsort=true | grep '\[INFO] .*:.*:.*:.*:.*' >.new-list.txt # Compare two dependency lists msg "Comparing dependency lists..." @@ -83,4 +86,4 @@ then else msg "Errors found. See log statements above." exit 1 -fi +fi \ No newline at end of file diff --git a/.kokoro/nightly/dependencies.cfg b/.kokoro/nightly/dependencies.cfg deleted file mode 100644 index 8908efe02..000000000 --- a/.kokoro/nightly/dependencies.cfg +++ /dev/null @@ -1,12 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/java-datastore/.kokoro/dependencies.sh" -} diff --git a/.kokoro/nightly/lint.cfg b/.kokoro/nightly/lint.cfg deleted file mode 100644 index 6d323c8ae..000000000 --- a/.kokoro/nightly/lint.cfg +++ /dev/null @@ -1,13 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Configure the docker image for kokoro-trampoline. - -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/java8" -} - -env_vars: { - key: "JOB_TYPE" - value: "lint" -} \ No newline at end of file diff --git a/.kokoro/release/publish_javadoc.cfg b/.kokoro/release/publish_javadoc.cfg index f321c5f60..5429fad5e 100644 --- a/.kokoro/release/publish_javadoc.cfg +++ b/.kokoro/release/publish_javadoc.cfg @@ -1,14 +1,24 @@ # Format: //devtools/kokoro/config/proto/build.proto + +gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/doc-templates/" + env_vars: { key: "STAGING_BUCKET" value: "docs-staging" } +env_vars: { + key: "STAGING_BUCKET_V2" + value: "docs-staging-v2-staging" + # Production will be at: docs-staging-v2 +} + env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/java-datastore/.kokoro/release/publish_javadoc.sh" } + before_action { fetch_keystore { keystore_resource { diff --git a/.kokoro/release/publish_javadoc.sh b/.kokoro/release/publish_javadoc.sh index 3dd8fe4a9..0597eb241 100755 --- a/.kokoro/release/publish_javadoc.sh +++ b/.kokoro/release/publish_javadoc.sh @@ -24,6 +24,11 @@ if [[ -z "${STAGING_BUCKET}" ]]; then exit 1 fi +if [[ -z "${STAGING_BUCKET_V2}" ]]; then + echo "Need to set STAGING_BUCKET_V2 environment variable" + exit 1 +fi + # work from the git root directory pushd $(dirname "$0")/../../ @@ -31,13 +36,13 @@ pushd $(dirname "$0")/../../ python3 -m pip install gcp-docuploader # compile all packages -mvn clean install -B -DskipTests=true +mvn clean install -B -q -DskipTests=true NAME=google-cloud-datastore VERSION=$(grep ${NAME}: versions.txt | cut -d: -f3) # build the docs -mvn site -B +mvn site -B -q pushd target/site/apidocs @@ -53,3 +58,19 @@ python3 -m docuploader upload . \ --staging-bucket ${STAGING_BUCKET} popd + +# V2 +mvn clean site -B -q -Ddevsite.template="${KOKORO_GFILE_DIR}/java/" + +pushd target/devsite + +# create metadata +python3 -m docuploader create-metadata \ + --name ${NAME} \ + --version ${VERSION} \ + --language java + +# upload docs +python3 -m docuploader upload . \ + --credentials ${CREDENTIALS} \ + --staging-bucket ${STAGING_BUCKET_V2} diff --git a/.kokoro/release/stage.cfg b/.kokoro/release/stage.cfg index c6ff500b2..159e4cfdf 100644 --- a/.kokoro/release/stage.cfg +++ b/.kokoro/release/stage.cfg @@ -13,32 +13,7 @@ action { } } -# Fetch the token needed for reporting release status to GitHub -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "yoshi-automation-github-key" - } - } -} - -# Fetch magictoken to use with Magic Github Proxy -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "releasetool-magictoken" - } - } -} - -# Fetch api key to use with Magic Github Proxy -before_action { - fetch_keystore { - keystore_resource { - keystore_config_id: 73713 - keyname: "magic-github-proxy-api-key" - } - } +env_vars: { + key: "SECRET_MANAGER_KEYS" + value: "releasetool-publish-reporter-app,releasetool-publish-reporter-googleapis-installation,releasetool-publish-reporter-pem" } diff --git a/.readme-partials.yaml b/.readme-partials.yaml new file mode 100644 index 000000000..0796b52e5 --- /dev/null +++ b/.readme-partials.yaml @@ -0,0 +1,122 @@ +custom_content: | + See the [Google Cloud Datastore docs][cloud-datastore-activation] for more details on how to activate + Cloud Datastore for your project. + + See the [Datastore client library docs][datastore-client-lib-docs] to learn how to interact + with the Cloud Datastore using this Client Library. + + #### Creating an authorized service object + To make authenticated requests to Google Cloud Datastore, you must create a service object with credentials. You can then make API calls by calling methods on the Datastore service object. The simplest way to authenticate is to use [Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials). These credentials are automatically inferred from your environment, so you only need the following code to create your service object: + + ```java + import com.google.cloud.datastore.Datastore; + import com.google.cloud.datastore.DatastoreOptions; + + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + ``` + + For other authentication options, see the [Authentication](https://github.com/googleapis/google-cloud-java#authentication) page. + + #### Storing data + Objects in Datastore are known as entities. Entities are grouped by "kind" and have keys for easy access. In this code snippet, we will create a new entity representing a person and store that data by the person's email. First, add the following imports at the top of your file: + + ```java + import com.google.cloud.datastore.Entity; + import com.google.cloud.datastore.Key; + import com.google.cloud.datastore.KeyFactory; + ``` + + Then add the following code to put an entity in Datastore. + + ```java + KeyFactory keyFactory = datastore.newKeyFactory().setKind("Person"); + Key key = keyFactory.newKey("john.doe@gmail.com"); + Entity entity = Entity.newBuilder(key) + .set("name", "John Doe") + .set("age", 51) + .set("favorite_food", "pizza") + .build(); + datastore.put(entity); + ``` + + Later, if you want to get this entity back, add the following to your code: + + ```java + Entity johnEntity = datastore.get(key); + ``` + + #### Running a query + In addition to retrieving entities by their keys, you can perform queries to retrieve entities by + the values of their properties. A typical query includes an entity kind, filters to select entities + with matching values, and sort orders to sequence the results. `google-cloud-datastore` supports two + types of queries: `StructuredQuery` (that allows you to construct query elements) and `GqlQuery` + (which operates using [GQL syntax](https://cloud.google.com/datastore/docs/apis/gql/gql_reference)) + in string format. In this tutorial, we will use a simple `StructuredQuery`. + + Suppose that you've added more people to Datastore, and now you want to find all people whose favorite food is pizza. Import the following: + + ```java + import com.google.cloud.datastore.Query; + import com.google.cloud.datastore.QueryResults; + import com.google.cloud.datastore.StructuredQuery; + import com.google.cloud.datastore.StructuredQuery.PropertyFilter; + ``` + + Then add the following code to your program: + + ```java + Query query = Query.newEntityQueryBuilder() + .setKind("Person") + .setFilter(PropertyFilter.eq("favorite_food", "pizza")) + .build(); + QueryResults results = datastore.run(query); + while (results.hasNext()) { + Entity currentEntity = results.next(); + System.out.println(currentEntity.getString("name") + ", you're invited to a pizza party!"); + } + ``` + + Cloud Datastore relies on indexing to run queries. Indexing is turned on by default for most types of properties. To read more about indexing, see the [Cloud Datastore Index Configuration documentation](https://cloud.google.com/datastore/docs/tools/indexconfig). + + #### Updating data + Another thing you'll probably want to do is update your data. The following snippet shows how to update a Datastore entity if it exists. + + ``` java + KeyFactory keyFactory = datastore.newKeyFactory().setKind("keyKind"); + Key key = keyFactory.newKey("keyName"); + Entity entity = datastore.get(key); + if (entity != null) { + System.out.println("Updating access_time for " + entity.getString("name")); + entity = Entity.newBuilder(entity) + .set("access_time", DateTime.now()) + .build(); + datastore.update(entity); + } + ``` + + The complete source code can be found at + [UpdateEntity.java](../../google-cloud-examples/src/main/java/com/google/cloud/examples/datastore/snippets/UpdateEntity.java). + + #### Complete source code + + In + [AddEntitiesAndRunQuery.java](../../google-cloud-examples/src/main/java/com/google/cloud/examples/datastore/snippets/AddEntitiesAndRunQuery.java) + we put together all the code to store data and run queries into one program. The program assumes that you are + running on Compute Engine or from your own desktop. To run the example on App Engine, simply move + the code from the main method to your application's servlet class and change the print statements to + display on your webpage. + + Testing + ------- + + This library has tools to help write tests for code that uses the Datastore. + + See [TESTING.md](https://github.com/googleapis/google-cloud-java/blob/master/TESTING.md#testing-code-that-uses-datastore) to read more about testing. + + Example Applications + -------------------- + - [`Bookshelf`](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/bookshelf) - An App Engine app that manages a virtual bookshelf. + - This app uses `google-cloud` to interface with Cloud Datastore and Cloud Storage. It also uses Cloud SQL, another Google Cloud Platform service. + - [`Flexible Environment/Datastore example`](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/datastore) - A simple app that uses Cloud Datastore to list the last 10 IP addresses that visited your site. + - [`SparkDemo`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/flexible/sparkjava) - An example of using `google-cloud-datastore` from within the SparkJava and App Engine Flexible Environment frameworks. + - Read about how it works on the example's [README page](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/sparkjava#how-does-it-work). diff --git a/.repo-metadata.json b/.repo-metadata.json index d1f6e9e23..188b904e2 100644 --- a/.repo-metadata.json +++ b/.repo-metadata.json @@ -2,12 +2,14 @@ "name": "datastore", "name_pretty": "Cloud Datastore", "product_documentation": "https://cloud.google.com/datastore", - "client_documentation": "https://googleapis.dev/java/google-cloud-clients/latest/index.html?com/google/cloud/asset/v1beta1/package-summary.html", + "client_documentation": "https://googleapis.dev/java/google-cloud-datastore/latest/index.html", "issue_tracker": "https://issuetracker.google.com/savedsearches/559768", "release_level": "ga", "language": "java", "repo": "googleapis/java-datastore", "repo_short": "java-datastore", "distribution_name": "com.google.cloud:google-cloud-datastore", - "api_id": "datastore.googleapis.com" + "codeowner_team": "@googleapis/firestore-dpe", + "api_id": "datastore.googleapis.com", + "api_description": "is a fully managed, schemaless database for\nstoring non-relational data. Cloud Datastore automatically scales with\nyour users and supports ACID transactions, high availability of reads and\nwrites, strong consistency for reads and ancestor queries, and eventual\nconsistency for all other queries." } diff --git a/CHANGELOG.md b/CHANGELOG.md index 925c17a3b..6e0c6283b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [1.105.0](https://www.github.com/googleapis/java-datastore/compare/v1.104.0...v1.105.0) (2020-09-01) + + +### Features + +* **deps:** adopt flatten plugin and google-cloud-shared-dependencies ([#174](https://www.github.com/googleapis/java-datastore/issues/174)) ([8618c18](https://www.github.com/googleapis/java-datastore/commit/8618c1848e71424fa164fee9d8b7b53641b6b823)) + + +### Bug Fixes + +* query result start with startCursor if specified ([#207](https://www.github.com/googleapis/java-datastore/issues/207)) ([023229a](https://www.github.com/googleapis/java-datastore/commit/023229a15edbbe773bd03410ed0784aba248ad6e)) + + +### Dependencies + +* remove direct declaration of google-auth-library-oauth2-http ([#184](https://www.github.com/googleapis/java-datastore/issues/184)) ([4fa4df4](https://www.github.com/googleapis/java-datastore/commit/4fa4df40d63d7fbce023d6231830dcc296c29dd1)) +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.2 ([#187](https://www.github.com/googleapis/java-datastore/issues/187)) ([941bea0](https://www.github.com/googleapis/java-datastore/commit/941bea016f1ce4e1c1fd027b1671f950e9c52160)) +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.3 ([#191](https://www.github.com/googleapis/java-datastore/issues/191)) ([a89eb08](https://www.github.com/googleapis/java-datastore/commit/a89eb08be1cd9689d38b8b67c472cc928e3549c1)) +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.4 ([#196](https://www.github.com/googleapis/java-datastore/issues/196)) ([7214e0a](https://www.github.com/googleapis/java-datastore/commit/7214e0ae224633e2effc023d10494e0164a8f9dc)) +* update dependency com.google.cloud:google-cloud-shared-dependencies to v0.8.6 ([#199](https://www.github.com/googleapis/java-datastore/issues/199)) ([6a959d3](https://www.github.com/googleapis/java-datastore/commit/6a959d3f7ca75ba5da1d1c4cb509593d3be39e98)) +* update dependency com.google.oauth-client:google-oauth-client to v1.31.0 ([#186](https://www.github.com/googleapis/java-datastore/issues/186)) ([16bfb9a](https://www.github.com/googleapis/java-datastore/commit/16bfb9a0127f4969a796ad95cc11cf2b8b92d0f3)) + + +### Documentation + +* libraries-bom 8.1.0 ([#200](https://www.github.com/googleapis/java-datastore/issues/200)) ([9425972](https://www.github.com/googleapis/java-datastore/commit/9425972905d1e370192eeb3bbfe837f5a7fb25cf)) +* update libraries-bom ([#211](https://www.github.com/googleapis/java-datastore/issues/211)) ([9407c4a](https://www.github.com/googleapis/java-datastore/commit/9407c4afec3de6e18c96c24872269e61c8ad40fb)) + ## [1.104.0](https://www.github.com/googleapis/java-datastore/compare/v1.103.0...v1.104.0) (2020-06-17) diff --git a/README.md b/README.md index 213eb9f9b..3ad8286e4 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,98 @@ -Google Cloud Java Client for Datastore -====================================== +# Google Cloud Datastore Client for Java -Java idiomatic client for [Google Cloud Datastore][cloud-datastore]. +Java idiomatic client for [Cloud Datastore][product-docs]. -[![Kokoro CI](http://storage.googleapis.com/cloud-devrel-public/java/badges/google-cloud-java/master.svg)](http://storage.googleapis.com/cloud-devrel-public/java/badges/google-cloud-java/master.html) -[![Maven](https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-datastore.svg)]( https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-datastore.svg) -[![Codacy Badge](https://api.codacy.com/project/badge/grade/9da006ad7c3a4fe1abd142e77c003917)](https://www.codacy.com/app/mziccard/google-cloud-java) +[![Maven][maven-version-image]][maven-version-link] +![Stability][stability-image] -- [Product Documentation][datastore-product-docs] -- [Client Library Documentation][datastore-client-lib-docs] +- [Product Documentation][product-docs] +- [Client Library Documentation][javadocs] -Quickstart ----------- -If you are using Maven with a BOM, add this to your pom.xml file. +## Quickstart + +If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file ```xml - + + + com.google.cloud + libraries-bom + 9.1.0 + pom + import + + + + + com.google.cloud - libraries-bom - 3.0.0 - pom - import - - - + google-cloud-datastore + - - com.google.cloud - google-cloud-datastore - ``` -[//]: # ({x-version-update-start:google-cloud-datastore:released}) -If you are using Maven without a BOM, add this to your dependencies. + +If you are using Maven without BOM, add this to your dependencies: + ```xml com.google.cloud google-cloud-datastore 1.104.0 + ``` + +[//]: # ({x-version-update-start:google-cloud-datastore:released}) + If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-datastore:1.104.0' +compile 'com.google.cloud:google-cloud-datastore:1.105.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "1.104.0" +libraryDependencies += "com.google.cloud" % "google-cloud-datastore" % "1.105.0" ``` [//]: # ({x-version-update-end}) -Example Applications --------------------- -- [`DatastoreExample`](../../google-cloud-examples/src/main/java/com/google/cloud/examples/datastore/DatastoreExample.java) is a simple command line interface for the Cloud Datastore. -- [`Bookshelf`](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/bookshelf) - An App Engine app that manages a virtual bookshelf. - - This app uses `google-cloud` to interface with Cloud Datastore and Cloud Storage. It also uses Cloud SQL, another Google Cloud Platform service. -- [`Flexible Environment/Datastore example`](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/datastore) - A simple app that uses Cloud Datastore to list the last 10 IP addresses that visited your site. -- [`GuestBook`](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/appengine/guestbook-cloud-datastore) - An App Engine Standard guestbook that uses Cloud Datastore. -- [`SparkDemo`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/flexible/sparkjava) - An example of using `google-cloud-datastore` from within the SparkJava and App Engine Flexible Environment frameworks. - - Read about how it works on the example's [README page](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/sparkjava#how-does-it-work). -- [`TaskList`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/datastore/src/main/java/com/google/datastore/snippets/TaskList.java) - A command line application that uses Cloud Datastore to manage a to-do list. - - Read about how to run the application on its [README page](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/datastore). +## Authentication -Authentication --------------- +See the [Authentication][authentication] section in the base directory's README. -See the [Authentication](https://github.com/googleapis/google-cloud-java#authentication) section in the base directory's README. +## Getting Started -About Google Cloud Datastore ----------------------------- +### Prerequisites -Google [Cloud Datastore][cloud-datastore] is a fully managed, schemaless database for +You will need a [Google Cloud Platform Console][developer-console] project with the Cloud Datastore [API enabled][enable-api]. + +[Follow these instructions][create-project] to get your project set up. You will also need to set up the local development environment by +[installing the Google Cloud SDK][cloud-sdk] and running the following commands in command line: +`gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`. + +### Installation and setup + +You'll need to obtain the `google-cloud-datastore` library. See the [Quickstart](#quickstart) section +to add `google-cloud-datastore` as a dependency in your code. + +## About Cloud Datastore + + +[Cloud Datastore][product-docs] is a fully managed, schemaless database for storing non-relational data. Cloud Datastore automatically scales with your users and supports ACID transactions, high availability of reads and writes, strong consistency for reads and ancestor queries, and eventual consistency for all other queries. +See the [Cloud Datastore client library docs][javadocs] to learn how to +use this Cloud Datastore Client Library. + + See the [Google Cloud Datastore docs][cloud-datastore-activation] for more details on how to activate Cloud Datastore for your project. See the [Datastore client library docs][datastore-client-lib-docs] to learn how to interact with the Cloud Datastore using this Client Library. -Getting Started ---------------- -#### Prerequisites -For this tutorial, you will need a [Google Developers Console](https://console.developers.google.com/) project with the Datastore API enabled. [Follow these instructions](https://cloud.google.com/resource-manager/docs/creating-managing-projects) to get your project set up. You will also need to set up the local development environment by [installing the Google Cloud SDK](https://cloud.google.com/sdk/) and running the following commands in command line: `gcloud auth login` and `gcloud config set project [YOUR PROJECT ID]`. - -#### Installation and setup -You'll need to obtain the `google-cloud-datastore` library. See the [Quickstart](#quickstart) section to add `google-cloud-datastore` as a dependency in your code. - #### Creating an authorized service object To make authenticated requests to Google Cloud Datastore, you must create a service object with credentials. You can then make API calls by calling methods on the Datastore service object. The simplest way to authenticate is to use [Application Default Credentials](https://developers.google.com/identity/protocols/application-default-credentials). These credentials are automatically inferred from your environment, so you only need the following code to create your service object: @@ -191,55 +194,99 @@ running on Compute Engine or from your own desktop. To run the example on App En the code from the main method to your application's servlet class and change the print statements to display on your webpage. -Troubleshooting ---------------- +Testing +------- -To get help, follow the instructions in the [shared Troubleshooting document](https://github.com/googleapis/google-cloud-common/blob/master/troubleshooting/readme.md#troubleshooting). +This library has tools to help write tests for code that uses the Datastore. -Transport ---------- -Datastore uses HTTP for the transport layer. +See [TESTING.md](https://github.com/googleapis/google-cloud-java/blob/master/TESTING.md#testing-code-that-uses-datastore) to read more about testing. -Java Versions -------------- +Example Applications +-------------------- +- [`Bookshelf`](https://github.com/GoogleCloudPlatform/getting-started-java/tree/master/bookshelf) - An App Engine app that manages a virtual bookshelf. + - This app uses `google-cloud` to interface with Cloud Datastore and Cloud Storage. It also uses Cloud SQL, another Google Cloud Platform service. +- [`Flexible Environment/Datastore example`](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/datastore) - A simple app that uses Cloud Datastore to list the last 10 IP addresses that visited your site. +- [`SparkDemo`](https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/flexible/sparkjava) - An example of using `google-cloud-datastore` from within the SparkJava and App Engine Flexible Environment frameworks. + - Read about how it works on the example's [README page](https://github.com/GoogleCloudPlatform/java-docs-samples/tree/master/flexible/sparkjava#how-does-it-work). -Java 7 or above is required for using this client. -Testing -------- -This library has tools to help write tests for code that uses the Datastore. -See [TESTING] to read more about testing. +## Samples -Versioning ----------- +Samples are in the [`samples/`](https://github.com/googleapis/java-datastore/tree/master/samples) directory. The samples' `README.md` +has instructions for running the samples. -This library follows [Semantic Versioning](http://semver.org/). +| Sample | Source Code | Try it | +| --------------------------- | --------------------------------- | ------ | +| Quickstart Sample | [source code](https://github.com/googleapis/java-datastore/blob/master/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) | +| Task List | [source code](https://github.com/googleapis/java-datastore/blob/master/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) | -It is currently in major version one (``1.y.z``), which means that the public API should be considered stable. -Contributing ------------- -Contributions to this library are always welcome and highly encouraged. +## Troubleshooting -See `google-cloud`'s [CONTRIBUTING] documentation and the [shared documentation](https://github.com/googleapis/google-cloud-common/blob/master/contributing/readme.md#how-to-contribute-to-gcloud) for more information on how to get started. +To get help, follow the instructions in the [shared Troubleshooting document][troubleshooting]. -Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. See [Code of Conduct][code-of-conduct] for more information. +## Java Versions -License -------- +Java 7 or above is required for using this client. -Apache 2.0 - See [LICENSE] for more information. +## Versioning -[CONTRIBUTING]:https://github.com/googleapis/google-cloud-java/blob/master/CONTRIBUTING.md -[code-of-conduct]:https://github.com/googleapis/google-cloud-java/blob/master/CODE_OF_CONDUCT.md#contributor-code-of-conduct -[LICENSE]: https://github.com/googleapis/google-cloud-java/blob/master/LICENSE -[TESTING]: https://github.com/googleapis/google-cloud-java/blob/master/TESTING.md#testing-code-that-uses-datastore -[cloud-platform]: https://cloud.google.com/ -[cloud-datastore-activation]: https://cloud.google.com/datastore/docs/activate -[cloud-datastore]: https://cloud.google.com/datastore/ -[datastore-product-docs]: https://cloud.google.com/datastore/docs/ -[datastore-client-lib-docs]: https://googleapis.dev/java/google-cloud-clients/latest/index.html?com/google/cloud/datastore/package-summary.html +This library follows [Semantic Versioning](http://semver.org/). + + +## Contributing + + +Contributions to this library are always welcome and highly encouraged. + +See [CONTRIBUTING][contributing] for more information how to get started. + +Please note that this project is released with a Contributor Code of Conduct. By participating in +this project you agree to abide by its terms. See [Code of Conduct][code-of-conduct] for more +information. + +## License + +Apache 2.0 - See [LICENSE][license] for more information. + +## CI Status + +Java Version | Status +------------ | ------ +Java 7 | [![Kokoro CI][kokoro-badge-image-1]][kokoro-badge-link-1] +Java 8 | [![Kokoro CI][kokoro-badge-image-2]][kokoro-badge-link-2] +Java 8 OSX | [![Kokoro CI][kokoro-badge-image-3]][kokoro-badge-link-3] +Java 8 Windows | [![Kokoro CI][kokoro-badge-image-4]][kokoro-badge-link-4] +Java 11 | [![Kokoro CI][kokoro-badge-image-5]][kokoro-badge-link-5] + +[product-docs]: https://cloud.google.com/datastore +[javadocs]: https://googleapis.dev/java/google-cloud-datastore/latest/index.html +[kokoro-badge-image-1]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java7.svg +[kokoro-badge-link-1]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java7.html +[kokoro-badge-image-2]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8.svg +[kokoro-badge-link-2]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8.html +[kokoro-badge-image-3]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8-osx.svg +[kokoro-badge-link-3]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8-osx.html +[kokoro-badge-image-4]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8-win.svg +[kokoro-badge-link-4]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java8-win.html +[kokoro-badge-image-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-datastore/java11.svg +[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-ga-green +[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-datastore.svg +[maven-version-link]: https://search.maven.org/search?q=g:com.google.cloud%20AND%20a:google-cloud-datastore&core=gav +[authentication]: https://github.com/googleapis/google-cloud-java#authentication +[developer-console]: https://console.developers.google.com/ +[create-project]: https://cloud.google.com/resource-manager/docs/creating-managing-projects +[cloud-sdk]: https://cloud.google.com/sdk/ +[troubleshooting]: https://github.com/googleapis/google-cloud-common/blob/master/troubleshooting/readme.md#troubleshooting +[contributing]: https://github.com/googleapis/java-datastore/blob/master/CONTRIBUTING.md +[code-of-conduct]: https://github.com/googleapis/java-datastore/blob/master/CODE_OF_CONDUCT.md#contributor-code-of-conduct +[license]: https://github.com/googleapis/java-datastore/blob/master/LICENSE + +[enable-api]: https://console.cloud.google.com/flows/enableapi?apiid=datastore.googleapis.com +[libraries-bom]: https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/The-Google-Cloud-Platform-Libraries-BOM +[shell_img]: https://gstatic.com/cloudssh/images/open-btn.png diff --git a/google-cloud-datastore-bom/pom.xml b/google-cloud-datastore-bom/pom.xml index 1a3b53317..cd830c0a6 100644 --- a/google-cloud-datastore-bom/pom.xml +++ b/google-cloud-datastore-bom/pom.xml @@ -3,12 +3,12 @@ 4.0.0 com.google.cloud google-cloud-datastore-bom - 1.104.0 + 1.105.0 pom com.google.cloud google-cloud-shared-config - 0.8.1 + 0.9.2 Google Cloud datastore BOM @@ -63,12 +63,12 @@ com.google.api.grpc proto-google-cloud-datastore-v1 - 0.87.0 + 0.88.0 com.google.cloud google-cloud-datastore - 1.104.0 + 1.105.0 diff --git a/google-cloud-datastore/pom.xml b/google-cloud-datastore/pom.xml index 518648f69..724ad4a00 100644 --- a/google-cloud-datastore/pom.xml +++ b/google-cloud-datastore/pom.xml @@ -2,7 +2,7 @@ 4.0.0 google-cloud-datastore - 1.104.0 + 1.105.0 jar Google Cloud Datastore https://github.com/googleapis/java-datastore @@ -12,7 +12,7 @@ com.google.cloud google-cloud-datastore-parent - 1.104.0 + 1.105.0 google-cloud-datastore diff --git a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/QueryResultsImpl.java b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/QueryResultsImpl.java index 3c8bba10a..9ed822985 100644 --- a/google-cloud-datastore/src/main/java/com/google/cloud/datastore/QueryResultsImpl.java +++ b/google-cloud-datastore/src/main/java/com/google/cloud/datastore/QueryResultsImpl.java @@ -71,10 +71,7 @@ private void sendRequest() { requestPb.setPartitionId(partitionIdPb); query.populatePb(requestPb); runQueryResponsePb = datastore.runQuery(requestPb.build()); - mostRecentQueryPb = runQueryResponsePb.getQuery(); - if (mostRecentQueryPb == null) { - mostRecentQueryPb = requestPb.getQuery(); - } + mostRecentQueryPb = requestPb.getQuery(); moreResults = runQueryResponsePb.getBatch().getMoreResults(); lastBatch = moreResults != MoreResultsType.NOT_FINISHED; entityResultPbIter = runQueryResponsePb.getBatch().getEntityResultsList().iterator(); diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/ITDatastoreTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/ITDatastoreTest.java index 442a6eb72..5a3bc7e00 100644 --- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/ITDatastoreTest.java +++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/ITDatastoreTest.java @@ -1242,4 +1242,25 @@ public void testGqlQueryWithNullBinding() { } assertEquals(1, count); } + + @Test + public void testQueryWithStartCursor() { + Entity entity1 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-01").build()).build(); + Entity entity2 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-02").build()).build(); + Entity entity3 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-03").build()).build(); + datastore.put(entity1, entity2, entity3); + QueryResults run1 = datastore.run(Query.newEntityQueryBuilder().setKind(KIND1).build()); + run1.next(); + Cursor cursor1 = run1.getCursorAfter(); + assertNotNull(cursor1); + QueryResults run2 = + datastore.run(Query.newEntityQueryBuilder().setKind(KIND1).setStartCursor(cursor1).build()); + Cursor cursor2 = run2.getCursorAfter(); + assertNotNull(cursor2); + assertEquals(cursor2, cursor1); + datastore.delete(entity1.getKey(), entity2.getKey(), entity3.getKey()); + } } diff --git a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreTest.java b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreTest.java index 7e7fec35f..3db8cfe3e 100644 --- a/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreTest.java +++ b/google-cloud-datastore/src/test/java/com/google/cloud/datastore/it/ITDatastoreTest.java @@ -28,6 +28,7 @@ import com.google.cloud.Timestamp; import com.google.cloud.datastore.Batch; import com.google.cloud.datastore.BooleanValue; +import com.google.cloud.datastore.Cursor; import com.google.cloud.datastore.Datastore; import com.google.cloud.datastore.DatastoreException; import com.google.cloud.datastore.DatastoreOptions; @@ -898,4 +899,25 @@ public void testGqlQueryWithNullBinding() { assertEquals(ENTITY1, results.next()); assertFalse(results.hasNext()); } + + @Test + public void testQueryWithStartCursor() { + Entity entity1 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-01").build()).build(); + Entity entity2 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-02").build()).build(); + Entity entity3 = + Entity.newBuilder(Key.newBuilder(PROJECT_ID, KIND1, "name-03").build()).build(); + DATASTORE.put(entity1, entity2, entity3); + QueryResults run1 = DATASTORE.run(Query.newEntityQueryBuilder().setKind(KIND1).build()); + run1.next(); + Cursor cursor1 = run1.getCursorAfter(); + assertNotNull(cursor1); + QueryResults run2 = + DATASTORE.run(Query.newEntityQueryBuilder().setKind(KIND1).setStartCursor(cursor1).build()); + Cursor cursor2 = run2.getCursorAfter(); + assertNotNull(cursor2); + assertEquals(cursor2, cursor1); + DATASTORE.delete(entity1.getKey(), entity2.getKey(), entity3.getKey()); + } } diff --git a/pom.xml b/pom.xml index 72bbbc0ee..c06a6c2f2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.google.cloud google-cloud-datastore-parent pom - 1.104.0 + 1.105.0 Google Cloud Datastore Parent https://github.com/googleapis/java-datastore @@ -14,7 +14,7 @@ com.google.cloud google-cloud-shared-config - 0.8.1 + 0.9.2 @@ -152,7 +152,6 @@ github google-cloud-datastore-parent https://googleapis.dev/java/google-api-grpc/latest - 1.3.2 @@ -160,7 +159,7 @@ com.google.cloud google-cloud-shared-dependencies - 0.8.1 + 0.8.6 pom import @@ -168,7 +167,7 @@ com.google.api.grpc proto-google-cloud-datastore-v1 - 0.87.0 + 0.88.0 com.google.cloud.datastore @@ -181,15 +180,10 @@ - - com.google.auth - google-auth-library-oauth2-http - 0.20.0 - com.google.oauth-client google-oauth-client - 1.30.6 + 1.31.0 @@ -217,6 +211,7 @@ com.google.http-client:google-http-client-jackson2 com.google.oauth-client:google-oauth-client + javax.annotation:javax.annotation-api diff --git a/proto-google-cloud-datastore-v1/pom.xml b/proto-google-cloud-datastore-v1/pom.xml index de0b88bc0..d5d7dcd2f 100644 --- a/proto-google-cloud-datastore-v1/pom.xml +++ b/proto-google-cloud-datastore-v1/pom.xml @@ -4,13 +4,13 @@ 4.0.0 com.google.api.grpc proto-google-cloud-datastore-v1 - 0.87.0 + 0.88.0 proto-google-cloud-datastore-v1 PROTO library for proto-google-cloud-datastore-v1 com.google.cloud google-cloud-datastore-parent - 1.104.0 + 1.105.0 @@ -44,7 +44,6 @@ javax.annotation javax.annotation-api - ${javax.annotations.version} diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml index 749f5d3f5..5303163b8 100644 --- a/samples/install-without-bom/pom.xml +++ b/samples/install-without-bom/pom.xml @@ -29,7 +29,7 @@ com.google.cloud google-cloud-datastore - 1.103.0 + 1.104.0 @@ -53,7 +53,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.1.0 + 3.2.0 add-snippets-source diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml index 2e5e1d8d2..ced7beed0 100644 --- a/samples/snapshot/pom.xml +++ b/samples/snapshot/pom.xml @@ -28,7 +28,7 @@ com.google.cloud google-cloud-datastore - 1.103.0 + 1.104.0 @@ -52,7 +52,7 @@ org.codehaus.mojo build-helper-maven-plugin - 3.1.0 + 3.2.0 add-snippets-source diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml index f4cc04008..1995442a2 100644 --- a/samples/snippets/pom.xml +++ b/samples/snippets/pom.xml @@ -30,7 +30,7 @@ com.google.cloud libraries-bom - 7.0.0 + 9.1.0 pom import diff --git a/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java b/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java new file mode 100644 index 000000000..ba1a67706 --- /dev/null +++ b/samples/snippets/src/main/java/com/example/datastore/QuickstartSample.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 Google 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.example.datastore; + +// [START datastore_quickstart] +// Imports the Google Cloud client library +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.Key; + +public class QuickstartSample { + public static void main(String... args) throws Exception { + // Instantiates a client + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // The kind for the new entity + String kind = "Task"; + // The name/ID for the new entity + String name = "sampletask1"; + // The Cloud Datastore key for the new entity + Key taskKey = datastore.newKeyFactory().setKind(kind).newKey(name); + + // Prepares the new entity + Entity task = Entity.newBuilder(taskKey) + .set("description", "Buy milk") + .build(); + + // Saves the entity + datastore.put(task); + + System.out.printf("Saved %s: %s%n", task.getKey().getName(), task.getString("description")); + + //Retrieve entity + Entity retrieved = datastore.get(taskKey); + + System.out.printf("Retrieved %s: %s%n", taskKey.getName(), retrieved.getString("description")); + + } +} +// [END datastore_quickstart] diff --git a/samples/snippets/src/main/java/com/google/datastore/snippets/TaskList.java b/samples/snippets/src/main/java/com/google/datastore/snippets/TaskList.java new file mode 100644 index 000000000..3f035d3e3 --- /dev/null +++ b/samples/snippets/src/main/java/com/google/datastore/snippets/TaskList.java @@ -0,0 +1,234 @@ +/* + * Copyright 2016 Google 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.google.datastore.snippets; + +import com.google.cloud.Timestamp; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreOptions; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.KeyFactory; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.StringValue; +import com.google.cloud.datastore.StructuredQuery.OrderBy; +import com.google.cloud.datastore.Transaction; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * A simple Task List application demonstrating how to connect to Cloud Datastore, create, modify, + * delete, and query entities. + */ +public class TaskList { + + // [START datastore_build_service] + // Create an authorized Datastore service using Application Default Credentials. + private final Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + + // Create a Key factory to construct keys associated with this project. + private final KeyFactory keyFactory = datastore.newKeyFactory().setKind("Task"); + // [END datastore_build_service] + + // [START datastore_add_entity] + /** + * Adds a task entity to the Datastore. + * + * @param description The task description + * @return The {@link Key} of the entity + * @throws DatastoreException if the ID allocation or put fails + */ + Key addTask(String description) { + Key key = datastore.allocateId(keyFactory.newKey()); + Entity task = Entity.newBuilder(key) + .set("description", StringValue.newBuilder(description).setExcludeFromIndexes(true).build()) + .set("created", Timestamp.now()) + .set("done", false) + .build(); + datastore.put(task); + return key; + } + // [END datastore_add_entity] + + // [START datastore_update_entity] + /** + * Marks a task entity as done. + * + * @param id The ID of the task entity as given by {@link Key#id()} + * @return true if the task was found, false if not + * @throws DatastoreException if the transaction fails + */ + boolean markDone(long id) { + Transaction transaction = datastore.newTransaction(); + try { + Entity task = transaction.get(keyFactory.newKey(id)); + if (task != null) { + transaction.put(Entity.newBuilder(task).set("done", true).build()); + } + transaction.commit(); + return task != null; + } finally { + if (transaction.isActive()) { + transaction.rollback(); + } + } + } + // [END datastore_update_entity] + + // [START datastore_retrieve_entities] + /** + * Returns a list of all task entities in ascending order of creation time. + * + * @throws DatastoreException if the query fails + */ + Iterator listTasks() { + Query query = + Query.newEntityQueryBuilder().setKind("Task").setOrderBy(OrderBy.asc("created")).build(); + return datastore.run(query); + } + // [END datastore_retrieve_entities] + + // [START datastore_delete_entity] + /** + * Deletes a task entity. + * + * @param id The ID of the task entity as given by {@link Key#id()} + * @throws DatastoreException if the delete fails + */ + void deleteTask(long id) { + datastore.delete(keyFactory.newKey(id)); + } + // [END datastore_delete_entity] + + /** + * Converts a list of task entities to a list of formatted task strings. + * + * @param tasks An iterator over task entities + * @return A list of tasks strings, one per entity + */ + static List formatTasks(Iterator tasks) { + List strings = new ArrayList<>(); + while (tasks.hasNext()) { + Entity task = tasks.next(); + if (task.getBoolean("done")) { + strings.add( + String.format("%d : %s (done)", task.getKey().getId(), task.getString("description"))); + } else { + strings.add(String.format("%d : %s (created %s)", task.getKey().getId(), + task.getString("description"), task.getTimestamp("created"))); + } + } + return strings; + } + + /** + * Handles a single command. + * + * @param commandLine A line of input provided by the user + */ + void handleCommandLine(String commandLine) { + String[] args = commandLine.split("\\s+"); + + if (args.length < 1) { + throw new IllegalArgumentException("not enough args"); + } + + String command = args[0]; + switch (command) { + case "new": + // Everything after the first whitespace token is interpreted to be the description. + args = commandLine.split("\\s+", 2); + if (args.length != 2) { + throw new IllegalArgumentException("missing description"); + } + // Set created to now() and done to false. + addTask(args[1]); + System.out.println("task added"); + break; + case "done": + assertArgsLength(args, 2); + long id = Long.parseLong(args[1]); + if (markDone(id)) { + System.out.println("task marked done"); + } else { + System.out.printf("did not find a Task entity with ID %d%n", id); + } + break; + case "list": + assertArgsLength(args, 1); + List tasks = formatTasks(listTasks()); + System.out.printf("found %d tasks:%n", tasks.size()); + System.out.println("task ID : description"); + System.out.println("---------------------"); + for (String taskString : tasks) { + System.out.println(taskString); + } + break; + case "delete": + assertArgsLength(args, 2); + deleteTask(Long.parseLong(args[1])); + System.out.println("task deleted (if it existed)"); + break; + default: + throw new IllegalArgumentException("unrecognized command: " + command); + } + } + + private void assertArgsLength(String[] args, int expectedLength) { + if (args.length != expectedLength) { + throw new IllegalArgumentException( + String.format("expected exactly %d arg(s), found %d", expectedLength, args.length)); + } + } + + /** + * Exercises the methods defined in this class. + * + *

Assumes that you are authenticated using the Google Cloud SDK (using + * {@code gcloud auth application-default login}). + */ + public static void main(String[] args) throws Exception { + TaskList taskList = new TaskList(); + System.out.println("Cloud Datastore Task List"); + System.out.println(); + printUsage(); + while (true) { + String commandLine = System.console().readLine("> "); + if (commandLine.trim().isEmpty()) { + break; + } + try { + taskList.handleCommandLine(commandLine); + } catch (IllegalArgumentException e) { + System.out.println(e.getMessage()); + printUsage(); + } + } + System.out.println("exiting"); + System.exit(0); + } + + private static void printUsage() { + System.out.println("Usage:"); + System.out.println(); + System.out.println(" new Adds a task with a description "); + System.out.println(" done Marks a task as done"); + System.out.println(" list Lists all tasks by creation time"); + System.out.println(" delete Deletes a task"); + System.out.println(); + } +} diff --git a/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java b/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java new file mode 100644 index 000000000..6bb2dfe30 --- /dev/null +++ b/samples/snippets/src/test/java/com/example/datastore/QuickstartSampleIT.java @@ -0,0 +1,71 @@ +/* + * Copyright 2016 Google 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.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 org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for quickstart sample. + */ +@RunWith(JUnit4.class) +@SuppressWarnings("checkstyle:abbreviationaswordinname") +public class QuickstartSampleIT { + private ByteArrayOutputStream bout; + private PrintStream out; + + private static final void deleteTestEntity() { + Datastore datastore = DatastoreOptions.getDefaultInstance().getService(); + String kind = "Task"; + String name = "sampletask1"; + Key taskKey = datastore.newKeyFactory().setKind(kind).newKey(name); + datastore.delete(taskKey); + } + + @Before + public void setUp() { + deleteTestEntity(); + + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + System.setOut(out); + } + + @After + public void tearDown() { + System.setOut(null); + deleteTestEntity(); + } + + @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"); + } +} diff --git a/samples/snippets/src/test/java/com/google/datastore/snippets/ConceptsTest.java b/samples/snippets/src/test/java/com/google/datastore/snippets/ConceptsTest.java new file mode 100644 index 000000000..92500ddf9 --- /dev/null +++ b/samples/snippets/src/test/java/com/google/datastore/snippets/ConceptsTest.java @@ -0,0 +1,985 @@ +/* + * Copyright 2016 Google 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.google.datastore.snippets; + +import static java.util.Calendar.DECEMBER; +import static java.util.Calendar.JANUARY; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import com.google.cloud.Timestamp; +import com.google.cloud.datastore.Cursor; +import com.google.cloud.datastore.Datastore; +import com.google.cloud.datastore.DatastoreException; +import com.google.cloud.datastore.Entity; +import com.google.cloud.datastore.EntityQuery; +import com.google.cloud.datastore.FullEntity; +import com.google.cloud.datastore.IncompleteKey; +import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.KeyFactory; +import com.google.cloud.datastore.ListValue; +import com.google.cloud.datastore.PathElement; +import com.google.cloud.datastore.ProjectionEntity; +import com.google.cloud.datastore.Query; +import com.google.cloud.datastore.QueryResults; +import com.google.cloud.datastore.ReadOption; +import com.google.cloud.datastore.StringValue; +import com.google.cloud.datastore.StructuredQuery; +import com.google.cloud.datastore.StructuredQuery.CompositeFilter; +import com.google.cloud.datastore.StructuredQuery.OrderBy; +import com.google.cloud.datastore.StructuredQuery.PropertyFilter; +import com.google.cloud.datastore.Transaction; +import com.google.cloud.datastore.testing.LocalDatastoreHelper; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterators; +import com.google.datastore.v1.TransactionOptions; +import com.google.datastore.v1.TransactionOptions.ReadOnly; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.TimeoutException; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.threeten.bp.Duration; + +/** + * Contains Cloud Datastore snippets demonstrating concepts for documentation. + */ +@RunWith(JUnit4.class) +public class ConceptsTest { + + private static final LocalDatastoreHelper HELPER = LocalDatastoreHelper.create(1.0); + private static final FullEntity TEST_FULL_ENTITY = FullEntity.newBuilder().build(); + + private Datastore datastore; + private KeyFactory keyFactory; + private Key taskKey; + private Entity testEntity; + private Timestamp startDate; + private Timestamp endDate; + private Timestamp includedDate; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * Starts the local Datastore emulator. + * + * @throws IOException if there are errors starting the local Datastore + * @throws InterruptedException if there are errors starting the local Datastore + */ + @BeforeClass + public static void beforeClass() throws IOException, InterruptedException { + HELPER.start(); + } + + /** + * Initializes Datastore and cleans out any residual values. Also initializes global variables + * used for testing. + */ + @Before + public void setUp() { + datastore = HELPER.getOptions().toBuilder().setNamespace("ghijklmnop").build().getService(); + StructuredQuery query = Query.newKeyQueryBuilder().build(); + QueryResults result = datastore.run(query); + datastore.delete(Iterators.toArray(result, Key.class)); + keyFactory = datastore.newKeyFactory().setKind("Task"); + taskKey = keyFactory.newKey("some-arbitrary-key"); + testEntity = Entity.newBuilder(taskKey, TEST_FULL_ENTITY).build(); + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + calendar.set(1990, JANUARY, 1); + startDate = Timestamp.of(calendar.getTime()); + calendar.set(2000, JANUARY, 1); + endDate = Timestamp.of(calendar.getTime()); + calendar.set(1999, DECEMBER, 31); + includedDate = Timestamp.of(calendar.getTime()); + } + + /** + * Stops the local Datastore emulator. + * + * @throws IOException if there are errors stopping the local Datastore + * @throws InterruptedException if there are errors stopping the local Datastore + */ + @AfterClass + public static void afterClass() throws IOException, InterruptedException, TimeoutException { + HELPER.stop(Duration.ofMinutes(1)); + } + + private void assertValidKey(Key taskKey) { + datastore.put(Entity.newBuilder(taskKey, TEST_FULL_ENTITY).build()); + } + + @Test + public void testIncompleteKey() { + // [START datastore_incomplete_key] + KeyFactory keyFactory = datastore.newKeyFactory().setKind("Task"); + Key taskKey = datastore.allocateId(keyFactory.newKey()); + // [END datastore_incomplete_key] + assertValidKey(taskKey); + } + + @Test + public void testNamedKey() { + // [START datastore_named_key] + Key taskKey = datastore.newKeyFactory().setKind("Task").newKey("sampleTask"); + // [END datastore_named_key] + assertValidKey(taskKey); + } + + @Test + public void testKeyWithParent() { + // [START datastore_key_with_parent] + Key taskKey = datastore.newKeyFactory() + .addAncestors(PathElement.of("TaskList", "default")) + .setKind("Task") + .newKey("sampleTask"); + // [END datastore_key_with_parent] + assertValidKey(taskKey); + } + + @Test + public void testKeyWithMultilevelParent() { + // [START datastore_key_with_multilevel_parent] + KeyFactory keyFactory = datastore.newKeyFactory() + .addAncestors(PathElement.of("User", "Alice"), PathElement.of("TaskList", "default")) + .setKind("Task"); + Key taskKey = keyFactory.newKey("sampleTask"); + // [END datastore_key_with_multilevel_parent] + assertValidKey(taskKey); + } + + private void assertValidEntity(Entity original) { + datastore.put(original); + assertEquals(original, datastore.get(original.getKey())); + } + + @Test + public void testEntityWithParent() { + // [START datastore_entity_with_parent] + Key taskKey = datastore.newKeyFactory() + .addAncestors(PathElement.of("TaskList", "default")) + .setKind("Task") + .newKey("sampleTask"); + Entity task = Entity.newBuilder(taskKey) + .set("category", "Personal") + .set("done", false) + .set("priority", 4) + .set("description", "Learn Cloud Datastore") + .build(); + // [END datastore_entity_with_parent] + assertValidEntity(task); + } + + @Test + public void testProperties() { + // [START datastore_properties] + Entity task = Entity.newBuilder(taskKey) + .set("category", "Personal") + .set("created", Timestamp.now()) + .set("done", false) + .set("priority", 4) + .set("percent_complete", 10.0) + .set("description", + StringValue.newBuilder("Learn Cloud Datastore").setExcludeFromIndexes(true).build()) + .build(); + // [END datastore_properties] + assertValidEntity(task); + } + + @Test + public void testArrayValue() { + // [START datastore_array_value] + Entity task = Entity.newBuilder(taskKey) + .set("tags", "fun", "programming") + .set("collaborators", ListValue.of("alice", "bob")) + .build(); + // [END datastore_array_value] + assertValidEntity(task); + } + + @Test + public void testBasicEntity() { + // [START datastore_basic_entity] + Key taskKey = datastore.newKeyFactory() + .setKind("Task") + .newKey("sampleTask"); + Entity task = Entity.newBuilder(taskKey) + .set("category", "Personal") + .set("done", false) + .set("priority", 4) + .set("description", "Learn Cloud Datastore") + .build(); + // [END datastore_basic_entity] + assertValidEntity(task); + } + + @Test + public void testUpsert() { + // [START datastore_upsert] + Entity task = Entity.newBuilder(keyFactory.newKey("sampleTask")).build(); + datastore.put(task); + // [END datastore_upsert] + assertEquals(task, datastore.get(task.getKey())); + } + + @Test + public void testInsert() { + // [START datastore_insert] + Key taskKey = datastore.add(FullEntity.newBuilder(keyFactory.newKey()).build()).getKey(); + // [END datastore_insert] + assertEquals(FullEntity.newBuilder(taskKey).build(), datastore.get(taskKey)); + } + + @Test + public void testLookup() { + datastore.put(testEntity); + // [START datastore_lookup] + Entity task = datastore.get(taskKey); + // [END datastore_lookup] + assertEquals(testEntity, task); + } + + @Test + public void testUpdate() { + datastore.put(testEntity); + // [START datastore_update] + Entity task = Entity.newBuilder(datastore.get(taskKey)).set("priority", 5).build(); + datastore.update(task); + // [END datastore_update] + assertEquals(task, datastore.get(taskKey)); + } + + @Test + public void testDelete() { + datastore.put(testEntity); + // [START datastore_delete] + datastore.delete(taskKey); + // [END datastore_delete] + assertNull(datastore.get(taskKey)); + } + + private List setUpBatchTests(Key taskKey1, Key taskKey2) { + Entity task1 = Entity.newBuilder(taskKey1) + .set("category", "Personal") + .set("done", false) + .set("priority", 4) + .set("description", "Learn Cloud Datastore") + .build(); + Entity task2 = Entity.newBuilder(taskKey2) + .set("category", "Personal") + .set("done", false) + .set("priority", 5) + .set("description", "Integrate Cloud Datastore") + .build(); + datastore.put(task1, task2); + return ImmutableList.of(task1, task2); + } + + @Test + public void testBatchUpsert() { + // [START datastore_batch_upsert] + FullEntity task1 = FullEntity.newBuilder(keyFactory.newKey()) + .set("category", "Personal") + .set("done", false) + .set("priority", 4) + .set("description", "Learn Cloud Datastore") + .build(); + FullEntity task2 = Entity.newBuilder(keyFactory.newKey()) + .set("category", "Personal") + .set("done", false) + .set("priority", 5) + .set("description", "Integrate Cloud Datastore") + .build(); + List tasks = datastore.add(task1, task2); + Key taskKey1 = tasks.get(0).getKey(); + Key taskKey2 = tasks.get(1).getKey(); + // [END datastore_batch_upsert] + assertEquals(Entity.newBuilder(taskKey1, task1).build(), datastore.get(taskKey1)); + assertEquals(Entity.newBuilder(taskKey2, task2).build(), datastore.get(taskKey2)); + } + + @Test + public void testBatchLookup() { + Key taskKey1 = keyFactory.newKey(1); + Key taskKey2 = keyFactory.newKey(2); + List expectedTasks = setUpBatchTests(taskKey1, taskKey2); + // [START datastore_batch_lookup] + Iterator tasks = datastore.get(taskKey1, taskKey2); + // [END datastore_batch_lookup] + assertEquals(expectedTasks.get(0), tasks.next()); + assertEquals(expectedTasks.get(1), tasks.next()); + } + + @Test + public void testBatchDelete() { + Key taskKey1 = keyFactory.newKey(1); + Key taskKey2 = keyFactory.newKey(2); + setUpBatchTests(taskKey1, taskKey2); + // [START datastore_batch_delete] + datastore.delete(taskKey1, taskKey2); + // [END datastore_batch_delete] + assertNull(datastore.get(taskKey1)); + assertNull(datastore.get(taskKey2)); + } + + private void setUpQueryTests() { + Key taskKey = datastore.newKeyFactory() + .setKind("Task") + .addAncestors(PathElement.of("TaskList", "default")) + .newKey("someTask"); + datastore.put(Entity.newBuilder(taskKey) + .set("category", "Personal") + .set("done", false) + .set("completed", false) + .set("priority", 4) + .set("created", includedDate) + .set("percent_complete", 10.0) + .set("description", + StringValue.newBuilder("Learn Cloud Datastore").setExcludeFromIndexes(true).build()) + .set("tag", "fun", "l", "programming") + .build()); + } + + private V assertValidQuery(Query query) { + QueryResults results = datastore.run(query); + V result = results.next(); + assertFalse(results.hasNext()); + return result; + } + + private void assertInvalidQuery(Query query) { + thrown.expect(DatastoreException.class); + datastore.run(query); + } + + @Test + public void testBasicQuery() { + setUpQueryTests(); + // [START datastore_basic_query] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and( + PropertyFilter.eq("done", false), PropertyFilter.ge("priority", 4))) + .setOrderBy(OrderBy.desc("priority")) + .build(); + // [END datastore_basic_query] + assertValidQuery(query); + } + + @Test + public void testRunQuery() { + setUpQueryTests(); + Query query = Query.newEntityQueryBuilder().setKind("Task").build(); + // [START datastore_run_query] + QueryResults tasks = datastore.run(query); + // [END datastore_run_query] + assertNotNull(tasks.next()); + assertFalse(tasks.hasNext()); + } + + @Test + public void testPropertyFilter() { + setUpQueryTests(); + // [START datastore_property_filter] + Query query = + Query.newEntityQueryBuilder().setKind("Task").setFilter(PropertyFilter.eq("done", false)) + .build(); + // [END datastore_property_filter] + assertValidQuery(query); + } + + @Test + public void testCompositeFilter() { + setUpQueryTests(); + // [START datastore_composite_filter] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter( + CompositeFilter.and(PropertyFilter.eq("done", false), PropertyFilter.eq("priority", 4))) + .build(); + // [END datastore_composite_filter] + assertValidQuery(query); + } + + @Test + public void testKeyFilter() { + setUpQueryTests(); + // [START datastore_key_filter] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.gt("__key__", keyFactory.newKey("someTask"))) + .build(); + // [END datastore_key_filter] + assertValidQuery(query); + } + + @Test + public void testAscendingSort() { + setUpQueryTests(); + // [START datastore_ascending_sort] + Query query = + Query.newEntityQueryBuilder().setKind("Task").setOrderBy(OrderBy.asc("created")).build(); + // [END datastore_ascending_sort] + assertValidQuery(query); + } + + @Test + public void testDescendingSort() { + setUpQueryTests(); + // [START datastore_descending_sort] + Query query = + Query.newEntityQueryBuilder().setKind("Task").setOrderBy(OrderBy.desc("created")).build(); + // [END datastore_descending_sort] + assertValidQuery(query); + } + + @Test + public void testMultiSort() { + setUpQueryTests(); + // [START datastore_multi_sort] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setOrderBy(OrderBy.desc("priority"), OrderBy.asc("created")) + .build(); + // [END datastore_multi_sort] + assertValidQuery(query); + } + + @Test + public void testKindlessQuery() { + Key lastSeenKey = keyFactory.newKey("a"); + setUpQueryTests(); + // [START datastore_kindless_query] + Query query = + Query.newEntityQueryBuilder().setFilter(PropertyFilter.gt("__key__", lastSeenKey)).build(); + // [END datastore_kindless_query] + assertValidQuery(query); + } + + @Test + public void testAncestorQuery() { + setUpQueryTests(); + // [START datastore_ancestor_query] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.hasAncestor( + datastore.newKeyFactory().setKind("TaskList").newKey("default"))) + .build(); + // [END datastore_ancestor_query] + assertValidQuery(query); + } + + @Test + public void testProjectionQuery() { + setUpQueryTests(); + // [START datastore_projection_query] + Query query = Query.newProjectionEntityQueryBuilder() + .setKind("Task") + .setProjection("priority", "percent_complete") + .build(); + // [END datastore_projection_query] + assertValidQuery(query); + } + + @Test + public void testRunProjectionQuery() { + setUpQueryTests(); + Query query = Query.newProjectionEntityQueryBuilder() + .setKind("Task") + .setProjection("priority", "percent_complete") + .build(); + // [START datastore_run_query_projection] + List priorities = new LinkedList<>(); + List percentCompletes = new LinkedList<>(); + QueryResults tasks = datastore.run(query); + while (tasks.hasNext()) { + ProjectionEntity task = tasks.next(); + priorities.add(task.getLong("priority")); + percentCompletes.add(task.getDouble("percent_complete")); + } + // [END datastore_run_query_projection] + assertEquals(ImmutableList.of(4L), priorities); + assertEquals(ImmutableList.of(10.0), percentCompletes); + } + + @Test + public void testKeysOnlyQuery() { + setUpQueryTests(); + // [START datastore_keys_only_query] + Query query = Query.newKeyQueryBuilder().setKind("Task").build(); + // [END datastore_keys_only_query] + assertValidQuery(query); + } + + @Test + public void testDistinctOnQuery() { + setUpQueryTests(); + // [START datastore_distinct_on_query] + Query query = Query.newProjectionEntityQueryBuilder() + .setKind("Task") + .setProjection("category", "priority") + .setDistinctOn("category") + .setOrderBy(OrderBy.asc("category"), OrderBy.asc("priority")) + .build(); + // [END datastore_distinct_on_query] + assertValidQuery(query); + } + + @Test + public void testArrayValueInequalityRange() { + setUpQueryTests(); + // [START datastore_array_value_inequality_range] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and( + PropertyFilter.gt("tag", "learn"), PropertyFilter.lt("tag", "math"))) + .build(); + // [END datastore_array_value_inequality_range] + QueryResults results = datastore.run(query); + assertFalse(results.hasNext()); + } + + @Test + public void testArrayValueEquality() { + setUpQueryTests(); + // [START datastore_array_value_equality] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and( + PropertyFilter.eq("tag", "fun"), PropertyFilter.eq("tag", "programming"))) + .build(); + // [END datastore_array_value_equality] + assertValidQuery(query); + } + + @Test + public void testInequalityRange() { + setUpQueryTests(); + // [START datastore_inequality_range] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and( + PropertyFilter.gt("created", startDate), PropertyFilter.lt("created", endDate))) + .build(); + // [END datastore_inequality_range] + assertValidQuery(query); + } + + @Test + public void testInequalityInvalid() { + // [START datastore_inequality_invalid] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and( + PropertyFilter.gt("created", startDate), PropertyFilter.gt("priority", 3))) + .build(); + // [END datastore_inequality_invalid] + assertInvalidQuery(query); + } + + @Test + public void testEqualAndInequalityRange() { + setUpQueryTests(); + // [START datastore_equal_and_inequality_range] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(CompositeFilter.and(PropertyFilter.eq("priority", 4), + PropertyFilter.gt("created", startDate), PropertyFilter.lt("created", endDate))) + .build(); + // [END datastore_equal_and_inequality_range] + assertValidQuery(query); + } + + @Test + public void testInequalitySort() { + setUpQueryTests(); + // [START datastore_inequality_sort] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.gt("priority", 3)) + .setOrderBy(OrderBy.asc("priority"), OrderBy.asc("created")) + .build(); + // [END datastore_inequality_sort] + assertValidQuery(query); + } + + @Test + public void testInequalitySortInvalidNotSame() { + // [START datastore_inequality_sort_invalid_not_same] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.gt("priority", 3)) + .setOrderBy(OrderBy.asc("created")) + .build(); + // [END datastore_inequality_sort_invalid_not_same] + assertInvalidQuery(query); + } + + @Test + public void testInequalitySortInvalidNotFirst() { + // [START datastore_inequality_sort_invalid_not_first] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.gt("priority", 3)) + .setOrderBy(OrderBy.asc("created"), OrderBy.asc("priority")) + .build(); + // [END datastore_inequality_sort_invalid_not_first] + assertInvalidQuery(query); + } + + @Test + public void testLimit() { + setUpQueryTests(); + // [START datastore_limit] + Query query = Query.newEntityQueryBuilder().setKind("Task").setLimit(5).build(); + // [END datastore_limit] + assertValidQuery(query); + } + + @Test + public void testCursorPaging() { + setUpQueryTests(); + datastore.put(testEntity); + Cursor nextPageCursor = cursorPaging(1, null); + assertNotNull(nextPageCursor); + nextPageCursor = cursorPaging(1, nextPageCursor); + assertNotNull(nextPageCursor); + } + + private Cursor cursorPaging(int pageSize, Cursor pageCursor) { + // [START datastore_cursor_paging] + EntityQuery.Builder queryBuilder = Query.newEntityQueryBuilder().setKind("Task") + .setLimit(pageSize); + if (pageCursor != null) { + queryBuilder.setStartCursor(pageCursor); + } + QueryResults tasks = datastore.run(queryBuilder.build()); + while (tasks.hasNext()) { + Entity task = tasks.next(); + // do something with the task + } + Cursor nextPageCursor = tasks.getCursorAfter(); + // [END datastore_cursor_paging] + return nextPageCursor; + } + + @Test + public void testEventualConsistentQuery() { + setUpQueryTests(); + // [START datastore_eventual_consistent_query] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.hasAncestor( + datastore.newKeyFactory().setKind("TaskList").newKey("default"))) + .build(); + datastore.run(query, ReadOption.eventualConsistency()); + // [END datastore_eventual_consistent_query] + assertValidQuery(query); + } + + @Test + public void testUnindexedPropertyQuery() { + setUpQueryTests(); + // [START datastore_unindexed_property_query] + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.eq("description", "A task description")) + .build(); + // [END datastore_unindexed_property_query] + QueryResults results = datastore.run(query); + assertFalse(results.hasNext()); + } + + @Test + public void testExplodingProperties() { + // [START datastore_exploding_properties] + Entity task = Entity.newBuilder(taskKey) + .set("tags", "fun", "programming", "learn") + .set("collaborators", "alice", "bob", "charlie") + .set("created", Timestamp.now()) + .build(); + // [END datastore_exploding_properties] + assertValidEntity(task); + } + + private List setUpTransferTests() { + KeyFactory keyFactory = datastore.newKeyFactory().setKind("People"); + Key from = keyFactory.newKey("from"); + Key to = keyFactory.newKey("to"); + datastore.put(Entity.newBuilder(from).set("balance", 100).build()); + datastore.put(Entity.newBuilder(to).set("balance", 0).build()); + return ImmutableList.of(from, to); + } + + private void assertSuccessfulTransfer(Key from, Key to) { + assertEquals(90, datastore.get(from).getLong("balance")); + assertEquals(10, datastore.get(to).getLong("balance")); + } + + @Test + public void testTransactionalUpdate() { + List keys = setUpTransferTests(); + transferFunds(keys.get(0), keys.get(1), 10); + assertSuccessfulTransfer(keys.get(0), keys.get(1)); + } + + // [START datastore_transactional_update] + void transferFunds(Key fromKey, Key toKey, long amount) { + Transaction txn = datastore.newTransaction(); + try { + List entities = txn.fetch(fromKey, toKey); + Entity from = entities.get(0); + Entity updatedFrom = + Entity.newBuilder(from).set("balance", from.getLong("balance") - amount).build(); + Entity to = entities.get(1); + Entity updatedTo = Entity.newBuilder(to).set("balance", to.getLong("balance") + amount) + .build(); + txn.put(updatedFrom, updatedTo); + txn.commit(); + } finally { + if (txn.isActive()) { + txn.rollback(); + } + } + } + // [END datastore_transactional_update] + + @Test + public void testTransactionalRetry() { + List keys = setUpTransferTests(); + Key fromKey = keys.get(0); + Key toKey = keys.get(1); + // [START datastore_transactional_retry] + int retries = 5; + while (true) { + try { + transferFunds(fromKey, toKey, 10); + break; + } catch (DatastoreException e) { + if (retries == 0) { + throw e; + } + --retries; + } + } + // Retry handling can also be configured and automatically applied using google-cloud-java. + // [END datastore_transactional_retry] + assertSuccessfulTransfer(keys.get(0), keys.get(1)); + } + + @Test + public void testTransactionalGetOrCreate() { + // [START datastore_transactional_get_or_create] + Entity task; + Transaction txn = datastore.newTransaction(); + try { + task = txn.get(taskKey); + if (task == null) { + task = Entity.newBuilder(taskKey).build(); + txn.put(task); + txn.commit(); + } + } finally { + if (txn.isActive()) { + txn.rollback(); + } + } + // [END datastore_transactional_get_or_create] + assertEquals(task, datastore.get(taskKey)); + } + + @Test + public void testTransactionalSingleEntityGroupReadOnly() { + setUpQueryTests(); + Key taskListKey = datastore.newKeyFactory().setKind("TaskList").newKey("default"); + Entity taskListEntity = Entity.newBuilder(taskListKey).build(); + datastore.put(taskListEntity); + // [START datastore_transactional_single_entity_group_read_only] + Entity taskList; + QueryResults tasks; + Transaction txn = datastore.newTransaction( + TransactionOptions.newBuilder() + .setReadOnly(ReadOnly.newBuilder().build()) + .build() + ); + try { + taskList = txn.get(taskListKey); + Query query = Query.newEntityQueryBuilder() + .setKind("Task") + .setFilter(PropertyFilter.hasAncestor(taskListKey)) + .build(); + tasks = txn.run(query); + txn.commit(); + } finally { + if (txn.isActive()) { + txn.rollback(); + } + } + // [END datastore_transactional_single_entity_group_read_only] + assertEquals(taskListEntity, taskList); + assertNotNull(tasks.next()); + assertFalse(tasks.hasNext()); + } + + @Test + public void testNamespaceRunQuery() { + setUpQueryTests(); + // [START datastore_namespace_run_query] + KeyFactory keyFactory = datastore.newKeyFactory().setKind("__namespace__"); + Key startNamespace = keyFactory.newKey("g"); + Key endNamespace = keyFactory.newKey("h"); + Query query = Query.newKeyQueryBuilder() + .setKind("__namespace__") + .setFilter(CompositeFilter.and( + PropertyFilter.gt("__key__", startNamespace), + PropertyFilter.lt("__key__", endNamespace))) + .build(); + List namespaces = new ArrayList<>(); + QueryResults results = datastore.run(query); + while (results.hasNext()) { + namespaces.add(results.next().getName()); + } + // [END datastore_namespace_run_query] + assertEquals(ImmutableList.of("ghijklmnop"), namespaces); + } + + @Test + public void testKindRunQuery() { + setUpQueryTests(); + // [START datastore_kind_run_query] + Query query = Query.newKeyQueryBuilder().setKind("__kind__").build(); + List kinds = new ArrayList<>(); + QueryResults results = datastore.run(query); + while (results.hasNext()) { + kinds.add(results.next().getName()); + } + // [END datastore_kind_run_query] + assertEquals(ImmutableList.of("Task"), kinds); + } + + @Test + public void testPropertyRunQuery() { + setUpQueryTests(); + // [START datastore_property_run_query] + Query query = Query.newKeyQueryBuilder().setKind("__property__").build(); + QueryResults keys = datastore.run(query); + Map> propertiesByKind = new HashMap<>(); + while (keys.hasNext()) { + Key key = keys.next(); + String kind = key.getParent().getName(); + String propertyName = key.getName(); + Collection properties = propertiesByKind.get(kind); + if (properties == null) { + properties = new HashSet<>(); + propertiesByKind.put(kind, properties); + } + properties.add(propertyName); + } + // [END datastore_property_run_query] + Map> expected = ImmutableMap.of("Task", ImmutableSet.of( + "done", "category", "done", "completed", "priority", "created", "percent_complete", "tag")); + assertEquals(expected, propertiesByKind); + } + + @Test + public void testPropertyByKindRunQuery() { + setUpQueryTests(); + // [START datastore_property_by_kind_run_query] + Key key = datastore.newKeyFactory().setKind("__kind__").newKey("Task"); + Query query = Query.newEntityQueryBuilder() + .setKind("__property__") + .setFilter(PropertyFilter.hasAncestor(key)) + .build(); + QueryResults results = datastore.run(query); + Map> representationsByProperty = new HashMap<>(); + while (results.hasNext()) { + Entity result = results.next(); + String propertyName = result.getKey().getName(); + List representations = result.getList("property_representation"); + Collection currentRepresentations = representationsByProperty.get(propertyName); + if (currentRepresentations == null) { + currentRepresentations = new HashSet<>(); + representationsByProperty.put(propertyName, currentRepresentations); + } + for (StringValue value : representations) { + currentRepresentations.add(value.get()); + } + } + // [END datastore_property_by_kind_run_query] + Map> expected = ImmutableMap.>builder() + .put("category", Collections.singleton("STRING")) + .put("done", Collections.singleton("BOOLEAN")) + .put("completed", Collections.singleton("BOOLEAN")) + .put("priority", Collections.singleton("INT64")) + .put("created", Collections.singleton("INT64")) + .put("percent_complete", Collections.singleton("DOUBLE")) + .put("tag", Collections.singleton("STRING")) + .build(); + assertEquals(expected, representationsByProperty); + } + + @Test + public void testPropertyFilteringRunQuery() { + setUpQueryTests(); + // [START datastore_property_filtering_run_query] + Key startKey = datastore.newKeyFactory() + .setKind("__property__") + .addAncestors(PathElement.of("__kind__", "Task")) + .newKey("priority"); + Query query = Query.newKeyQueryBuilder() + .setKind("__property__") + .setFilter(PropertyFilter.ge("__key__", startKey)) + .build(); + Map> propertiesByKind = new HashMap<>(); + QueryResults keys = datastore.run(query); + while (keys.hasNext()) { + Key key = keys.next(); + String kind = key.getParent().getName(); + String propertyName = key.getName(); + Collection properties = propertiesByKind.get(kind); + if (properties == null) { + properties = new HashSet(); + propertiesByKind.put(kind, properties); + } + properties.add(propertyName); + } + // [END datastore_property_filtering_run_query] + Map> expected = + ImmutableMap.of("Task", ImmutableSet.of("priority", "tag")); + assertEquals(expected, propertiesByKind); + } +} diff --git a/synth.metadata b/synth.metadata index c6089f985..70f2f18e5 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,22 +4,22 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/java-datastore.git", - "sha": "f1874f1b2745724ccc2345f35b65fb577f53683e" + "sha": "d6eca596440371e31031d36d600466b8e13e8109" } }, { "git": { "name": "googleapis", "remote": "https://github.com/googleapis/googleapis.git", - "sha": "c829fa0bfa725adaf20d82e86cbc1220e3ffd784", - "internalRef": "316124477" + "sha": "99ae9a76dbecb2aab008d5403e25413f5da0f436", + "internalRef": "320455075" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "c4f3059c27591eb24d6942a0e357ec94c80459f2" + "sha": "019c7168faa0e56619f792693a8acdb30d6de19b" } } ], @@ -33,5 +33,147 @@ "generator": "bazel" } } + ], + "generatedFiles": [ + ".github/CODEOWNERS", + ".github/ISSUE_TEMPLATE/bug_report.md", + ".github/ISSUE_TEMPLATE/feature_request.md", + ".github/ISSUE_TEMPLATE/support_request.md", + ".github/PULL_REQUEST_TEMPLATE.md", + ".github/release-please.yml", + ".github/trusted-contribution.yml", + ".github/workflows/ci.yaml", + ".github/workflows/samples.yaml", + ".kokoro/build.bat", + ".kokoro/build.sh", + ".kokoro/coerce_logs.sh", + ".kokoro/common.cfg", + ".kokoro/common.sh", + ".kokoro/continuous/common.cfg", + ".kokoro/continuous/java8.cfg", + ".kokoro/dependencies.sh", + ".kokoro/linkage-monitor.sh", + ".kokoro/nightly/common.cfg", + ".kokoro/nightly/integration.cfg", + ".kokoro/nightly/java11.cfg", + ".kokoro/nightly/java7.cfg", + ".kokoro/nightly/java8-osx.cfg", + ".kokoro/nightly/java8-win.cfg", + ".kokoro/nightly/java8.cfg", + ".kokoro/nightly/samples.cfg", + ".kokoro/populate-secrets.sh", + ".kokoro/presubmit/clirr.cfg", + ".kokoro/presubmit/common.cfg", + ".kokoro/presubmit/dependencies.cfg", + ".kokoro/presubmit/integration.cfg", + ".kokoro/presubmit/java11.cfg", + ".kokoro/presubmit/java7.cfg", + ".kokoro/presubmit/java8-osx.cfg", + ".kokoro/presubmit/java8-win.cfg", + ".kokoro/presubmit/java8.cfg", + ".kokoro/presubmit/linkage-monitor.cfg", + ".kokoro/presubmit/lint.cfg", + ".kokoro/presubmit/samples.cfg", + ".kokoro/release/bump_snapshot.cfg", + ".kokoro/release/common.cfg", + ".kokoro/release/common.sh", + ".kokoro/release/drop.cfg", + ".kokoro/release/drop.sh", + ".kokoro/release/promote.cfg", + ".kokoro/release/promote.sh", + ".kokoro/release/publish_javadoc.cfg", + ".kokoro/release/publish_javadoc.sh", + ".kokoro/release/snapshot.cfg", + ".kokoro/release/snapshot.sh", + ".kokoro/release/stage.cfg", + ".kokoro/release/stage.sh", + ".kokoro/trampoline.sh", + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "LICENSE", + "codecov.yaml", + "java.header", + "license-checks.xml", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/AllocateIdsRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/AllocateIdsRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/AllocateIdsResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/AllocateIdsResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ArrayValue.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ArrayValueOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/BeginTransactionRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/BeginTransactionRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/BeginTransactionResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/BeginTransactionResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CommitRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CommitRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CommitResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CommitResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CompositeFilter.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/CompositeFilterOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/DatastoreProto.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Entity.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/EntityOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/EntityProto.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/EntityResult.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/EntityResultOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Filter.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/FilterOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/GqlQuery.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/GqlQueryOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/GqlQueryParameter.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/GqlQueryParameterOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Key.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/KeyOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/KindExpression.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/KindExpressionOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/LookupRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/LookupRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/LookupResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/LookupResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Mutation.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/MutationOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/MutationResult.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/MutationResultOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PartitionId.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PartitionIdOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Projection.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ProjectionOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyFilter.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyFilterOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyOrder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyOrderOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyReference.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/PropertyReferenceOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Query.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/QueryOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/QueryProto.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/QueryResultBatch.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/QueryResultBatchOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReadOptions.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReadOptionsOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReserveIdsRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReserveIdsRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReserveIdsResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ReserveIdsResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RollbackRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RollbackRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RollbackResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RollbackResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RunQueryRequest.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RunQueryRequestOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RunQueryResponse.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/RunQueryResponseOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/TransactionOptions.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/TransactionOptionsOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/Value.java", + "proto-google-cloud-datastore-v1/src/main/java/com/google/datastore/v1/ValueOrBuilder.java", + "proto-google-cloud-datastore-v1/src/main/proto/google/datastore/v1/datastore.proto", + "proto-google-cloud-datastore-v1/src/main/proto/google/datastore/v1/entity.proto", + "proto-google-cloud-datastore-v1/src/main/proto/google/datastore/v1/query.proto", + "renovate.json", + "samples/install-without-bom/pom.xml", + "samples/pom.xml", + "samples/snapshot/pom.xml", + "samples/snippets/pom.xml" ] } \ No newline at end of file diff --git a/synth.py b/synth.py index d04690762..7220e8879 100644 --- a/synth.py +++ b/synth.py @@ -66,6 +66,5 @@ java.format_code('google-cloud-datastore/src') java.format_code(f'proto-google-cloud-{service}-{version}/src') -java.common_templates(excludes=[ - 'README.md', -]) +java.common_templates() + diff --git a/versions.txt b/versions.txt index 492e61c8b..96e4e4ae4 100644 --- a/versions.txt +++ b/versions.txt @@ -1,8 +1,8 @@ # Format: # module:released-version:current-version -google-cloud-datastore:1.104.0:1.104.0 -google-cloud-datastore-bom:1.104.0:1.104.0 -google-cloud-datastore-parent:1.104.0:1.104.0 -proto-google-cloud-datastore-v1:0.87.0:0.87.0 +google-cloud-datastore:1.105.0:1.105.0 +google-cloud-datastore-bom:1.105.0:1.105.0 +google-cloud-datastore-parent:1.105.0:1.105.0 +proto-google-cloud-datastore-v1:0.88.0:0.88.0