-
Notifications
You must be signed in to change notification settings - Fork 884
JAVA-2307: Improve @Select and @Delete by not requiring full primary key #1285
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
Conversation
Motivation: Currently `@Select` and `@Delete` annotated methods only allow selecting/deleting individual entities when parameters are provided as the mapper currently requires specifying all columns of the primary key as parameters. Since CQL allows you to select and delete multiple rows by providing a subset of the primary key, these dao methods can be improved by accepting a subset of the primary key as parameters, as long as at least the partition keys are represented. In addition `@Select` should be supported when providing no parameters, which will allow querying an entire table's rows for a given entity. Modifications: Add `EntityHelper.selectByPrimaryKeyParts` and `deleteByPrimaryKeyParts` methods and added generators to provide this capability. Refactor parameter validation into EntityUtils.areParametersValid from somewhat duplicated logic in delete and select method generators. Add tests to exercise functionality. Add documentation demonstrating extended capability. Result: `@Select` and `@Delete` now support providing a subset of primary key to select/delete multiple entities. `@Select` also supports providing zero parameters, which performs a select on all rows in an entity's table.
*/ | ||
@NonNull | ||
default Select selectByPrimaryKeyParts(int parameterCount) { | ||
throw new UnsupportedOperationException("selectbyPrimaryKeyParts is unimplemented"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done to avoid breaking changes, although it is a bit awkward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done to avoid breaking changes, although it is a bit awkward.
Yes, and this only hides the breaking change by turning it into a runtime error. I've been thinking about other possible approaches:
-
introduce a sub-interface and require a cast (as we've done in other cases). The problem is that this doesn't scale well: we add
ExtendedProductHelper
now but what if we need more methods in the next version?ExtendedExtendedProductHelper
? -
Accept the breaking change and document it, on the assumption that clients probably don't implement this interface. The problem is in the "probably"; also, it's a slippery slope.
-
Don't add those methods to
EntityHelper
. Instead, generate the query directly from the method generators. For SELECT we already haveselectStart()
; for DELETE we have to duplicate the whole method, but it's not huge either.We won't make those queries available to users through the interface (e.g. for custom query providers), but they're not that hard to rewrite from scratch anyway.
My vote goes to 3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't add those methods to EntityHelper
You know, it didn't occur to me that generated code used the implementations instead of declaring things as EntityHelper
. In this case, there is no reason to add something to the interface, so I agree this seems like a good course of action.
It looks like the only place (currently) that EntityHelper
is used as an interface in other code is in QueryProvider
and in DaoBase
, where it's more used for setting/getting fields.
Since this method is used for query generation, I suppose it's probably fine to not put directly in EntityHelper
.
But I do wonder if we should just consider removing all the query-generation based methods from EntityHelper
now if we see no utility. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You know, it didn't occur to me that generated code used the implementations instead of declaring things as
EntityHelper
.
It didn't occur to me either 😆 I was initially thinking of moving the code to the DAO implementation class, but keeping them as "internal" methods in the helper class is even better.
removing all the query-generation based methods from
EntityHelper
As we discussed privately, those methods can be useful for @QueryProvider
implementors, so it's nice to have them on the interface.
changelog/README.md
Outdated
@@ -2,8 +2,10 @@ | |||
|
|||
<!-- Note: contrary to 3.x, insert new entries *first* in their section --> | |||
|
|||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary change.
changelog/README.md
Outdated
### 4.2.0 (in progress) | ||
|
||
- [improvement] JAVA-2307: Improve @Select and @Delete by not requiring full primary key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tip: place all words starting with @
within backticks here and in commit messages, to avoid having Github consider that these are user handles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I'll amend the commit when merging. It looks like github doesn't hijack markdown in the same way, but agree that we shoulds use backticks here as well.
integration-tests/src/test/java/com/datastax/oss/driver/mapper/InventoryITBase.java
Outdated
Show resolved
Hide resolved
...ain/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java
Outdated
Show resolved
Hide resolved
...ain/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java
Outdated
Show resolved
Hide resolved
...ocessor/src/main/java/com/datastax/oss/driver/internal/mapper/processor/dao/EntityUtils.java
Outdated
Show resolved
Hide resolved
...ain/java/com/datastax/oss/driver/internal/mapper/processor/dao/DaoDeleteMethodGenerator.java
Outdated
Show resolved
Hide resolved
*/ | ||
@NonNull | ||
default Select selectByPrimaryKeyParts(int parameterCount) { | ||
throw new UnsupportedOperationException("selectbyPrimaryKeyParts is unimplemented"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done to avoid breaking changes, although it is a bit awkward.
Yes, and this only hides the breaking change by turning it into a runtime error. I've been thinking about other possible approaches:
-
introduce a sub-interface and require a cast (as we've done in other cases). The problem is that this doesn't scale well: we add
ExtendedProductHelper
now but what if we need more methods in the next version?ExtendedExtendedProductHelper
? -
Accept the breaking change and document it, on the assumption that clients probably don't implement this interface. The problem is in the "probably"; also, it's a slippery slope.
-
Don't add those methods to
EntityHelper
. Instead, generate the query directly from the method generators. For SELECT we already haveselectStart()
; for DELETE we have to duplicate the whole method, but it's not huge either.We won't make those queries available to users through the interface (e.g. for custom query providers), but they're not that hard to rewrite from scratch anyway.
My vote goes to 3.
…l/mapper/processor/dao/EntityUtils.java Co-Authored-By: Olivier Michallat <olim7t@users.noreply.github.com>
* Use backticks for annotations in changelog. * Use constants for dates in tests. * Make more explicit in readme that clustering column order matters. * Rename keyParameterSize -> primaryKeyParamterCounter * sublist primaryKeyNames to avoid assertion error. * Demote deleteByPrimaryKeyParts / selectByPrimaryKeyParts from EntityHelper interface. *
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
manual/mapper/daos/delete/README.md
Outdated
void deleteByIdForCustomer(UUID productId, LocalDate day, UUID customerId); | ||
|
||
/* Note that the clustering columns in your primary key definition are significant. All | ||
* proceeding clustering columns must be provided if any are. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proceeding clustering columns
Did you mean "preceding"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦♂️ yep, that's what I meant. Good catch, i'll fix.
For JAVA-2307
Motivation:
Currently
@Select
and@Delete
annotated methods only allowselecting/deleting individual entities when parameters are provided as
the mapper currently requires specifying all columns of the primary key as
parameters.
Since CQL allows you to select and delete multiple rows by providing a
subset of the primary key, these dao methods can be improved by
accepting a subset of the primary key as parameters, as long as
at least the partition keys are represented.
In addition
@Select
should be supported when providing no parameters,which will allow querying an entire table's rows for a given entity.
Modifications:
Add
EntityHelper.selectByPrimaryKeyParts
anddeleteByPrimaryKeyParts
methods and added generators to provide this capability.
Refactor parameter validation into EntityUtils.areParametersValid from
somewhat duplicated logic in delete and select method generators.
Add tests to exercise functionality.
Add documentation demonstrating extended capability.
Result:
@Select
and@Delete
now support providing a subset of primary key toselect/delete multiple entities.
@Select
also supports providing zero parameters, which performs aselect on all rows in an entity's table.