Skip to content

Commit

Permalink
Add support method for generating dynamic sql on SQL class
Browse files Browse the repository at this point in the history
* applyIf
* applyForEach
  • Loading branch information
kazuki43zoo committed Jun 11, 2023
1 parent c060395 commit bc050f2
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 0 deletions.
94 changes: 94 additions & 0 deletions src/main/java/org/apache/ibatis/jdbc/AbstractSQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

/**
* @author Clinton Begin
Expand Down Expand Up @@ -526,6 +528,71 @@ public <A extends Appendable> A usingAppender(A a) {
return a;
}

/**
* Apply sql phrases that provide by SQL consumer if condition is matches.
*
* @param applyCondition
* if {@code true} apply sql phrases
* @param sqlConsumer
* a consumer that append sql phrase to SQL instance
*
* @return a self instance
*
* @see #applyIf(BooleanSupplier, Consumer)
*
* @since 3.5.14
*/
public T applyIf(boolean applyCondition, Consumer<T> sqlConsumer) {
T self = getSelf();
if (applyCondition) {
sqlConsumer.accept(self);
}
return self;
}

/**
* Apply sql phrases that provide by SQL consumer if condition is matches.
*
* @param applyConditionSupplier
* if supplier return {@code true} apply sql phrases
* @param sqlConsumer
* a consumer that append sql phrase to SQL instance
*
* @return a self instance
*
* @see #applyIf(boolean, Consumer)
*
* @since 3.5.14
*/
public T applyIf(BooleanSupplier applyConditionSupplier, Consumer<T> sqlConsumer) {
return applyIf(applyConditionSupplier.getAsBoolean(), sqlConsumer);
}

/**
* Apply sql phrases that provide by SQL consumer for iterable.
*
* @param iterable
* an iterable
* @param forEachSqlConsumer
* a consumer that append sql phrase to SQL instance
*
* @return a self instance
*
* @param <E>
* element type of iterable
*
* @since 3.5.14
*/
public <E> T applyForEach(Iterable<E> iterable, ForEachConsumer<T, E> forEachSqlConsumer) {
T self = getSelf();
int elementIndex = 0;
for (E element : iterable) {
forEachSqlConsumer.accept(self, element, elementIndex);
elementIndex++;
}
return self;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expand Down Expand Up @@ -737,4 +804,31 @@ public String sql(Appendable a) {
return answer;
}
}

/**
* Consumer for 'forEach' operation.
*
* @param <T>
* SQL type
* @param <E>
* Element type of iterable
*
* @since 3.5.14
*/
public interface ForEachConsumer<T, E> {

/**
* Accept an iterable element with index.
*
* @param sql
* SQL instance
* @param element
* an iterable element
* @param elementIndex
* an element index
*/
void accept(T sql, E element, int elementIndex);

}

}
51 changes: 51 additions & 0 deletions src/test/java/org/apache/ibatis/jdbc/SQLTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.List;

import org.junit.jupiter.api.Test;

class SQLTest {
Expand Down Expand Up @@ -499,4 +502,52 @@ void testValues() {
assertThat(sql).isEqualToIgnoringWhitespace(
"INSERT INTO PERSON (ID, FIRST_NAME, LAST_NAME) VALUES (#{id}, #{firstName}, #{lastName})");
}

@Test
void testApplyIf() {
Bean bean = new Bean();
// @formatter:off
String sqlString = new SQL()
.UPDATE("test")
.applyIf(bean.a != null, sql -> sql.SET("a=#{a}"))
.applyIf(bean.b != null, sql -> sql.SET("b=#{b}"))
.applyIf(bean::hasC, sql -> sql.SET("c=#{c}"))
.WHERE("id=#{id}").toString();
// @formatter:on

assertThat(sqlString).isEqualToIgnoringWhitespace("UPDATE test SET a=#{a} WHERE (id=#{id})");
}

@Test
void testApplyForEach() {
List<Bean> beans = new ArrayList<>();
beans.add(new Bean());
beans.add(new Bean());

// @formatter:off
String sqlString = new SQL()
.INSERT_INTO("test")
.INTO_COLUMNS("a", "b", "c")
.applyForEach(beans, (sql, element, index) ->
sql.INTO_VALUES(
String.format("#{list[%s].a}", index),
String.format("#{list[%s].b}", index),
String.format("#{list[%s].c}", index)
).ADD_ROW())
.toString();
// @formatter:on

assertThat(sqlString).isEqualToIgnoringWhitespace(
"INSERT INTO test (a, b, c) VALUES (#{list[0].a}, #{list[0].b}, #{list[0].c}), (#{list[1].a}, #{list[1].b}, #{list[1].c})");
}

static class Bean {
private String a = "foo";
private String b;
private String c;

boolean hasC() {
return c != null;
}
}
}

0 comments on commit bc050f2

Please sign in to comment.