Skip to content

Commit 5be8e87

Browse files
committed
feat: support any number/order of merge operations
1 parent 34561d8 commit 5be8e87

File tree

12 files changed

+293
-165
lines changed

12 files changed

+293
-165
lines changed

src/main/java/net/sf/jsqlparser/statement/merge/Merge.java

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ public class Merge implements Statement {
3434
private OracleHint oracleHint = null;
3535
private FromItem fromItem;
3636
private Expression onCondition;
37-
private MergeInsert mergeInsert;
38-
private MergeUpdate mergeUpdate;
39-
private boolean insertFirst = false;
37+
private List<MergeOperation> operations;
4038

4139
private OutputClause outputClause;
4240

@@ -129,33 +127,52 @@ public void setOnCondition(Expression onCondition) {
129127
this.onCondition = onCondition;
130128
}
131129

132-
public MergeInsert getMergeInsert() {
133-
return mergeInsert;
130+
public List<MergeOperation> getOperations() {
131+
return operations;
134132
}
135133

136-
public void setMergeInsert(MergeInsert insert) {
137-
this.mergeInsert = insert;
134+
public void setOperations(List<MergeOperation> operations) {
135+
this.operations = operations;
138136
}
139137

140-
public MergeUpdate getMergeUpdate() {
141-
return mergeUpdate;
138+
/**
139+
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
140+
*/
141+
@Deprecated
142+
public MergeInsert getMergeInsert() {
143+
return operations.stream()
144+
.filter(MergeInsert.class::isInstance)
145+
.findFirst()
146+
.map(MergeInsert.class::cast)
147+
.orElse(null);
142148
}
143149

144-
public void setMergeUpdate(MergeUpdate mergeUpdate) {
145-
this.mergeUpdate = mergeUpdate;
150+
/**
151+
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
152+
*/
153+
@Deprecated
154+
public MergeUpdate getMergeUpdate() {
155+
return operations.stream()
156+
.filter(MergeUpdate.class::isInstance)
157+
.findFirst()
158+
.map(MergeUpdate.class::cast)
159+
.orElse(null);
146160
}
147161

148162
@Override
149163
public void accept(StatementVisitor statementVisitor) {
150164
statementVisitor.visit(this);
151165
}
152166

167+
/**
168+
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
169+
*/
170+
@Deprecated
153171
public boolean isInsertFirst() {
154-
return insertFirst;
155-
}
156-
157-
public void setInsertFirst(boolean insertFirst) {
158-
this.insertFirst = insertFirst;
172+
if (operations == null || operations.isEmpty()) {
173+
return false;
174+
}
175+
return operations.get(0) instanceof MergeInsert;
159176
}
160177

161178
public OutputClause getOutputClause() {
@@ -193,16 +210,8 @@ public String toString() {
193210
b.append(" ON ");
194211
b.append(onCondition);
195212

196-
if (insertFirst && mergeInsert != null) {
197-
b.append(mergeInsert);
198-
}
199-
200-
if (mergeUpdate != null) {
201-
b.append(mergeUpdate);
202-
}
203-
204-
if (!insertFirst && mergeInsert != null) {
205-
b.append(mergeInsert);
213+
if (operations != null && !operations.isEmpty()) {
214+
operations.forEach(b::append);
206215
}
207216

208217
if (outputClause != null) {
@@ -235,26 +244,11 @@ public Merge withOnCondition(Expression onCondition) {
235244
return this;
236245
}
237246

238-
public Merge withMergeUpdate(MergeUpdate mergeUpdate) {
239-
this.setMergeUpdate(mergeUpdate);
240-
return this;
241-
}
242-
243-
public Merge withInsertFirst(boolean insertFirst) {
244-
this.setInsertFirst(insertFirst);
245-
return this;
246-
}
247-
248247
public Merge withTable(Table table) {
249248
this.setTable(table);
250249
return this;
251250
}
252251

253-
public Merge withMergeInsert(MergeInsert mergeInsert) {
254-
this.setMergeInsert(mergeInsert);
255-
return this;
256-
}
257-
258252
public <E extends Expression> E getOnCondition(Class<E> type) {
259253
return type.cast(getOnCondition());
260254
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package net.sf.jsqlparser.statement.merge;
2+
3+
import net.sf.jsqlparser.expression.Expression;
4+
5+
import java.io.Serializable;
6+
7+
public class MergeDelete implements Serializable, MergeOperation {
8+
private Expression andPredicate;
9+
10+
public Expression getAndPredicate() {
11+
return andPredicate;
12+
}
13+
14+
public void setAndPredicate(Expression andPredicate) {
15+
this.andPredicate = andPredicate;
16+
}
17+
18+
@Override
19+
public void accept(MergeOperationVisitor mergeOperationVisitor) {
20+
mergeOperationVisitor.visit(this);
21+
}
22+
23+
@Override
24+
public String toString() {
25+
StringBuilder b = new StringBuilder();
26+
b.append(" WHEN MATCHED");
27+
if (andPredicate != null) {
28+
b.append(" AND ").append(andPredicate.toString());
29+
}
30+
b.append(" THEN DELETE");
31+
return b.toString();
32+
}
33+
}

src/main/java/net/sf/jsqlparser/statement/merge/MergeInsert.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import java.util.Collection;
1919
import java.util.Optional;
2020

21-
public class MergeInsert implements Serializable {
21+
public class MergeInsert implements Serializable, MergeOperation {
2222

2323
private Expression andPredicate;
2424
private ExpressionList<Column> columns;
@@ -57,6 +57,11 @@ public void setWhereCondition(Expression whereCondition) {
5757
this.whereCondition = whereCondition;
5858
}
5959

60+
@Override
61+
public void accept(MergeOperationVisitor mergeOperationVisitor) {
62+
mergeOperationVisitor.visit(this);
63+
}
64+
6065
@Override
6166
public String toString() {
6267
StringBuilder b = new StringBuilder();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package net.sf.jsqlparser.statement.merge;
2+
3+
/**
4+
* Marker interface to cover {@link MergeDelete}, {@link MergeUpdate} and {@link MergeInsert}
5+
*/
6+
public interface MergeOperation {
7+
void accept(MergeOperationVisitor mergeOperationVisitor);
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package net.sf.jsqlparser.statement.merge;
2+
3+
public interface MergeOperationVisitor {
4+
5+
void visit(MergeDelete mergeDelete);
6+
7+
void visit(MergeUpdate mergeUpdate);
8+
9+
void visit(MergeInsert mergeInsert);
10+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package net.sf.jsqlparser.statement.merge;
2+
3+
@SuppressWarnings({"PMD.UncommentedEmptyMethodBody"})
4+
public class MergeOperationVisitorAdapter implements MergeOperationVisitor {
5+
@Override
6+
public void visit(MergeDelete mergeDelete) {
7+
8+
}
9+
10+
@Override
11+
public void visit(MergeUpdate mergeUpdate) {
12+
13+
}
14+
15+
@Override
16+
public void visit(MergeInsert mergeInsert) {
17+
18+
}
19+
}

src/main/java/net/sf/jsqlparser/statement/merge/MergeUpdate.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import java.io.Serializable;
1616
import java.util.List;
1717

18-
public class MergeUpdate implements Serializable {
18+
public class MergeUpdate implements Serializable, MergeOperation {
1919

2020
private List<UpdateSet> updateSets;
2121
private Expression andPredicate;
@@ -61,6 +61,11 @@ public void setDeleteWhereCondition(Expression deleteWhereCondition) {
6161
this.deleteWhereCondition = deleteWhereCondition;
6262
}
6363

64+
@Override
65+
public void accept(MergeOperationVisitor mergeOperationVisitor) {
66+
mergeOperationVisitor.visit(this);
67+
}
68+
6469
@Override
6570
public String toString() {
6671
StringBuilder b = new StringBuilder();
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package net.sf.jsqlparser.util.deparser;
2+
3+
import net.sf.jsqlparser.statement.merge.*;
4+
import net.sf.jsqlparser.statement.select.WithItem;
5+
6+
import java.util.Iterator;
7+
import java.util.List;
8+
9+
public class MergeDeParser extends AbstractDeParser<Merge> implements MergeOperationVisitor {
10+
private final ExpressionDeParser expressionDeParser;
11+
12+
private final SelectDeParser selectDeParser;
13+
14+
public MergeDeParser(ExpressionDeParser expressionDeParser, SelectDeParser selectDeParser,
15+
StringBuilder buffer) {
16+
super(buffer);
17+
this.expressionDeParser = expressionDeParser;
18+
this.selectDeParser = selectDeParser;
19+
}
20+
21+
@Override
22+
void deParse(Merge merge) {
23+
List<WithItem> withItemsList = merge.getWithItemsList();
24+
if (withItemsList != null && !withItemsList.isEmpty()) {
25+
buffer.append("WITH ");
26+
for (Iterator<WithItem> iter = withItemsList.iterator(); iter.hasNext();) {
27+
iter.next().accept(expressionDeParser);
28+
if (iter.hasNext()) {
29+
buffer.append(",");
30+
}
31+
buffer.append(" ");
32+
}
33+
}
34+
35+
buffer.append("MERGE ");
36+
if (merge.getOracleHint() != null) {
37+
buffer.append(merge.getOracleHint()).append(" ");
38+
}
39+
buffer.append("INTO ");
40+
merge.getTable().accept(selectDeParser);
41+
42+
buffer.append(" USING ");
43+
merge.getFromItem().accept(selectDeParser);
44+
45+
buffer.append(" ON ");
46+
merge.getOnCondition().accept(expressionDeParser);
47+
48+
List<MergeOperation> operations = merge.getOperations();
49+
if (operations != null && !operations.isEmpty()) {
50+
operations.forEach(operation -> operation.accept(this));
51+
}
52+
53+
if (merge.getOutputClause() != null) {
54+
merge.getOutputClause().appendTo(buffer);
55+
}
56+
}
57+
58+
@Override
59+
public void visit(MergeDelete mergeDelete) {
60+
buffer.append(" WHEN MATCHED");
61+
if (mergeDelete.getAndPredicate() != null) {
62+
buffer.append(" AND ");
63+
mergeDelete.getAndPredicate().accept(expressionDeParser);
64+
}
65+
buffer.append(" THEN DELETE");
66+
}
67+
68+
@Override
69+
public void visit(MergeUpdate mergeUpdate) {
70+
buffer.append(" WHEN MATCHED");
71+
if (mergeUpdate.getAndPredicate() != null) {
72+
buffer.append(" AND ");
73+
mergeUpdate.getAndPredicate().accept(expressionDeParser);
74+
}
75+
buffer.append(" THEN UPDATE SET ");
76+
deparseUpdateSets(mergeUpdate.getUpdateSets(), buffer, expressionDeParser);
77+
78+
if (mergeUpdate.getWhereCondition() != null) {
79+
buffer.append(" WHERE ");
80+
mergeUpdate.getWhereCondition().accept(expressionDeParser);
81+
}
82+
83+
if (mergeUpdate.getDeleteWhereCondition() != null) {
84+
buffer.append(" DELETE WHERE ");
85+
mergeUpdate.getDeleteWhereCondition().accept(expressionDeParser);
86+
}
87+
}
88+
89+
@Override
90+
public void visit(MergeInsert mergeInsert) {
91+
buffer.append(" WHEN NOT MATCHED");
92+
if (mergeInsert.getAndPredicate() != null) {
93+
buffer.append(" AND ");
94+
mergeInsert.getAndPredicate().accept(expressionDeParser);
95+
}
96+
buffer.append(" THEN INSERT ");
97+
if (mergeInsert.getColumns() != null) {
98+
mergeInsert.getColumns().accept(expressionDeParser);
99+
}
100+
buffer.append(" VALUES ");
101+
mergeInsert.getValues().accept(expressionDeParser);
102+
103+
if (mergeInsert.getWhereCondition() != null) {
104+
buffer.append(" WHERE ");
105+
mergeInsert.getWhereCondition().accept(expressionDeParser);
106+
}
107+
}
108+
109+
}

0 commit comments

Comments
 (0)