From 2f8f293ed23d8a173a6b15ab663e00c66a408733 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Mon, 21 May 2018 01:05:53 -0400 Subject: [PATCH] Refactor BindInList, split out to InListUtil, add unit tests --- common/pom.xml | 7 ++ .../moparisthebest/jdbc/util/InListUtil.java | 59 +++++++++++++ .../jdbc/util/InListUtilTest.java | 87 +++++++++++++++++++ .../com/moparisthebest/jdbc/BindInList.java | 48 +--------- 4 files changed, 156 insertions(+), 45 deletions(-) create mode 100644 common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java create mode 100644 common/src/test/java/com/moparisthebest/jdbc/util/InListUtilTest.java diff --git a/common/pom.xml b/common/pom.xml index ae7fc5a..f1635dd 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -8,6 +8,13 @@ common ${project.artifactId} + + + junit + junit + test + + ${project.artifactId} diff --git a/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java new file mode 100644 index 0000000..e2eeee8 --- /dev/null +++ b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java @@ -0,0 +1,59 @@ +package com.moparisthebest.jdbc.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class InListUtil { + + private static List> split(final List list, final int maxLength) { + final int listSize = list.size(); + final List> ret = new ArrayList>(); + if (listSize < maxLength) + ret.add(list); + else + for (int fromIndex = 0, toIndex = maxLength; fromIndex < listSize; fromIndex = toIndex, toIndex += maxLength) + ret.add(list.subList(fromIndex, toIndex > listSize ? listSize : toIndex)); + return ret; + } + + private static StringBuilder buildCommaSeparatedList(final Iterable list, final StringBuilder sb) { + boolean notFirst = false; + for (final T obj : list) { + if (notFirst) sb.append(','); + else notFirst = true; + sb.append('?'); + } + return sb; + } + + private static StringBuilder buildInList(final Iterable list, final StringBuilder sb, final String fieldName, final String listPrefix) { + return buildCommaSeparatedList(list, sb.append(fieldName).append(listPrefix)).append(")"); + } + + private static String toInList(final String fieldName, final Collection items, final int maxSize, final String listPrefix, final String listCombine) { + final StringBuilder sb = new StringBuilder("("); + + // do it quick if it will fit in one in-list + if (items.size() < maxSize) // 999 or less + return buildInList(items, sb, fieldName, listPrefix).append(")").toString(); + + // else we need to split lists + boolean notFirst = false; + for (final List item : split(items instanceof List ? (List) items : new ArrayList(items), maxSize)) { + if (notFirst) sb.append(listCombine); + else notFirst = true; + buildInList(item, sb, fieldName, listPrefix); + } + + return sb.append(")").toString(); + } + + public static String toInList(final String fieldName, final Collection items, final int maxSize) { + return toInList(fieldName, items, maxSize, " IN (", " OR "); + } + + public static String toNotInList(final String fieldName, final Collection items, final int maxSize) { + return toInList(fieldName, items, maxSize, " NOT IN (", " AND "); + } +} diff --git a/common/src/test/java/com/moparisthebest/jdbc/util/InListUtilTest.java b/common/src/test/java/com/moparisthebest/jdbc/util/InListUtilTest.java new file mode 100644 index 0000000..73effd8 --- /dev/null +++ b/common/src/test/java/com/moparisthebest/jdbc/util/InListUtilTest.java @@ -0,0 +1,87 @@ +package com.moparisthebest.jdbc.util; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +import static com.moparisthebest.jdbc.util.InListUtil.toInList; +import static com.moparisthebest.jdbc.util.InListUtil.toNotInList; +import static org.junit.Assert.assertEquals; + +public class InListUtilTest { + + private static Collection makeCollection(final int length) { + final Collection ret = new ArrayList(length); + final int loopLength = length + 1; + for(int x = 1; x < loopLength; ++x) + ret.add((long) x); + return ret; + } + + @Test + public void testMakeCollection() { + assertEquals(new ArrayList(Arrays.asList(1L, 2L, 3L)), makeCollection(3)); + } + + @Test + public void testShortInList() { + assertEquals("(column_name IN (?,?,?,?,?))", toInList("column_name", makeCollection(5), 20)); + } + + @Test + public void testShortNotInList() { + assertEquals("(column_name NOT IN (?,?,?,?,?))", toNotInList("column_name", makeCollection(5), 20)); + } + + @Test + public void testExactInList() { + assertEquals("(column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?))", + toInList("column_name", makeCollection(20), 20)); + } + + @Test + public void testExactNotInList() { + assertEquals("(column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?))", + toNotInList("column_name", makeCollection(20), 20)); + } + + @Test + public void testOneOverInList() { + assertEquals("(column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) OR column_name IN (?))", + toInList("column_name", makeCollection(21), 20)); + } + + @Test + public void testOneOverNotInList() { + assertEquals("(column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) AND column_name NOT IN (?))", + toNotInList("column_name", makeCollection(21), 20)); + } + + @Test + public void testOneUnderInList() { + assertEquals("(column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?))", + toInList("column_name", makeCollection(19), 20)); + } + + @Test + public void testOneUnderNotInList() { + assertEquals("(column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?))", + toNotInList("column_name", makeCollection(19), 20)); + } + + @Test + public void testOneOver3InList() { + assertEquals("(column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) OR column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) " + + "OR column_name IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) OR column_name IN (?))", + toInList("column_name", makeCollection(61), 20)); + } + + @Test + public void testOneOver3NotInList() { + assertEquals("(column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) AND column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) " + + "AND column_name NOT IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) AND column_name NOT IN (?))", + toNotInList("column_name", makeCollection(61), 20)); + } +} diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java index 80f4288..370f2a0 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java @@ -3,6 +3,8 @@ package com.moparisthebest.jdbc; import java.sql.Connection; import java.util.*; +import static com.moparisthebest.jdbc.util.InListUtil.toInList; + /** * Created by mopar on 4/29/15. */ @@ -26,53 +28,9 @@ public class BindInList implements InList { this(defaultMaxSize); } - private static List> split(final List list, final int maxLength) { - final int listSize = list.size(); - final List> ret = new ArrayList>(); - if (listSize < maxLength) - ret.add(list); - else - for (int fromIndex = 0, toIndex = maxLength; fromIndex < listSize; fromIndex = toIndex, toIndex += maxLength) - ret.add(list.subList(fromIndex, toIndex > listSize ? listSize : toIndex)); - return ret; - } - - private String toInList(final String fieldName, final Collection items) { - final StringBuilder sb = new StringBuilder("("); - - // do it quick if it will fit in one in-list - if (items.size() < maxSize) // 999 or less - return buildInList(items, sb, fieldName).append(")").toString(); - - // else we need to split lists - boolean notFirst = false; - for (final List item : split(new ArrayList(items), maxSize)) { - if (notFirst) sb.append(" OR "); - else notFirst = true; - buildInList(item, sb, fieldName); - } - - return sb.append(")").toString(); - } - - private static StringBuilder buildInList(Iterable list, StringBuilder sb, String fieldName) { - return oracleCommaSeparatedList(list, sb.append(fieldName).append(" IN (")).append(")"); - } - - private static StringBuilder oracleCommaSeparatedList(Iterable list, StringBuilder sb) { - boolean notFirst = false; - for (final T obj : list) { - // DO NOT DO THIS ANYMORE: if (obj == null) continue; - if (notFirst) sb.append(','); - else notFirst = true; - sb.append('?'); - } - return sb; - } - public InListObject inList(final Connection conn, final String columnName, final Collection values) { return values == null || values.isEmpty() ? InListObject.empty : new BindInListObject( - toInList(columnName, values), + toInList(columnName, values, this.maxSize), values.toArray() ); }