diff --git a/README.md b/README.md index ca2b577..74dde6c 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Stream users = db.select("SELECT * FROM HUGE_TABLE") .execute((batch, session) -> { // list of mapped rows (to resulting type) with size not more than 1000 // session maps to currently used connection - Map attrs = session.select("SELECT * FROM USER_ATTR WHERE id IN (:ids)", batch.stream().map(User::getId).collect(Collectors.toList())) + Map attrs = session.select("SELECT * FROM USER_ATTR WHERE id IN (:ids)", entry("ids", batch.stream().map(User::getId).collect(Collectors.toList()))) .execute(/* map to collection of domain objects that represents a user attribute */) .groupingBy(UserAttr::userId, Function::identity); batch.forEach(user -> user.addAttrs(attrs.getOrDefault(user.getId, Collections.emptyList()))); diff --git a/src/main/java/buckelieg/jdbc/DefaultConnectionManager.java b/src/main/java/buckelieg/jdbc/DefaultConnectionManager.java index ffe67a5..ca1272b 100644 --- a/src/main/java/buckelieg/jdbc/DefaultConnectionManager.java +++ b/src/main/java/buckelieg/jdbc/DefaultConnectionManager.java @@ -21,10 +21,10 @@ import javax.annotation.Nullable; import java.sql.Connection; import java.sql.SQLException; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -46,7 +46,7 @@ final class DefaultConnectionManager implements ConnectionManager { this.connectionSupplier = connectionSupplier; this.maxConnections = maxConnections; this.pool = new ArrayBlockingQueue<>(maxConnections); - this.obtainedConnections = new ArrayList<>(maxConnections); + this.obtainedConnections = new CopyOnWriteArrayList<>(); } @Nonnull diff --git a/src/main/java/buckelieg/jdbc/fn/TryPredicate.java b/src/main/java/buckelieg/jdbc/fn/TryPredicate.java index 620d68f..b7264c2 100644 --- a/src/main/java/buckelieg/jdbc/fn/TryPredicate.java +++ b/src/main/java/buckelieg/jdbc/fn/TryPredicate.java @@ -134,7 +134,7 @@ default TryPredicate or(TryPredicate other) throws E { * @throws E an arbitrary exception */ static TryPredicate isEqual(Object targetRef) throws E { - return ref -> Objects.equals(ref, targetRef); + return (null == targetRef) ? Objects::isNull : ref -> Objects.equals(ref, targetRef); } /** diff --git a/src/test/java/buckelieg/jdbc/FNTests.java b/src/test/java/buckelieg/jdbc/FNTests.java new file mode 100644 index 0000000..c89b9b6 --- /dev/null +++ b/src/test/java/buckelieg/jdbc/FNTests.java @@ -0,0 +1,142 @@ +package buckelieg.jdbc; + +import buckelieg.jdbc.fn.*; +import org.junit.jupiter.api.Test; +import org.opentest4j.AssertionFailedError; + +import static org.junit.jupiter.api.Assertions.*; + +public class FNTests { + + @Test + public void testTryFunction() throws Exception { + TryFunction fn = TryFunction.of(TryFunction.identity()); + assertEquals(1, fn.apply(1)); + assertEquals(2, fn.andThen(i -> i * 2).apply(1)); + assertEquals(0, fn.compose(i -> i - 1).apply(1)); + assertThrows(NullPointerException.class, () -> fn.andThen(null).apply(1)); + assertThrows(NullPointerException.class, () -> fn.compose(null).apply(1)); + } + + @Test + public void testTryBiFunction() throws Exception { + TryBiFunction fn = TryBiFunction.of(Integer::sum); + assertEquals(3, fn.apply(1, 2)); + assertEquals(6, fn.andThen(sum -> sum * 2).apply(1, 2)); + assertThrows(NullPointerException.class, () -> fn.andThen(null).apply(1, 2)); + } + + @Test + public void testTryTriFunction() throws Exception { + TryTriFunction fn = TryTriFunction.of((i1, i2, i3) -> i1 + i2 + i3); + assertEquals(6, fn.apply(1, 2, 3)); + assertEquals(18, fn.andThen(sum -> sum * 3).apply(1, 2, 3)); + assertThrows(NullPointerException.class, () -> fn.andThen(null).apply(1, 2, 3)); + } + + @Test + public void testTryQuadFunction() throws Exception { + TryQuadFunction fn = TryQuadFunction.of((i1, i2, i3, i4) -> i1 + i2 + i3 + i4); + assertEquals(10, fn.apply(1, 2, 3, 4)); + assertEquals(40, fn.andThen(sum -> sum * 4).apply(1, 2, 3, 4)); + assertThrows(NullPointerException.class, () -> fn.andThen(null).apply(1, 2, 3, 4)); + } + + @Test + public void testTryRunnable() throws Exception { + TryRunnable fn = TryRunnable.of(() -> assertInstanceOf(TryRunnable.class, this)); + assertThrows(AssertionFailedError.class, fn::run); + assertEquals(TryRunnable.NOOP, TryRunnable.NOOP()); + } + + @Test + public void testTrySupplier() throws Exception { + TrySupplier fn = TrySupplier.of(() -> 5); + assertEquals(5, fn.get()); + } + + @Test + public void testTryConsumer() throws Exception { + TryConsumer fn = TryConsumer.of(TryConsumer.NOOP()) + .compose(integer -> assertEquals(integer, 1)) + .andThen(integer -> assertEquals(integer, 1)); + fn.accept(1); + assertThrows(NullPointerException.class, () -> fn.andThen(null).accept(1)); + assertThrows(NullPointerException.class, () -> fn.compose(null).accept(1)); + assertEquals(TryConsumer.NOOP, TryConsumer.NOOP()); + } + + @Test + public void testTryBiConsumer() throws Exception { + TryBiConsumer fn = TryBiConsumer.of(TryBiConsumer.NOOP()); + fn.andThen((i1, i2) -> { + assertEquals(i1, 1); + assertEquals(i2, 2); + }).accept(1, 2); + assertThrows(NullPointerException.class, () -> fn.andThen(null).accept(1, 2)); + assertEquals(TryBiConsumer.NOOP, TryBiConsumer.NOOP()); + } + + @Test + public void testTryTriConsumer() throws Exception { + TryTriConsumer fn = TryTriConsumer.of((i1, i2, i3) -> { + assertEquals(i1, 1); + assertEquals(i2, 2); + assertEquals(i3, 3); + }); + fn.accept(1, 2, 3); + assertEquals(TryTriConsumer.NOOP, TryTriConsumer.NOOP()); + } + + @Test + public void testTryQuadConsumer() throws Exception { + TryQuadConsumer fn = TryQuadConsumer.of((i1, i2, i3, i4) -> { + assertEquals(i1, 1); + assertEquals(i2, 2); + assertEquals(i3, 3); + assertEquals(i4, 4); + }); + fn.accept(1, 2, 3, 4); + assertEquals(TryQuadConsumer.NOOP, TryQuadConsumer.NOOP()); + } + + @Test + public void testTryPredicate() throws Exception { + TryPredicate fn = TryPredicate.of(TryPredicate.FALSE()); + assertTrue(fn.negate().test(1)); + assertFalse(fn.test(1)); + assertEquals(TryPredicate.TRUE, TryPredicate.TRUE()); + assertEquals(TryPredicate.FALSE, TryPredicate.FALSE()); + assertTrue(TryPredicate.TRUE().or(TryPredicate.TRUE()).test(1)); + assertFalse(TryPredicate.FALSE().or(TryPredicate.FALSE()).test(1)); + assertFalse(TryPredicate.TRUE().and(TryPredicate.FALSE()).test(1)); + assertFalse(fn.and(TryPredicate.TRUE()).test(1)); + assertTrue(TryPredicate.not(TryPredicate.FALSE()).test(1)); + assertFalse(TryPredicate.not(TryPredicate.TRUE()).test(1)); + assertTrue(TryPredicate.isEqual(fn).test(fn)); + assertFalse(TryPredicate.isEqual(fn).test(TryPredicate.TRUE())); + assertFalse(TryPredicate.isEqual(null).test(fn)); + assertThrows(NullPointerException.class, () -> TryPredicate.not(null).test(1)); + assertThrows(NullPointerException.class, () -> TryPredicate.of(null).test(1)); + assertThrows(NullPointerException.class, () -> fn.or(null).test(1)); + assertThrows(NullPointerException.class, () -> fn.and(null).test(1)); + } + + @Test + public void testTryBiPredicate() throws Exception { + TryBiPredicate fn = TryBiPredicate.of(TryBiPredicate.FALSE()); + assertTrue(fn.negate().test(1, 2)); + assertFalse(fn.test(1, 2)); + assertEquals(TryPredicate.TRUE, TryPredicate.TRUE()); + assertEquals(TryPredicate.FALSE, TryPredicate.FALSE()); + assertTrue(TryBiPredicate.TRUE().or(TryBiPredicate.TRUE()).test(1, 2)); + assertFalse(TryBiPredicate.FALSE().or(TryBiPredicate.FALSE()).test(1, 2)); + assertFalse(TryBiPredicate.TRUE().and(TryBiPredicate.FALSE()).test(1, 2)); + assertFalse(fn.and(TryBiPredicate.TRUE()).test(1, 2)); + assertThrows(NullPointerException.class, () -> TryPredicate.not(null).test(1)); + assertThrows(NullPointerException.class, () -> TryPredicate.of(null).test(1)); + assertThrows(NullPointerException.class, () -> fn.or(null).test(1, 1)); + assertThrows(NullPointerException.class, () -> fn.and(null).test(1, 2)); + } + +}