diff --git a/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java index 39268b8..0308db1 100644 --- a/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java +++ b/common/src/main/java/com/moparisthebest/jdbc/util/InListUtil.java @@ -73,7 +73,7 @@ public class InListUtil { } public static String toNotInList(final String fieldName, final Collection items) { - return toInList(fieldName, items, defaultMaxSize); + return toNotInList(fieldName, items, defaultMaxSize); } public static String toInList(final String fieldName, final T[] items) { @@ -81,6 +81,6 @@ public class InListUtil { } public static String toNotInList(final String fieldName, final T[] items) { - return toInList(fieldName, Arrays.asList(items), defaultMaxSize); + return toNotInList(fieldName, Arrays.asList(items), defaultMaxSize); } } diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/ArrayInList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/ArrayInList.java index ca0f5fa..879782f 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/ArrayInList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/ArrayInList.java @@ -29,10 +29,14 @@ public class ArrayInList implements InList { this(JdbcMapper.DatabaseType.ANY.arrayNumberTypeName, JdbcMapper.DatabaseType.ANY.arrayStringTypeName); } - protected String columnAppend(final String columnName) { + protected String columnAppendIn(final String columnName) { return "(" + columnName + " = ANY(?))"; } + protected String columnAppendNotIn(final String columnName) { + return "(" + columnName + " != ANY(?))"; + } + public Array toArray(final Connection conn, final String typeName, final Object[] elements) throws SQLException { return conn.createArrayOf(typeName, elements); } @@ -46,8 +50,15 @@ public class ArrayInList implements InList { } public InListObject inList(final Connection conn, final String columnName, final Collection values) throws SQLException { - return values == null || values.isEmpty() ? InListObject.empty : new ArrayListObject( - columnAppend(columnName), + return values == null || values.isEmpty() ? InListObject.inEmpty : new ArrayListObject( + columnAppendIn(columnName), + toArray(conn, values) + ); + } + + public InListObject notInList(final Connection conn, final String columnName, final Collection values) throws SQLException { + return values == null || values.isEmpty() ? InListObject.notInEmpty : new ArrayListObject( + columnAppendNotIn(columnName), toArray(conn, values) ); } diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java index 13862ec..2d8b50a 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/BindInList.java @@ -5,6 +5,7 @@ import java.util.*; import static com.moparisthebest.jdbc.util.InListUtil.defaultMaxSize; import static com.moparisthebest.jdbc.util.InListUtil.toInList; +import static com.moparisthebest.jdbc.util.InListUtil.toNotInList; /** * Created by mopar on 4/29/15. @@ -28,12 +29,19 @@ public class BindInList implements InList { } public InListObject inList(final Connection conn, final String columnName, final Collection values) { - return values == null || values.isEmpty() ? InListObject.empty : new BindInListObject( + return values == null || values.isEmpty() ? InListObject.inEmpty : new BindInListObject( toInList(columnName, values, this.maxSize), values.toArray() ); } + public InListObject notInList(final Connection conn, final String columnName, final Collection values) { + return values == null || values.isEmpty() ? InListObject.notInEmpty : new BindInListObject( + toNotInList(columnName, values, this.maxSize), + values.toArray() + ); + } + class BindInListObject extends InListObject { private final Object[] bindObjects; diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java index 16e9ab7..e5027fe 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/InList.java @@ -18,8 +18,17 @@ public interface InList { */ public InListObject inList(final Connection conn, final String columnName, final Collection values) throws SQLException; + /** + * Returns an Object who's .toString returns a String for a query, and QueryMapper knows how to bind to a PreparedStatement + * @param columnName Column name for query + * @param values values for not in list + * @return object + */ + public InListObject notInList(final Connection conn, final String columnName, final Collection values) throws SQLException; + class InListObject { - static final InListObject empty = new InListObject("(0=1)"); + static final InListObject inEmpty = new InListObject("(0=1)"); + static final InListObject notInEmpty = new InListObject("(1=1)"); private final String sql; diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java index 4b130d1..e1bf46e 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/ListQueryMapper.java @@ -109,6 +109,10 @@ public class ListQueryMapper extends QueryMapper { return this.inList.inList(delegate.conn, columnName, values); } + public InList.InListObject notInList(final String columnName, final Collection values) throws SQLException { + return this.inList.notInList(delegate.conn, columnName, values); + } + // these update the database @Override diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/OracleArrayInList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/OracleArrayInList.java index ca894e4..2d22c2e 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/OracleArrayInList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/OracleArrayInList.java @@ -44,10 +44,14 @@ public class OracleArrayInList extends ArrayInList { this(JdbcMapper.DatabaseType.ORACLE.arrayNumberTypeName, JdbcMapper.DatabaseType.ORACLE.arrayStringTypeName); } - protected String columnAppend(final String columnName) { + protected String columnAppendIn(final String columnName) { return "(" + columnName + " IN(select column_value from table(?)))"; } + protected String columnAppendNotIn(final String columnName) { + return "(" + columnName + " NOT IN(select column_value from table(?)))"; + } + public Array toArray(final Connection conn, final String typeName, final Object[] elements) throws SQLException { //return conn.unwrap(oracle.jdbc.OracleConnection.class).createOracleArray(typeName, elements); try { diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java index 1d687e9..eef7ea3 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/QueryMapper.java @@ -238,7 +238,7 @@ public class QueryMapper implements JdbcMapper { if (bindObjects != null && bindObjects.length > 0) { for (Object o : bindObjects) { if (o != null) { - if (o == InList.InListObject.empty || o == noBind) { + if (o == InList.InListObject.inEmpty || o == InList.InListObject.notInEmpty || o == noBind) { continue; // ignore } else if (o instanceof BindInList.BindInListObject) { if (((BindInList.BindInListObject) o).getBindObjects() != null) diff --git a/querymapper/src/main/java/com/moparisthebest/jdbc/UnNestArrayInList.java b/querymapper/src/main/java/com/moparisthebest/jdbc/UnNestArrayInList.java index 1147624..d638d2e 100644 --- a/querymapper/src/main/java/com/moparisthebest/jdbc/UnNestArrayInList.java +++ b/querymapper/src/main/java/com/moparisthebest/jdbc/UnNestArrayInList.java @@ -22,7 +22,11 @@ public class UnNestArrayInList extends ArrayInList { this(JdbcMapper.DatabaseType.UNNEST.arrayNumberTypeName, JdbcMapper.DatabaseType.UNNEST.arrayStringTypeName); } - protected String columnAppend(final String columnName) { + protected String columnAppendIn(final String columnName) { return "(" + columnName + " IN(UNNEST(?)))"; } + + protected String columnAppendNotIn(final String columnName) { + return "(" + columnName + " NOT IN(UNNEST(?)))"; + } } diff --git a/test/src/main/java/com/moparisthebest/jdbc/codegen/QmDao.java b/test/src/main/java/com/moparisthebest/jdbc/codegen/QmDao.java index 9af0e27..2b05cc2 100644 --- a/test/src/main/java/com/moparisthebest/jdbc/codegen/QmDao.java +++ b/test/src/main/java/com/moparisthebest/jdbc/codegen/QmDao.java @@ -255,4 +255,7 @@ public interface QmDao extends JdbcMapper { @SQL("SELECT person_no, first_name, last_name, birth_date from person WHERE {person_no IN personNos} AND ({first_name IN names} OR {last_name IN names}) ORDER BY person_no") List getFieldPeopleByName(List personNos, List names) throws SQLException; + + @SQL("SELECT person_no, first_name, last_name, birth_date from person WHERE {person_no NOT IN personNos} ORDER BY person_no") + List getFieldPeopleNotIn(List personNos) throws SQLException; } diff --git a/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperQmDao.java b/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperQmDao.java index 15ca82e..849e7fd 100644 --- a/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperQmDao.java +++ b/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperQmDao.java @@ -62,11 +62,11 @@ public class QueryMapperQmDao implements QmDao { Collection> no = new ArrayList>(); for(final String connectionClassName : new String[]{ "org.apache.derby.iapi.jdbc.EngineConnection" - //, "org.hsqldb.jdbc.JDBCConnection" // does not support ArrayInList but *does* support UnNestArrayInList + , "org.hsqldb.jdbc.JDBCConnection" // does not support ArrayInList but *does* support UnNestArrayInList , "org.sqlite.jdbc3.JDBC3Connection" , "org.mariadb.jdbc.MariaDbConnection" , "com.microsoft.sqlserver.jdbc.ISQLServerConnection" - //, "oracle.jdbc.OracleConnection" // does not support ArrayInList but *does* support OracleArrayInList + , "oracle.jdbc.OracleConnection" // does not support ArrayInList but *does* support OracleArrayInList // h2 doesn't support this with java6 either... /*IFJAVA6_START , "org.h2.jdbc.JdbcConnection" @@ -475,4 +475,9 @@ public class QueryMapperQmDao implements QmDao { lqm.inList("last_name", names) ); } + + @Override + public List getFieldPeopleNotIn(final List personNos) throws SQLException { + return lqm.toList("SELECT * from person WHERE " + inListReplace + " ORDER BY person_no", FieldPerson.class, lqm.notInList("person_no", personNos)); + } } diff --git a/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperTypeQmDao.java b/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperTypeQmDao.java index 6e87994..e222d7c 100644 --- a/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperTypeQmDao.java +++ b/test/src/main/java/com/moparisthebest/jdbc/codegen/QueryMapperTypeQmDao.java @@ -354,4 +354,9 @@ public class QueryMapperTypeQmDao extends QueryMapperQmDao { lqm.inList("last_name", names) ); } + + @Override + public List getFieldPeopleNotIn(final List personNos) throws SQLException { + return lqm.toType("SELECT * from person WHERE " + ListQueryMapper.inListReplace + " ORDER BY person_no", new TypeReference>() {}, lqm.notInList("person_no", personNos)); + } } diff --git a/test/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java b/test/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java index 35d913a..a61afef 100644 --- a/test/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java +++ b/test/src/test/java/com/moparisthebest/jdbc/QueryMapperTest.java @@ -682,4 +682,10 @@ public class QueryMapperTest { Arrays.asList(people[0].getFirstName(), people[1].getFirstName(), people[2].getFirstName())); assertArrayEquals(people, fromDb.toArray()); } + + @Test + public void testListQueryMapperListNotIn() throws SQLException { + final List fromDb = qm.getFieldPeopleNotIn(Arrays.asList(bosses[0].getPersonNo(), bosses[1].getPersonNo(), bosses[2].getPersonNo())); + assertArrayEquals(people, fromDb.toArray()); + } }