Browse Source

add stream support to Iterable classes; add some unit tests with streaming

git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@1321 f203690c-595d-4dc9-a70b-905162fa7fd2
tags/jackcess-3.5.0
James Ahlborn 4 years ago
parent
commit
11bf84249c

+ 16
- 7
src/main/java/com/healthmarketscience/jackcess/Cursor.java View File

@@ -20,6 +20,8 @@ import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.util.ColumnMatcher;
import com.healthmarketscience.jackcess.util.ErrorHandler;
@@ -143,6 +145,13 @@ public interface Cursor extends Iterable<Row>
@Override
public Iterator<Row> iterator();

/**
* @return a Stream using the default Iterator.
*/
default public Stream<Row> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* Convenience method for constructing a new IterableBuilder for this
* cursor. An IterableBuilder provides a variety of options for more
@@ -174,7 +183,7 @@ public interface Cursor extends Iterable<Row>
* @throws IllegalStateException if the current row is not valid (at
* beginning or end of table), or deleted.
*/
public <M extends Map<String,Object>> M updateCurrentRowFromMap(M row)
public <M extends Map<String,Object>> M updateCurrentRowFromMap(M row)
throws IOException;

/**
@@ -190,7 +199,7 @@ public interface Cursor extends Iterable<Row>
* @return The next row in this table (Column name -&gt; Column value), or
* {@code null} if no next row is found
*/
public Row getNextRow(Collection<String> columnNames)
public Row getNextRow(Collection<String> columnNames)
throws IOException;

/**
@@ -206,7 +215,7 @@ public interface Cursor extends Iterable<Row>
* @return The previous row in this table (Column name -&gt; Column value), or
* {@code null} if no previous row is found
*/
public Row getPreviousRow(Collection<String> columnNames)
public Row getPreviousRow(Collection<String> columnNames)
throws IOException;

/**
@@ -222,11 +231,11 @@ public interface Cursor extends Iterable<Row>
* otherwise
*/
public boolean moveToPreviousRow() throws IOException;
/**
* Moves to the row with the given rowId. If the row is not found (or an
* exception is thrown), the cursor is restored to its previous state.
*
*
* @return {@code true} if a valid row was found with the given id,
* {@code false} if no row was found
*/
@@ -356,14 +365,14 @@ public interface Cursor extends Iterable<Row>
* Savepoint.
*/
public interface Id
{
{
}

/**
* Value object which maintains the current position of the cursor.
*/
public interface Position
{
{
/**
* Returns the unique RowId of the position of the cursor.
*/

+ 17
- 0
src/main/java/com/healthmarketscience/jackcess/Database.java View File

@@ -29,6 +29,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.expr.EvalConfig;
import com.healthmarketscience.jackcess.impl.DatabaseImpl;
@@ -218,6 +220,13 @@ public interface Database extends Iterable<Table>, Closeable, Flushable
@Override
public Iterator<Table> iterator();

/**
* @return a Stream using the default Iterator.
*/
default public Stream<Table> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* Convenience method for constructing a new TableIterableBuilder for this
* cursor. A TableIterableBuilder provides a variety of options for more
@@ -236,6 +245,14 @@ public interface Database extends Iterable<Table>, Closeable, Flushable
*/
public Iterable<TableMetaData> newTableMetaDataIterable();

/**
* @return a Stream using the {@link #newTableMetaDataIterable}
*/
default public Stream<TableMetaData> newTableMetaDataStream() {
return StreamSupport.stream(
newTableMetaDataIterable().spliterator(), false);
}

/**
* @param name User table name (case-insensitive)
* @return The Table, or null if it doesn't exist (or is a system table)

+ 9
- 0
src/main/java/com/healthmarketscience/jackcess/PropertyMap.java View File

@@ -17,6 +17,8 @@ limitations under the License.
package com.healthmarketscience.jackcess;

import java.io.IOException;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
* Map of properties for a database object.
@@ -130,6 +132,13 @@ public interface PropertyMap extends Iterable<PropertyMap.Property>
*/
public void save() throws IOException;

/**
* @return a Stream using the default Iterator.
*/
default public Stream<PropertyMap.Property> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* Info about a property defined in a PropertyMap.
*/

+ 15
- 6
src/main/java/com/healthmarketscience/jackcess/Table.java View File

@@ -20,6 +20,8 @@ import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.util.ErrorHandler;

@@ -49,7 +51,7 @@ public interface Table extends Iterable<Row>
public enum ColumnOrder {
/** columns are ordered based on the order of the data in the table (this
order does not change as columns are added to the table). */
DATA,
DATA,
/** columns are ordered based on the "display" order (this order can be
changed arbitrarily) */
DISPLAY;
@@ -209,7 +211,7 @@ public interface Table extends Iterable<Row>
* @return the given row map, which will contain any autonumbers generated
* @usage _general_method_
*/
public <M extends Map<String,Object>> M addRowFromMap(M row)
public <M extends Map<String,Object>> M addRowFromMap(M row)
throws IOException;

/**
@@ -226,7 +228,7 @@ public interface Table extends Iterable<Row>
* partially successful write.
*
* @see #addRow(Object...) for more details on row arrays
*
*
* @param rows List of Object[] row values. the rows will be modified if
* this table contains an auto-number column, otherwise they
* will not be modified.
@@ -236,7 +238,7 @@ public interface Table extends Iterable<Row>
* generated
* @usage _general_method_
*/
public List<? extends Object[]> addRows(List<? extends Object[]> rows)
public List<? extends Object[]> addRows(List<? extends Object[]> rows)
throws IOException;

/**
@@ -249,12 +251,12 @@ public interface Table extends Iterable<Row>
* Most exceptions thrown from this method will be wrapped with a {@link
* BatchUpdateException} which gives useful information in the case of a
* partially successful write.
*
*
* @return the given row map list, where the row maps will contain any
* autonumbers generated
* @usage _general_method_
*/
public <M extends Map<String,Object>> List<M> addRowsFromMaps(List<M> rows)
public <M extends Map<String,Object>> List<M> addRowsFromMaps(List<M> rows)
throws IOException;

/**
@@ -288,6 +290,13 @@ public interface Table extends Iterable<Row>
@Override
public Iterator<Row> iterator();

/**
* @return a Stream using the default Iterator.
*/
default public Stream<Row> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* After calling this method, {@link #getNextRow} will return the first row
* in the table, see {@link Cursor#reset} (uses the {@link #getDefaultCursor

+ 10
- 1
src/main/java/com/healthmarketscience/jackcess/util/EntryIterableBuilder.java View File

@@ -19,6 +19,8 @@ package com.healthmarketscience.jackcess.util;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.Column;
import com.healthmarketscience.jackcess.IndexCursor;
@@ -109,5 +111,12 @@ public class EntryIterableBuilder implements Iterable<Row>
@Override
public Iterator<Row> iterator() {
return ((IndexCursorImpl)_cursor).entryIterator(this);
}
}

/**
* @return a Stream using the default Iterator.
*/
public Stream<Row> stream() {
return StreamSupport.stream(spliterator(), false);
}
}

+ 13
- 4
src/main/java/com/healthmarketscience/jackcess/util/IterableBuilder.java View File

@@ -22,6 +22,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.Column;
import com.healthmarketscience.jackcess.Cursor;
@@ -139,7 +141,7 @@ public class IterableBuilder implements Iterable<Row>
_columnNames.add(columnName);
}

public IterableBuilder setMatchPattern(Column columnPattern,
public IterableBuilder setMatchPattern(Column columnPattern,
Object valuePattern) {
_type = Type.COLUMN_MATCH;
_matchPattern = new AbstractMap.SimpleImmutableEntry<Column,Object>(
@@ -147,7 +149,7 @@ public class IterableBuilder implements Iterable<Row>
return this;
}

public IterableBuilder setMatchPattern(String columnNamePattern,
public IterableBuilder setMatchPattern(String columnNamePattern,
Object valuePattern) {
return setMatchPattern(_cursor.getTable().getColumn(columnNamePattern),
valuePattern);
@@ -159,7 +161,7 @@ public class IterableBuilder implements Iterable<Row>
return this;
}

public IterableBuilder addMatchPattern(String columnNamePattern,
public IterableBuilder addMatchPattern(String columnNamePattern,
Object valuePattern)
{
_type = Type.ROW_MATCH;
@@ -171,7 +173,7 @@ public class IterableBuilder implements Iterable<Row>
}
matchPattern.put(columnNamePattern, valuePattern);
return this;
}
}

public IterableBuilder setColumnMatcher(ColumnMatcher columnMatcher) {
_columnMatcher = columnMatcher;
@@ -182,4 +184,11 @@ public class IterableBuilder implements Iterable<Row>
public Iterator<Row> iterator() {
return ((CursorImpl)_cursor).iterator(this);
}

/**
* @return a Stream using the default Iterator.
*/
public Stream<Row> stream() {
return StreamSupport.stream(spliterator(), false);
}
}

+ 24
- 15
src/main/java/com/healthmarketscience/jackcess/util/OleBlob.java View File

@@ -24,6 +24,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.impl.OleUtil;

@@ -64,7 +66,7 @@ import com.healthmarketscience.jackcess.impl.OleUtil;
* }
* } finally {
* if(oleBlob != null) { oleBlob.close(); }
* }
* }
* </pre>
* <p>
* <b>Example for creating new, embedded ole data:</b>
@@ -77,7 +79,7 @@ import com.healthmarketscience.jackcess.impl.OleUtil;
* db.addRow(1, oleBlob);
* } finally {
* if(oleBlob != null) { oleBlob.close(); }
* }
* }
* </pre>
* <p>
* <b>Example for creating new, linked ole data:</b>
@@ -90,7 +92,7 @@ import com.healthmarketscience.jackcess.impl.OleUtil;
* db.addRow(1, oleBlob);
* } finally {
* if(oleBlob != null) { oleBlob.close(); }
* }
* }
* </pre>
*
* @author James Ahlborn
@@ -102,11 +104,11 @@ public interface OleBlob extends Blob, Closeable
public enum ContentType {
/** the blob contents are a link (file path) to some external content.
Content will be an instance of LinkContent */
LINK,
LINK,
/** the blob contents are a simple wrapper around some embedded content
and related file names/paths. Content will be an instance
SimplePackageContent */
SIMPLE_PACKAGE,
SIMPLE_PACKAGE,
/** the blob contents are a complex embedded data known as compound
storage (aka OLE2). Working with compound storage requires the
optional POI library. Content will be an instance of CompoundContent.
@@ -119,7 +121,7 @@ public interface OleBlob extends Blob, Closeable
OTHER,
/** the top-level blob wrapper is not understood (this may not be a valid
ole instance). Content will simply be an instance of Content (the
data can be accessed from the main blob instance) */
data can be accessed from the main blob instance) */
UNKNOWN;
}

@@ -137,8 +139,8 @@ public interface OleBlob extends Blob, Closeable
public Content getContent() throws IOException;


public interface Content
{
public interface Content
{
/**
* Returns the type of this content.
*/
@@ -154,7 +156,7 @@ public interface OleBlob extends Blob, Closeable
* Intermediate sub-interface for Content which has a nested package.
*/
public interface PackageContent extends Content
{
{
public String getPrettyName() throws IOException;

public String getClassName() throws IOException;
@@ -171,7 +173,7 @@ public interface OleBlob extends Blob, Closeable

public InputStream getStream() throws IOException;

public void writeTo(OutputStream out) throws IOException;
public void writeTo(OutputStream out) throws IOException;
}

/**
@@ -196,7 +198,7 @@ public interface OleBlob extends Blob, Closeable
* the access database (but the original file source path can also be found
* at {@link #getFilePath}).
*/
public interface SimplePackageContent
public interface SimplePackageContent
extends PackageContent, EmbeddedContent
{
public String getFileName();
@@ -228,6 +230,13 @@ public interface OleBlob extends Blob, Closeable

public Entry getContentsEntry() throws IOException;

/**
* @return a Stream using the default Iterator.
*/
default public Stream<CompoundContent.Entry> stream() {
return StreamSupport.stream(spliterator(), false);
}

/**
* A document entry in the compound storage.
*/
@@ -240,7 +249,7 @@ public interface OleBlob extends Blob, Closeable
*/
public CompoundContent getParent();
}
}
}

/**
* Sub-interface for Content which has the {@link ContentType#OTHER} type.
@@ -269,7 +278,7 @@ public interface OleBlob extends Blob, Closeable
private String _prettyName;
private String _className;
private String _typeName;
public ContentType getType() {
return _type;
}
@@ -301,11 +310,11 @@ public interface OleBlob extends Blob, Closeable
public String getClassName() {
return _className;
}
public String getTypeName() {
return _typeName;
}
public Builder setSimplePackageBytes(byte[] bytes) {
_bytes = bytes;
_contentLen = bytes.length;

+ 22
- 1
src/main/java/com/healthmarketscience/jackcess/util/RowFilter.java View File

@@ -20,6 +20,9 @@ import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.Column;
import com.healthmarketscience.jackcess.Row;
@@ -33,7 +36,7 @@ import com.healthmarketscience.jackcess.Row;
* @author Patricia Donaldson, Xerox Corporation
* @usage _general_class_
*/
public abstract class RowFilter
public abstract class RowFilter implements Predicate<Row>
{

/**
@@ -43,6 +46,15 @@ public abstract class RowFilter
*/
public abstract boolean matches(Row row);

/**
* Adaptation of this class for {@link Predicate} support. Uses the
* {@link #matches} method.
*/
@Override
public boolean test(Row row) {
return matches(row);
}

/**
* Returns an iterable which filters the given iterable based on this
* filter.
@@ -56,6 +68,15 @@ public abstract class RowFilter
return new FilterIterable(iterable);
}

/**
* Convenience method to apply this filter to the given iterable and return
* it as a Stream.
*/
public Stream<Row> filter(Iterable<? extends Row> iterable) {
return StreamSupport.stream(
new FilterIterable(iterable).spliterator(), false)
.filter(this);
}

/**
* Creates a filter based on a row pattern.

+ 16
- 7
src/main/java/com/healthmarketscience/jackcess/util/TableIterableBuilder.java View File

@@ -17,6 +17,8 @@ limitations under the License.
package com.healthmarketscience.jackcess.util;

import java.util.Iterator;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.Table;
@@ -36,7 +38,7 @@ public class TableIterableBuilder implements Iterable<Table>
private boolean _includeNormalTables = true;
private boolean _includeSystemTables;
private boolean _includeLinkedTables = true;
public TableIterableBuilder(Database db) {
_db = db;
}
@@ -44,20 +46,20 @@ public class TableIterableBuilder implements Iterable<Table>
public boolean isIncludeNormalTables() {
return _includeNormalTables;
}
public boolean isIncludeSystemTables() {
return _includeSystemTables;
}
public boolean isIncludeLinkedTables() {
return _includeLinkedTables;
}
public TableIterableBuilder setIncludeNormalTables(boolean includeNormalTables) {
_includeNormalTables = includeNormalTables;
return this;
}
public TableIterableBuilder setIncludeSystemTables(boolean includeSystemTables) {
_includeSystemTables = includeSystemTables;
return this;
@@ -77,7 +79,7 @@ public class TableIterableBuilder implements Iterable<Table>
setIncludeSystemTables(false);
return setIncludeLinkedTables(false);
}
/**
* Convenience method to set the flags to include only system tables.
*/
@@ -86,9 +88,16 @@ public class TableIterableBuilder implements Iterable<Table>
setIncludeSystemTables(true);
return setIncludeLinkedTables(false);
}
@Override
public Iterator<Table> iterator() {
return ((DatabaseImpl)_db).iterator(this);
}

/**
* @return a Stream using the default Iterator.
*/
public Stream<Table> stream() {
return StreamSupport.stream(spliterator(), false);
}
}

+ 10
- 12
src/test/java/com/healthmarketscience/jackcess/CursorTest.java View File

@@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static com.healthmarketscience.jackcess.Database.*;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
@@ -1102,11 +1103,10 @@ public class CursorTest extends TestCase {
Index idx = t1.getIndex("Table2Table1");
IndexCursor cursor = CursorBuilder.createCursor(idx);

List<String> expectedData = new ArrayList<String>();
for(Row row : cursor.newEntryIterable(1)
.addColumnNames("data")) {
expectedData.add(row.getString("data"));
}
List<String> expectedData = cursor.newEntryIterable(1)
.addColumnNames("data")
.stream().map(r -> r.getString("data"))
.collect(Collectors.toList());

assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);

@@ -1155,13 +1155,11 @@ public class CursorTest extends TestCase {
Table t1 = db.getTable("Table1");
Cursor cursor = CursorBuilder.createCursor(t1);

List<String> expectedData = new ArrayList<String>();
for(Row row : cursor.newIterable().setColumnNames(
Arrays.asList("otherfk1", "data"))) {
if(row.get("otherfk1").equals(1)) {
expectedData.add(row.getString("data"));
}
}
List<String> expectedData = cursor.newIterable().setColumnNames(
Arrays.asList("otherfk1", "data")).stream()
.filter(r -> r.get("otherfk1").equals(1))
.map(r -> r.getString("data"))
.collect(Collectors.toList());

assertEquals(Arrays.asList("baz11", "baz11-2"), expectedData);


+ 10
- 12
src/test/java/com/healthmarketscience/jackcess/DatabaseTest.java View File

@@ -35,6 +35,7 @@ import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;

import static com.healthmarketscience.jackcess.Database.*;
import com.healthmarketscience.jackcess.impl.ColumnImpl;
@@ -571,10 +572,9 @@ public class DatabaseTest extends TestCase
((DatabaseImpl)db).getPageChannel().finishWrite();
}

Set<Integer> ids = new HashSet<Integer>();
for(Row row : t) {
ids.add(row.getInt("ID"));
}
Set<Integer> ids = t.stream()
.map(r -> r.getInt("ID"))
.collect(Collectors.toSet());
assertEquals(1000, ids.size());

assertTrue(((TableImpl)t).getOwnedPagesCursor().getUsageMap().toString()
@@ -666,10 +666,9 @@ public class DatabaseTest extends TestCase
((DatabaseImpl)db).getPageChannel().finishWrite();
}

List<Date> foundDates = new ArrayList<Date>();
for(Row row : table) {
foundDates.add(row.getDate("date"));
}
List<Date> foundDates = table.stream()
.map(r -> r.getDate("date"))
.collect(Collectors.toList());

assertEquals(dates.size(), foundDates.size());
for(int i = 0; i < dates.size(); ++i) {
@@ -706,10 +705,9 @@ public class DatabaseTest extends TestCase
table.addRow("row " + dateStr, d);
}

List<String> foundDates = new ArrayList<String>();
for(Row row : table) {
foundDates.add(sdf.format(row.getDate("date")));
}
List<String> foundDates = table.stream()
.map(r -> sdf.format(r.getDate("date")))
.collect(Collectors.toList());

assertEquals(dates, foundDates);


+ 15
- 19
src/test/java/com/healthmarketscience/jackcess/util/JoinerTest.java View File

@@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.Index;
@@ -63,9 +64,9 @@ public class JoinerTest extends TestCase {
assertSame(t2t1, t2t1Join.getFromIndex());
assertSame(t1, t2t1Join.getToTable());
assertSame(t1t2, t2t1Join.getToIndex());
doTestJoiner(t2t1Join, createT2T1Data());
Index t3t1 = t1t3.getReferencedIndex();
assertSame(t3, t3t1.getTable());
Joiner t3t1Join = Joiner.create(t3t1);
@@ -74,11 +75,11 @@ public class JoinerTest extends TestCase {
assertSame(t3t1, t3t1Join.getFromIndex());
assertSame(t1, t3t1Join.getToTable());
assertSame(t1t3, t3t1Join.getToIndex());
doTestJoiner(t3t1Join, createT3T1Data());
doTestJoiner(t3t1Join, createT3T1Data());

doTestJoinerDelete(t2t1Join);
}
}
}

private static void doTestJoiner(
@@ -92,11 +93,8 @@ public class JoinerTest extends TestCase {
for(Row row : join.getFromTable()) {
Integer id = row.getInt("id");

List<Row> joinedRows =
new ArrayList<Row>();
for(Row t1Row : join.findRows(row)) {
joinedRows.add(t1Row);
}
List<Row> joinedRows = join.findRows(row).stream()
.collect(Collectors.toList());

List<Row> expectedRows = expectedData.get(id);
assertEquals(expectedData.get(id), joinedRows);
@@ -110,18 +108,16 @@ public class JoinerTest extends TestCase {
assertFalse(join.hasRows(row));
assertNull(join.findFirstRow(row));
}
List<Row> expectedRows2 = new ArrayList<Row>();
for(Row tmpRow : expectedRows) {
Row tmpRow2 = new RowImpl(tmpRow);
tmpRow2.keySet().retainAll(colNames);
expectedRows2.add(tmpRow2);
}
joinedRows = new ArrayList<Row>();
for(Row t1Row : join.findRows(row).setColumnNames(colNames)) {
joinedRows.add(t1Row);
}

joinedRows = join.findRows(row).setColumnNames(colNames)
.stream().collect(Collectors.toList());

assertEquals(expectedRows2, joinedRows);

@@ -129,7 +125,7 @@ public class JoinerTest extends TestCase {
assertEquals(expectedRows2.get(0), join.findFirstRow(row, colNames));
} else {
assertNull(join.findFirstRow(row, colNames));
}
}
}
}

@@ -175,7 +171,7 @@ public class JoinerTest extends TestCase {

return data;
}
private static Map<Integer,List<Row>> createT3T1Data()
{
Map<Integer,List<Row>> data = new HashMap<Integer,List<Row>>();
@@ -202,5 +198,5 @@ public class JoinerTest extends TestCase {

return data;
}
}

Loading…
Cancel
Save