Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
fix: readd standard fields and add compatibility logic
  • Loading branch information
davidjgoss committed Jan 5, 2024
commit 49115da64b52476dd143771d9ab66b763aa0d7ed
97 changes: 71 additions & 26 deletions src/main/java/net/sf/jsqlparser/statement/merge/Merge.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class Merge implements Statement {

Expand All @@ -34,10 +35,46 @@ public class Merge implements Statement {
private OracleHint oracleHint = null;
private FromItem fromItem;
private Expression onCondition;
private MergeInsert mergeInsert;
private MergeUpdate mergeUpdate;
private boolean insertFirst = false;
private List<MergeOperation> operations;

private OutputClause outputClause;

private void deriveOperationsFromStandardClauses() {
List<MergeOperation> operations = new ArrayList<>();
if (insertFirst) {
Optional.ofNullable(mergeInsert).ifPresent(operations::add);
Optional.ofNullable(mergeUpdate).ifPresent(operations::add);
} else {
Optional.ofNullable(mergeUpdate).ifPresent(operations::add);
Optional.ofNullable(mergeInsert).ifPresent(operations::add);
}
this.operations = operations;
}

private void deriveStandardClausesFromOperations() {
List<MergeOperation> applicableOperations =
Optional.ofNullable(operations).orElse(Collections.emptyList()).stream()
.filter(o -> o instanceof MergeUpdate || o instanceof MergeInsert)
.collect(Collectors.toList());
mergeUpdate = applicableOperations.stream()
.filter(o -> o instanceof MergeUpdate)
.map(MergeUpdate.class::cast)
.findFirst()
.orElse(null);
mergeInsert = applicableOperations.stream()
.filter(o -> o instanceof MergeInsert)
.map(MergeInsert.class::cast)
.findFirst()
.orElse(null);
insertFirst = applicableOperations.stream()
.findFirst()
.map(o -> o instanceof MergeInsert)
.orElse(false);
}

public List<WithItem> getWithItemsList() {
return withItemsList;
}
Expand Down Expand Up @@ -133,46 +170,39 @@ public List<MergeOperation> getOperations() {

public void setOperations(List<MergeOperation> operations) {
this.operations = operations;
deriveStandardClausesFromOperations();
}

/**
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
*/
@Deprecated
public MergeInsert getMergeInsert() {
return operations.stream()
.filter(MergeInsert.class::isInstance)
.findFirst()
.map(MergeInsert.class::cast)
.orElse(null);
return mergeInsert;
}

public void setMergeInsert(MergeInsert mergeInsert) {
this.mergeInsert = mergeInsert;
deriveOperationsFromStandardClauses();
}

/**
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
*/
@Deprecated
public MergeUpdate getMergeUpdate() {
return operations.stream()
.filter(MergeUpdate.class::isInstance)
.findFirst()
.map(MergeUpdate.class::cast)
.orElse(null);
return mergeUpdate;
}

public void setMergeUpdate(MergeUpdate mergeUpdate) {
this.mergeUpdate = mergeUpdate;
deriveOperationsFromStandardClauses();
}

@Override
public void accept(StatementVisitor statementVisitor) {
statementVisitor.visit(this);
}

/**
* @deprecated use {@link #getOperations()} or consider a {@link MergeOperationVisitor} instead
*/
@Deprecated
public boolean isInsertFirst() {
if (operations == null || operations.isEmpty()) {
return false;
}
return operations.get(0) instanceof MergeInsert;
return insertFirst;
}

public void setInsertFirst(boolean insertFirst) {
this.insertFirst = insertFirst;
deriveOperationsFromStandardClauses();
}

public OutputClause getOutputClause() {
Expand Down Expand Up @@ -244,11 +274,26 @@ public Merge withOnCondition(Expression onCondition) {
return this;
}

public Merge withMergeUpdate(MergeUpdate mergeUpdate) {
this.setMergeUpdate(mergeUpdate);
return this;
}

public Merge withInsertFirst(boolean insertFirst) {
this.setInsertFirst(insertFirst);
return this;
}

public Merge withTable(Table table) {
this.setTable(table);
return this;
}

public Merge withMergeInsert(MergeInsert mergeInsert) {
this.setMergeInsert(mergeInsert);
return this;
}

public <E extends Expression> E getOnCondition(Class<E> type) {
return type.cast(getOnCondition());
}
Expand Down
70 changes: 67 additions & 3 deletions src/test/java/net/sf/jsqlparser/statement/merge/MergeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,20 @@
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists;
import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

/**
*
Expand Down Expand Up @@ -153,10 +162,10 @@ public void testInsertMergeWhere() throws JSQLParserException {

Merge merge = (Merge) statement;
MergeInsert mergeInsert = merge.getMergeInsert();
Assertions.assertThat(mergeInsert.getWhereCondition());
assertThat(mergeInsert.getWhereCondition());

MergeUpdate mergeUpdate = merge.getMergeUpdate();
Assertions.assertThat(mergeUpdate.getWhereCondition());
assertThat(mergeUpdate.getWhereCondition());
}

@Test
Expand Down Expand Up @@ -266,4 +275,59 @@ void testSnowflakeMergeStatementWithManyWhensAndDelete() throws JSQLParserExcept

assertSqlCanBeParsedAndDeparsed(sql, true);
}

@ParameterizedTest
@MethodSource("deriveOperationsFromStandardClausesCases")
void testDeriveOperationsFromStandardClauses(List<MergeOperation> expectedOperations,
MergeUpdate update, MergeInsert insert, boolean insertFirst) {
Merge merge = new Merge();
merge.setMergeUpdate(update);
merge.setMergeInsert(insert);
merge.setInsertFirst(insertFirst);

assertThat(merge.getOperations()).isEqualTo(expectedOperations);
}

private static Stream<Arguments> deriveOperationsFromStandardClausesCases() {
MergeUpdate update = mock(MergeUpdate.class);
MergeInsert insert = mock(MergeInsert.class);

return Stream.of(
Arguments.of(Arrays.asList(update, insert), update, insert, false),
Arguments.of(Arrays.asList(insert, update), update, insert, true));
}

@ParameterizedTest
@MethodSource("deriveStandardClausesFromOperationsCases")
void testDeriveStandardClausesFromOperations(List<MergeOperation> operations,
MergeUpdate expectedUpdate, MergeInsert expectedInsert, boolean expectedInsertFirst) {
Merge merge = new Merge();
merge.setOperations(operations);

assertThat(merge.getMergeUpdate()).isEqualTo(expectedUpdate);
assertThat(merge.getMergeInsert()).isEqualTo(expectedInsert);
assertThat(merge.isInsertFirst()).isEqualTo(expectedInsertFirst);
}

private static Stream<Arguments> deriveStandardClausesFromOperationsCases() {
MergeDelete delete1 = mock(MergeDelete.class);
MergeUpdate update1 = mock(MergeUpdate.class);
MergeUpdate update2 = mock(MergeUpdate.class);
MergeInsert insert1 = mock(MergeInsert.class);
MergeInsert insert2 = mock(MergeInsert.class);

return Stream.of(
// just the two standard clauses present
Arguments.of(Arrays.asList(update1, insert1), update1, insert1, false),
Arguments.of(Arrays.asList(insert1, update1), update1, insert1, true),
// some clause(s) missing
Arguments.of(Collections.singletonList(update1), update1, null, false),
Arguments.of(Collections.singletonList(insert1), null, insert1, true),
Arguments.of(Collections.emptyList(), null, null, false),
// many clauses (non-standard)
Arguments.of(Arrays.asList(update1, update2, delete1, insert1, insert2), update1,
insert1, false),
Arguments.of(Arrays.asList(insert1, insert2, update1, update2, delete1), update1,
insert1, true));
}
}