Skip to content

Made JSqlParserQueryEnhancer aware of MERGE statements. #2642

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

Closed
wants to merge 2 commits into from

Conversation

gderemetz
Copy link
Contributor

Related tickets #2641

  • You have read the Spring Data contribution guidelines.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

Copy link
Contributor

@DiegoKrupitza DiegoKrupitza left a comment

Choose a reason for hiding this comment

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

I like your extension :) It should resolve the problem. Please review my comments. The JavaDoc is important, so the documentation stays up-to-date. Regarding the alias I would love to hear your take on this.

@@ -478,7 +482,7 @@ public DeclaredQuery getQuery() {
* </ul>
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add the new MERGE to the JavaDoc of the enum.

<li>{@code ParsedType.MERGE}: means the top level statement is {@link Merge}</li>

QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);

assertThat(queryEnhancer.getJoinAliases()).isEmpty();
assertThat(queryEnhancer.detectAlias()).isNull();
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know if this is ever needed but as far as I can see a merge has an "alias" (see screenshot).
Maybe it should not return NULL here. Is it possible to adapt the detectAlias() to consider this edge case without making the method overly complicated?

image

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 tried to adapt the detectAlias() method for JSqlParserQueryEnhancer class, however it is more difficult for me to modify the method for the DefaultQueryEnhancer (82590bf)
I am waiting your feedback

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes your are totally right! It seems that the DefaultQueryEnhancer (which uses QueryUtils) does not correctly detect the alias, when providing a Merge statement. I checked this using the following test:

@Test 
void queryUtilsDetectsMergeAliasCorrectly() {
String alias = QueryUtils.detectAlias(
		"merge into a using (select id, value from b) query on (a.id = query.id) when matched then update set a.value = value");

assertThat(alias).isNotNull().isNotEmpty();
}

I think for this we have to turn to @gregturn or any other member of the team.
Do we want the JSqlParserQueryEnhancer to "simulate" the same behaviour as DefaultQueryEnhancer (which is at the moment returning smth wrong aka NULL for a Merge statement) or should it be returning the actual correct alias.

Personally I would like JSqlParserQueryEnhancer to return the correct alias. Ergo stick with your implementation.

If the members are also of the same opinion, we should, in later stages (another PR), make DefaultQueryEnhancer (entails QueryUtils) aware of the fact that a merge statement can have an alias.

@DiegoKrupitza
Copy link
Contributor

I have seen this is your first PR here, welcome to Open Source 🥳👍 While reviewing your PR I have seen your forgot to add the Closes #2641 to your commit. Adding this is quite helpful because then GitHub then create automatic links between commits and issues.

https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc#commit-messages

Copy link
Contributor

@DiegoKrupitza DiegoKrupitza left a comment

Choose a reason for hiding this comment

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

All in all it looks good. I just left two comments just for personal taste.

* @return Might return {@literal null}.
*/
@Nullable
private static String detectAlias(Merge mergeStatement) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason why you decided to make the method static?

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 just kept the same behavior for the function just above (static method) to have a homogeneous code :
private static String detectAlias(PlainSelect selectBody)

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh makes sense! I can't remember anymore why I made that method static 😅

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 made a force push ... I hope this is not a mistake

@@ -449,10 +465,10 @@ public Set<String> getJoinAliases() {
* @param query the query to parse
* @return the parsed query
*/
private static Select parseSelectStatement(String query) {
private static <T extends Statement> T parseSelectStatement(String query, Class<T> classOfT) {
Copy link
Contributor

@DiegoKrupitza DiegoKrupitza Sep 23, 2022

Choose a reason for hiding this comment

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

Thats a clever solution! Makes it more flexible in the future.
Personally I would also add a "default" version where we know it will be a Select. Because as you can see above we often call parseSelectStatement(query.getQueryString(), Select.class);.

       /**
	 * Parses a query string with JSqlParser.
	 *
	 * @param query the query to parse
	 * @return the parsed query
	 */
	private Select parseSelectStatement(String query) {
		return parseSelectStatement(query,Select.class);
	}

@gregturn
Copy link
Contributor

Thanks to @xercasy and @DiegoKrupitza! I have polished and merged this PR to main.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage An issue we've not yet triaged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants