Skip to content

Commit e589265

Browse files
gderemetzgregturn
authored andcommitted
Made JSqlParserQueryEnhancer aware of MERGE statements.
Closes #2641.
1 parent eff3803 commit e589265

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import net.sf.jsqlparser.statement.Statement;
2929
import net.sf.jsqlparser.statement.delete.Delete;
3030
import net.sf.jsqlparser.statement.insert.Insert;
31+
import net.sf.jsqlparser.statement.merge.Merge;
3132
import net.sf.jsqlparser.statement.select.OrderByElement;
3233
import net.sf.jsqlparser.statement.select.PlainSelect;
3334
import net.sf.jsqlparser.statement.select.Select;
@@ -58,6 +59,7 @@
5859
*
5960
* @author Diego Krupitza
6061
* @author Greg Turnquist
62+
* @author Geoffrey Deremetz
6163
* @since 2.7.0
6264
*/
6365
public class JSqlParserQueryEnhancer implements QueryEnhancer {
@@ -92,6 +94,8 @@ private ParsedType detectParsedType() {
9294
return ParsedType.DELETE;
9395
} else if (statement instanceof Select) {
9496
return ParsedType.SELECT;
97+
} else if (statement instanceof Merge) {
98+
return ParsedType.MERGE;
9599
} else {
96100
return ParsedType.SELECT;
97101
}
@@ -483,10 +487,11 @@ public DeclaredQuery getQuery() {
483487
* <li>{@code ParsedType.UPDATE}: means the top level statement is {@link Update}</li>
484488
* <li>{@code ParsedType.SELECT}: means the top level statement is {@link Select}</li>
485489
* <li>{@code ParsedType.INSERT}: means the top level statement is {@link Insert}</li>
490+
* <li>{@code ParsedType.MERGE}: means the top level statement is {@link Merge}</li>
486491
* </ul>
487492
*/
488493
enum ParsedType {
489-
DELETE, UPDATE, SELECT, INSERT;
494+
DELETE, UPDATE, SELECT, INSERT, MERGE;
490495
}
491496

492497
}

src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java

+17
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
* @author Diego Krupitza
108108
* @author Daniel Shuy
109109
* @author Simon Paradies
110+
* @author Geoffrey Deremetz
110111
*/
111112
@ExtendWith(SpringExtension.class)
112113
@ContextConfiguration("classpath:application-context.xml")
@@ -2810,6 +2811,22 @@ void insertStatementModifyingQueryWithParamsWorks() {
28102811
.contains("Gierke", "Arrasz", "Matthews", "raymond", testLastName);
28112812
}
28122813

2814+
@Test // GH-2641
2815+
void mergeWithNativeStatement() {
2816+
2817+
flushTestUsers();
2818+
2819+
Optional<User> byIdUser = repository.findById(firstUser.getId());
2820+
assertThat(byIdUser).isPresent().map(User::getAge).get().isEqualTo(28);
2821+
2822+
// when
2823+
repository.mergeNativeStatement();
2824+
2825+
// then
2826+
Optional<User> afterUpdate = repository.findById(firstUser.getId());
2827+
assertThat(afterUpdate).isPresent().map(User::getAge).get().isEqualTo(30);
2828+
}
2829+
28132830
private Page<User> executeSpecWithSort(Sort sort) {
28142831

28152832
flushTestUsers();

src/test/java/org/springframework/data/jpa/repository/query/QueryEnhancerUnitTests.java

+13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* Unit tests for {@link QueryEnhancer}.
3939
*
4040
* @author Diego Krupitza
41+
* @author Geoffrey Deremetz
4142
*/
4243
class QueryEnhancerUnitTests {
4344

@@ -922,6 +923,18 @@ void insertStatementIsProcessedSameAsDefault(String insertQuery) {
922923
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
923924
}
924925

926+
@Test // GH-2641
927+
void mergeStatementWorksWithJSqlParser() {
928+
String query = "merge into a using (select id, value from b) query on (a.id = query.id) when matched then update set a.value = value";
929+
StringQuery stringQuery = new StringQuery(query, true);
930+
QueryEnhancer queryEnhancer = QueryEnhancerFactory.forQuery(stringQuery);
931+
932+
assertThat(queryEnhancer.getJoinAliases()).isEmpty();
933+
assertThat(queryEnhancer.detectAlias()).isNull();
934+
assertThat(queryEnhancer.getProjection()).isEmpty();
935+
assertThat(queryEnhancer.hasConstructorExpression()).isFalse();
936+
}
937+
925938
public static Stream<Arguments> insertStatementIsProcessedSameAsDefaultSource() {
926939
return Stream.of( //
927940
Arguments.of("INSERT INTO FOO(A) VALUES('A')"), //

src/test/java/org/springframework/data/jpa/repository/sample/UserRepository.java

+11
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
* @author Greg Turnquist
5656
* @author Simon Paradies
5757
* @author Diego Krupitza
58+
* @author Geoffrey Deremetz
5859
*/
5960
public interface UserRepository
6061
extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User>, UserRepositoryCustom {
@@ -693,6 +694,16 @@ List<String> findAllAndSortByFunctionResultNamedParameter(@Param("namedParameter
693694
nativeQuery = true)
694695
void insertNewUserWithParamNativeQuery(@Param("lastname") String lastname);
695696

697+
// GH-2641
698+
@Modifying(clearAutomatically = true)
699+
@Query(value = "merge into sd_user " + //
700+
"using (select id from sd_user where age < 30) request " + //
701+
"on (sd_user.id = request.id) " + //
702+
"when matched then " + //
703+
" update set sd_user.age = 30", //
704+
nativeQuery = true)
705+
int mergeNativeStatement();
706+
696707
interface RolesAndFirstname {
697708

698709
String getFirstname();

0 commit comments

Comments
 (0)