Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for Proto Columns DDL #2277

Conversation

harshachinta
Copy link
Contributor

This PR adds feature support for Proto Columns DDL with supporting integration tests.

@product-auto-label product-auto-label bot added the size: xl Pull request size is extra large. label Feb 13, 2023
@generated-files-bot
Copy link

generated-files-bot bot commented Feb 13, 2023

Warning: This pull request is touching the following templated files:

  • google-cloud-spanner/src/main/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClient.java
  • google-cloud-spanner/src/test/java/com/google/cloud/spanner/admin/database/v1/DatabaseAdminClientTest.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequest.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/CreateDatabaseRequestOrBuilder.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponse.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/GetDatabaseDdlResponseOrBuilder.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/SpannerDatabaseAdminProto.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequest.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/java/com/google/spanner/admin/database/v1/UpdateDatabaseDdlRequestOrBuilder.java
  • proto-google-cloud-spanner-admin-database-v1/src/main/proto/google/spanner/admin/database/v1/spanner_database_admin.proto

@product-auto-label product-auto-label bot added the api: spanner Issues related to the googleapis/java-spanner API. label Feb 13, 2023
@Override
public Builder setProtoDescriptors(String filePath) throws IOException {
Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty.");
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the method only support reading files from Project Resources. If yes please clarify it in java doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in java doc

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Project Resources a good default?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Having the resources with in the class path can help users provide a relative file path as input and Project resources directory is a good place to maintain all these files.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I understand the argument that having the proto descriptors in the resources directory of your project makes sense, I'm not sure that this will work as expected in all cases. This code does not live in the project of the end user, but in the client library. In an end user project, the client library will be one of many dependencies packaged as a jar. Will this always include the resources of directories of the end user project? What if that project uses multiple class loaders? I'm afraid that this could cause unexpected behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olavloite
My understanding here is class loader can find a resource if it is there in the classpath and resources directory would always be a part of the classpath. I tried this with a small demo application and it works fine.
However, I am not aware of the behaviour if there are any custom/multiple class loaders. I would need some time to analyse the behaviour in this case.
In the interest of time, I am planning to remove this overload that accepts a file path as argument and take it separately in another PR.
Can you please let me know your views here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that removing this for now is a good choice. People can easily use resources from their class path using the overload that takes an InputStream by calling getResourceAsStream() themselves.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the overload changes.

Copy link
Contributor

@gauravpurohit06 gauravpurohit06 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Override
public Builder setProtoDescriptors(String filePath) throws IOException {
Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty.");
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Project Resources a good default?

}

@Override
public Builder setProtoDescriptors(String filePath) throws IOException {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a precedence of reading file on user's behalf? What about other Google Cloud client libraries. Are we reading files in the recommended way in case there is one?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User's can read the file on their end and pass in the byte[] or InputStream as input to the setProtoDescriptors method. Alternatively, we also add another overloaded method that accepts the file path as input.

@gauravpurohit06 gauravpurohit06 requested a review from Shua1 March 9, 2023 11:53
@harshachinta harshachinta marked this pull request as ready for review March 9, 2023 12:13
@harshachinta harshachinta requested review from a team as code owners March 9, 2023 12:13
* one. This must be unique within a database abd must be a valid identifier
* [a-zA-Z][a-zA-Z0-9_]*.
*/
public OperationFuture<Void, UpdateDatabaseDdlMetadata> updateDdl(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't notice this during the last review, but this seems a little strange. It is a method in the Database class and takes a Database instance as an argument. Why does it not just operate on this database?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason it cannot operate on this database is because a user cannot set ProtoDescriptor directly to Database Class as setProtoDescriptors method belongs to Database.Builder. Below is a small example to illustrate this,

Database database = client.getDatabase(INSTANCE_ID, DB_ID);

// If a user wants to update the ProtoDescriptor field then, 
// the below line cannot be written as setProtoDescriptors method does not belong to Database class.
database.setProtoDescriptors("descriptors.pb"); 

// This does not update proto descriptor in the database because the field was not updated.
database.updateDdl(Collections.singletonList("DROP TABLE Singer"), null); 

So a new Database instance has to be passed to update the ProtoDescriptor field. However, I agree that this is incorrect and confusing at same time.

Another Approach
@olavloite Please validate if below is more meaningful to do.

Expose a new method toBuilder() in Database.java that return a Builder of that Database instance. This allows users to setProtoDescriptor by calling the builder.
The change in Database.java is

public class Database extends DatabaseInfo {
  public Builder toBuilder() {
      return new Builder(this);
    }


  public OperationFuture<Void, UpdateDatabaseDdlMetadata> updateDdl(
      Iterable<String> statements, String operationId) throws SpannerException {
     // The updateDatabaseDdl is called with 'this' as argument instead of instance(), database()
    return dbClient.updateDatabaseDdl(this, statements, operationId);
  }
}

The user can use it like below

Database database = client.getDatabase(INSTANCE_ID, DB_ID);
// The below database instance has the updated ProtoDescriptor field
database = database.toBuilder().setProtoDescriptors("descriptors.pb").build();
// Update works fine
database.updateDdl(Collections.singletonList("DROP TABLE Singer"), null);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm.... If the protoDescriptors field is not something that is actually part of the Database class and thereby also not stored with the database, and is only needed for the update method, then we need to add it as an argument to the method afte rall. Other approaches would be non-idiomatic Java.

So the signature of the method would then become Database#updateDatabaseDdl(Iterable<String> statements, String protoDescriptors, String operationId). Another option would be to create a DatabaseUpdateOptions class that contains all possible update options, the first one being protoDescriptors (that would make it more easily reusable for additional options in the future).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you @olavloite. Creating a new DatabaseUpdateOptions class that can update options will help us reuse in future. I will take this effort as part of the next PR. I will tag this comment in the other PR later to understand the need of that change.

@Override
public Builder setProtoDescriptors(String filePath) throws IOException {
Preconditions.checkState(filePath.length() != 0, "Input File Path cannot be empty.");
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I understand the argument that having the proto descriptors in the resources directory of your project makes sense, I'm not sure that this will work as expected in all cases. This code does not live in the project of the end user, but in the client library. In an end user project, the client library will be one of many dependencies packaged as a jar. Will this always include the resources of directories of the end user project? What if that project uses multiple class loaders? I'm afraid that this could cause unexpected behavior.

@olavloite olavloite requested review from arpan14 and removed request for Shua1 March 14, 2023 19:02
@harshachinta harshachinta requested a review from olavloite March 15, 2023 11:49
@harshachinta harshachinta merged commit 2f8eb42 into googleapis:proto-column-enhancement-alpha Mar 15, 2023
harshachinta added a commit that referenced this pull request Jan 26, 2024
* feat: Support for Proto Messages & Enums (#2155)

* feat: Importing Proto Changes

Commit will be reverted, once PROTO changes are available publicly.

* feat: Proto Message Implementation

* feat: Adding support for enum

* feat: Code refactoring

Adding default implementation for newly added methods
ByteArray compatability changes for Proto Messages

* docs: Adding Java docs for all the newly added methods.

* test: Sample Proto & Generated classes for unit test

* feat: Adding bytes/proto & int64/enum compatability

Adding Additional check for ChecksumResultSet

* test: Adding unit tests

* test: Adding unit tests for ValueBinder.java

* feat: refactoring to add support for getValue & other minor changes

* feat: Minor refactoring

1. Adding docs and formatting the code.
2. Adding additional methods for enum and message which accepts descriptors.

* feat: Adding bytes/message & int64/enum compatability in Value

* refactor: Minor refactoring

* feat: Adding Proto Array Implementation

* test: Implementing unit tests for array of protos and enums

* refactor: adding clirr ignores

* feat: Adding support for enum as Primary Key

* feat: Code Review Changes, minor refactoring and adding docs

* feat: Addressing review comments

-Modified Docs/Comments
-Minor Refactoring

* refactor: Using Column instead of column to avoid test failures

* feat: Minor refactoring

-code review comments
-adding function docs

* samples: Adding samples for updating & querying Proto messages & enums (#2211)

* samples: Adding samples for updating & querying Proto messages & enums

* style: linting

* style: linting

* docs: Adding function and class doc

* test: Proto Column Integration tests (#2212)

* test: Adding Integration tests for Proto Messages & Enums

* test: Adding additional test for Parameterized Queries, Primary Keys & Invalid Wire type errors.

* style: Formatting

* style: Formatting

* test: Updating instance and db name

* test: Adding inter compatability check while writing data

* Configured jitpack.yml to use OpenJDK 11 (#2218)

Co-authored-by: Pavol Juhos <[email protected]>

* feat: add support for Proto Columns DDL (#2277)

* feat: add code changes and tests for Proto columns DDL support

* feat: add auto generated code

* feat: code changes and tests for Proto columns DDL support

* feat: add descriptors file

* feat: code refactoring

* feat: Integration tests and code refactoring

* feat: code refactoring

* feat: unit tests and clirr differences

* feat: lint changes

* feat: code refactor

* feat: code refactoring

* feat: code refactoring

* feat: code refactoring

* feat: add java docs to new methods

* feat: lint formatting

* feat: lint formatting changes

* feat: lint formatting

* feat: lint formatting

* feat: test exception cases

* feat: code refactoring

* feat: add java docs and refactoring

* feat: add java docs

* feat: java docs refactor

* feat: remove overload method setProtoDescriptors that accepts file path as input to avoid unexpected issues

* feat: remove updateDdl method overload to update proto descriptor

* teat: update pom file to run tests on cloud-devel region temporarily to validate main branch update

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix: revert host changes in pom.xml file

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* feat(spanner): revert autogenerated code

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* feat(spanner): remove samples

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* feat(spanner): remove clirr

* feat(spanner): skip emulator test

* feat(spanner): clirr

* feat(spanner): fix javadoc

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* feat(spanner): fix javadoc

* feat(spanner): fix javadoc

* feat(spanner): fix javadoc

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* feat(spanner): fix emulator skip

* build: ignore all changes in v1 package

* feat(spanner): add optimizations to deserialize proto messages

* feat(spanner): remove TODO

* feat(spanner): remove TODO

---------

Co-authored-by: Gaurav Purohit <[email protected]>
Co-authored-by: Pavol Juhos <[email protected]>
Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Co-authored-by: Knut Olav Løite <[email protected]>
harshachinta added a commit that referenced this pull request May 24, 2024
* feat: Support for Proto Messages & Enums (#2155)

* feat: Importing Proto Changes

Commit will be reverted, once PROTO changes are available publicly.

* feat: Proto Message Implementation

* feat: Adding support for enum

* feat: Code refactoring

Adding default implementation for newly added methods
ByteArray compatability changes for Proto Messages

* docs: Adding Java docs for all the newly added methods.

* test: Sample Proto & Generated classes for unit test

* feat: Adding bytes/proto & int64/enum compatability

Adding Additional check for ChecksumResultSet

* test: Adding unit tests

* test: Adding unit tests for ValueBinder.java

* feat: refactoring to add support for getValue & other minor changes

* feat: Minor refactoring

1. Adding docs and formatting the code.
2. Adding additional methods for enum and message which accepts descriptors.

* feat: Adding bytes/message & int64/enum compatability in Value

* refactor: Minor refactoring

* feat: Adding Proto Array Implementation

* test: Implementing unit tests for array of protos and enums

* refactor: adding clirr ignores

* feat: Adding support for enum as Primary Key

* feat: Code Review Changes, minor refactoring and adding docs

* feat: Addressing review comments

-Modified Docs/Comments
-Minor Refactoring

* refactor: Using Column instead of column to avoid test failures

* feat: Minor refactoring

-code review comments
-adding function docs

* samples: Adding samples for updating & querying Proto messages & enums (#2211)

* samples: Adding samples for updating & querying Proto messages & enums

* style: linting

* style: linting

* docs: Adding function and class doc

* test: Proto Column Integration tests (#2212)

* test: Adding Integration tests for Proto Messages & Enums

* test: Adding additional test for Parameterized Queries, Primary Keys & Invalid Wire type errors.

* style: Formatting

* style: Formatting

* test: Updating instance and db name

* test: Adding inter compatability check while writing data

* Configured jitpack.yml to use OpenJDK 11 (#2218)

Co-authored-by: Pavol Juhos <[email protected]>

* feat: add support for Proto Columns DDL (#2277)

* feat: add code changes and tests for Proto columns DDL support

* feat: add auto generated code

* feat: code changes and tests for Proto columns DDL support

* feat: add descriptors file

* feat: code refactoring

* feat: Integration tests and code refactoring

* feat: code refactoring

* feat: unit tests and clirr differences

* feat: lint changes

* feat: code refactor

* feat: code refactoring

* feat: code refactoring

* feat: code refactoring

* feat: add java docs to new methods

* feat: lint formatting

* feat: lint formatting changes

* feat: lint formatting

* feat: lint formatting

* feat: test exception cases

* feat: code refactoring

* feat: add java docs and refactoring

* feat: add java docs

* feat: java docs refactor

* feat: remove overload method setProtoDescriptors that accepts file path as input to avoid unexpected issues

* feat: remove updateDdl method overload to update proto descriptor

* teat: update pom file to run tests on cloud-devel region temporarily to validate main branch update

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix: revert host changes in pom.xml file

* feat: add support for Proto Columns to Connection API

* feat: add client side statement support for proto descriptor

* feat: update existing unit tests to include proto descriptorss argument

* feat: code refactor for client side statements

* feat: add unit tests

* feat: code refactoring for file path client statement

* test: add integration test for DDL

* fix: comment refactoring

* feat: move proto descriptor file read logic to ConnectionImpl file to fix autogenerated client side statement tests

* feat: add autogenerated test for new proto columns client side statements

* feat: add unit tests to verify proto descriptor set via filepath

* feat: add review comments

* feat: add client side statement to show proto descriptors file path

* fix: remove proto descriptors file extension validation

* feat: comment refactor

* feat: address review comments

* feat: update tests and revert autogenerated code

* chore: revert autogenerated coee

* chore: revert autogenerated code

* chore: revert autogenerated code

* chore: lint format

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* chore: regenerate descriptors file

* chore: update schema

* chore: update base64 value for protodescriptor

* chore: update copyright year

---------

Co-authored-by: Gaurav Purohit <[email protected]>
Co-authored-by: Pavol Juhos <[email protected]>
Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: spanner Issues related to the googleapis/java-spanner API. size: xl Pull request size is extra large.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants