git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@378 f203690c-595d-4dc9-a70b-905162fa7fd2tags/rel_1_1_18
James Ahlborn - Added support for NUMERIC data type | James Ahlborn - Added support for NUMERIC data type | ||||
Jon Iles - Added support for reading table definitions that span multiple pages | Jon Iles - Added support for reading table definitions that span multiple pages | ||||
James Schopp - added support for reading currency columns | James Schopp - added support for reading currency columns | ||||
Patricia Donaldson - contributed RowFilter class |
<author email="jahlborn@users.sf.net">James Ahlborn</author> | <author email="jahlborn@users.sf.net">James Ahlborn</author> | ||||
</properties> | </properties> | ||||
<body> | <body> | ||||
<release version="1.1.18" date="TBD"> | |||||
<action dev="jahlborn" type="add"> | |||||
Add RowFilter contributed by Patricia Donaldson. | |||||
</action> | |||||
</release> | |||||
<release version="1.1.17" date="2008-09-23"> | <release version="1.1.17" date="2008-09-23"> | ||||
<action dev="jahlborn" type="fix" issue="2043499"> | <action dev="jahlborn" type="fix" issue="2043499"> | ||||
Fix simple index handling of tail index pages. | Fix simple index handling of tail index pages. |
/* | |||||
Copyright (c) 2007 Health Market Science, Inc. | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |||||
USA | |||||
You can contact Health Market Science at info@healthmarketscience.com | |||||
or at the following address: | |||||
Health Market Science | |||||
2700 Horizon Drive | |||||
Suite 200 | |||||
King of Prussia, PA 19406 | |||||
*/ | |||||
package com.healthmarketscience.jackcess; | |||||
import java.util.Iterator; | |||||
import java.util.Map; | |||||
import org.apache.commons.lang.ObjectUtils; | |||||
/** | |||||
* The RowFilter class encapsulates a filter test for a table row. This can | |||||
* be used by the {@link #apply(Iterable)} method to create an Iterable over a | |||||
* table which returns only rows matching some criteria. | |||||
* | |||||
* @author Patricia Donaldson, Xerox Corporation | |||||
*/ | |||||
public abstract class RowFilter | |||||
{ | |||||
/** | |||||
* Returns {@code true} if the given table row matches the Filter criteria, | |||||
* {@code false} otherwise. | |||||
* @param row current row to test for inclusion in the filter | |||||
*/ | |||||
public abstract boolean matches(Map<String, Object> row); | |||||
/** | |||||
* Returns an iterable which filters the given iterable based on this | |||||
* filter. | |||||
* | |||||
* @param iterable row iterable to filter | |||||
* | |||||
* @return a filtering iterable | |||||
*/ | |||||
public Iterable<Map<String, Object>> apply( | |||||
Iterable<Map<String, Object>> iterable) | |||||
{ | |||||
return new FilterIterable(iterable); | |||||
} | |||||
/** | |||||
* Creates a filter based on a row pattern. | |||||
* | |||||
* @param rowPattern Map from column names to the values to be matched. | |||||
* A table row will match the target if | |||||
* {@code ObjectUtil.equals(rowPattern.get(s), row.get(s))} | |||||
* for all column names in the pattern map. | |||||
* @return a filter which matches table rows which match the values in the | |||||
* row pattern | |||||
*/ | |||||
public static RowFilter matchPattern(final Map<String, Object> rowPattern) | |||||
{ | |||||
return new RowFilter() { | |||||
@Override | |||||
public boolean matches(Map<String, Object> row) | |||||
{ | |||||
for(Map.Entry<String,Object> e : rowPattern.entrySet()) { | |||||
if(!ObjectUtils.equals(e.getValue(), row.get(e.getKey()))) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
}; | |||||
} | |||||
/** | |||||
* Creates a filter based on a single value row pattern. | |||||
* | |||||
* @param columnPattern column to be matched | |||||
* @param valuePattern value to be matched. | |||||
* A table row will match the target if | |||||
* {@code ObjectUtil.equals(valuePattern, row.get(columnPattern.getName()))}. | |||||
* @return a filter which matches table rows which match the value in the | |||||
* row pattern | |||||
*/ | |||||
public static RowFilter matchPattern(final Column columnPattern, final Object valuePattern) | |||||
{ | |||||
return new RowFilter() { | |||||
@Override | |||||
public boolean matches(Map<String, Object> row) | |||||
{ | |||||
return ObjectUtils.equals(valuePattern, row.get(columnPattern.getName())); | |||||
} | |||||
}; | |||||
} | |||||
/** | |||||
* Creates a filter which inverts the sense of the given filter (rows which | |||||
* are matched by the given filter will not be matched by the returned | |||||
* filter, and vice versa). | |||||
* | |||||
* @param filter filter which to invert | |||||
* | |||||
* @return a RowFilter which matches rows not matched by the given filter | |||||
*/ | |||||
public static RowFilter invert(final RowFilter filter) | |||||
{ | |||||
return new RowFilter() { | |||||
@Override | |||||
public boolean matches(Map<String, Object> row) | |||||
{ | |||||
return !filter.matches(row); | |||||
} | |||||
}; | |||||
} | |||||
/** | |||||
* Returns an iterable which filters the given iterable based on the given | |||||
* rowFilter. | |||||
* | |||||
* @param rowFilter the filter criteria, may be {@code null} | |||||
* @param iterable row iterable to filter | |||||
* | |||||
* @return a filtering iterable (or the given iterable if a {@code null} | |||||
* filter was given) | |||||
*/ | |||||
public static Iterable<Map<String, Object>> apply( | |||||
RowFilter rowFilter, | |||||
Iterable<Map<String, Object>> iterable) | |||||
{ | |||||
return((rowFilter != null) ? rowFilter.apply(iterable) : iterable); | |||||
} | |||||
/** | |||||
* Iterable which creates a filtered view of a another row iterable. | |||||
*/ | |||||
private class FilterIterable implements Iterable<Map<String, Object>> | |||||
{ | |||||
private final Iterable<Map<String, Object>> _iterable; | |||||
private FilterIterable(Iterable<Map<String, Object>> iterable) | |||||
{ | |||||
_iterable = iterable; | |||||
} | |||||
/** | |||||
* Returns an iterator which iterates through the rows of the underlying | |||||
* iterable, returning only rows for which the {@link RowFilter#matches} | |||||
* method returns {@code true} | |||||
*/ | |||||
public Iterator<Map<String, Object>> iterator() | |||||
{ | |||||
return new Iterator<Map<String, Object>>() { | |||||
private final Iterator<Map<String, Object>> _iter = | |||||
_iterable.iterator(); | |||||
private Map<String, Object> _next; | |||||
public boolean hasNext() { | |||||
while(_iter.hasNext()) { | |||||
_next = _iter.next(); | |||||
if(RowFilter.this.matches(_next)) { | |||||
return true; | |||||
} | |||||
} | |||||
_next = null; | |||||
return false; | |||||
} | |||||
public Map<String, Object> next() { | |||||
return _next; | |||||
} | |||||
public void remove() { | |||||
throw new UnsupportedOperationException(); | |||||
} | |||||
}; | |||||
} | |||||
} | |||||
} |
private String _oldBigIndexValue = null; | private String _oldBigIndexValue = null; | ||||
/** | |||||
* Creates a new <code>IndexTest</code> instance. | |||||
* | |||||
*/ | |||||
public BigIndexTest(String name) { | public BigIndexTest(String name) { | ||||
super(name); | super(name); | ||||
} | } |
*/ | */ | ||||
public class IndexTest extends TestCase { | public class IndexTest extends TestCase { | ||||
/** | |||||
* Creates a new <code>IndexTest</code> instance. | |||||
* | |||||
*/ | |||||
public IndexTest(String name) { | public IndexTest(String name) { | ||||
super(name); | super(name); | ||||
} | } |
/* | |||||
Copyright (c) 2008 Health Market Science, Inc. | |||||
This library is free software; you can redistribute it and/or | |||||
modify it under the terms of the GNU Lesser General Public | |||||
License as published by the Free Software Foundation; either | |||||
version 2.1 of the License, or (at your option) any later version. | |||||
This library is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
Lesser General Public License for more details. | |||||
You should have received a copy of the GNU Lesser General Public | |||||
License along with this library; if not, write to the Free Software | |||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |||||
USA | |||||
You can contact Health Market Science at info@healthmarketscience.com | |||||
or at the following address: | |||||
Health Market Science | |||||
2700 Horizon Drive | |||||
Suite 200 | |||||
King of Prussia, PA 19406 | |||||
*/ | |||||
package com.healthmarketscience.jackcess; | |||||
import java.util.ArrayList; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import junit.framework.TestCase; | |||||
import static com.healthmarketscience.jackcess.DatabaseTest.*; | |||||
/** | |||||
* @author James Ahlborn | |||||
*/ | |||||
public class RowFilterTest extends TestCase | |||||
{ | |||||
private static final String ID_COL = "id"; | |||||
private static final String COL1 = "col1"; | |||||
private static final String COL2 = "col2"; | |||||
private static final String COL3 = "col3"; | |||||
public RowFilterTest(String name) { | |||||
super(name); | |||||
} | |||||
@SuppressWarnings("unchecked") | |||||
public void testFilter() throws Exception | |||||
{ | |||||
Map<String,Object> row0 = createExpectedRow(ID_COL, 0, COL1, "foo", COL2, 13, COL3, "bar"); | |||||
Map<String,Object> row1 = createExpectedRow(ID_COL, 1, COL1, "bar", COL2, 42, COL3, null); | |||||
Map<String,Object> row2 = createExpectedRow(ID_COL, 2, COL1, "foo", COL2, 55, COL3, "bar"); | |||||
Map<String,Object> row3 = createExpectedRow(ID_COL, 3, COL1, "baz", COL2, 42, COL3, "bar"); | |||||
Map<String,Object> row4 = createExpectedRow(ID_COL, 4, COL1, "foo", COL2, 13, COL3, null); | |||||
Map<String,Object> row5 = createExpectedRow(ID_COL, 5, COL1, "bla", COL2, 13, COL3, "bar"); | |||||
List<Map<String,Object>> rows = Arrays.asList(row0, row1, row2, row3, row4, row5); | |||||
assertEquals(Arrays.asList(row0, row2, row4), | |||||
toList(RowFilter.matchPattern( | |||||
new ColumnBuilder(COL1, DataType.TEXT).toColumn(), | |||||
"foo").apply(rows))); | |||||
assertEquals(Arrays.asList(row1, row3, row5), | |||||
toList(RowFilter.invert( | |||||
RowFilter.matchPattern( | |||||
new ColumnBuilder(COL1, DataType.TEXT).toColumn(), | |||||
"foo")).apply(rows))); | |||||
assertEquals(Arrays.asList(row0, row2, row4), | |||||
toList(RowFilter.matchPattern( | |||||
createExpectedRow(COL1, "foo")) | |||||
.apply(rows))); | |||||
assertEquals(Arrays.asList(row0, row2), | |||||
toList(RowFilter.matchPattern( | |||||
createExpectedRow(COL1, "foo", COL3, "bar")) | |||||
.apply(rows))); | |||||
assertEquals(Arrays.asList(row4), | |||||
toList(RowFilter.matchPattern( | |||||
createExpectedRow(COL1, "foo", COL3, null)) | |||||
.apply(rows))); | |||||
assertEquals(Arrays.asList(row0, row4, row5), | |||||
toList(RowFilter.matchPattern( | |||||
createExpectedRow(COL2, 13)) | |||||
.apply(rows))); | |||||
assertEquals(Arrays.asList(row1), | |||||
toList(RowFilter.matchPattern(row1) | |||||
.apply(rows))); | |||||
assertEquals(rows, toList(RowFilter.apply(null, rows))); | |||||
assertEquals(Arrays.asList(row1), | |||||
toList(RowFilter.apply(RowFilter.matchPattern(row1), | |||||
rows))); | |||||
} | |||||
private List<Map<String,Object>> toList(Iterable<Map<String,Object>> rows) | |||||
{ | |||||
List<Map<String,Object>> rowList = new ArrayList<Map<String,Object>>(); | |||||
for(Map<String,Object> row : rows) { | |||||
rowList.add(row); | |||||
} | |||||
return rowList; | |||||
} | |||||
} |