Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 41 additions & 14 deletions src/main/java/io/deephaven/csv/CsvSpecs.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,27 +68,54 @@ public interface Builder {
*/
Builder parsers(Iterable<? extends Parser<?>> elements);


/**
* Used to force a specific parser for a specific column, specified by column name. Specifying a parser forgoes
* column inference for that column. If {@link #putParserForName} and {@link #putParserForIndex} both refer to
* the same column, {@link #putParserForName} takes priority.
*
* Used to force a single parser for a specific column, specified by column name. Specifying a single parser
* forgoes type inference for that column. If {@link #putParserForName} and {@link #putParserForIndex} both
* refer to the same column, {@link #putParserForName} takes priority.
*
* @param columnName The column name
* @param parser The parser
* @return self after modifying the parser property for the given columnName.
*/
Builder putParserForName(String columnName, Parser<?> parser);
default Builder putParserForName(String columnName, Parser<?> parser) {
return putParsersForName(columnName, Collections.singletonList(parser));
}

/**
* Used to force a specific parser for a specific column, specified by 0-based column index. Specifying a parser
* forgoes column inference for that column. If {@link #putParserForName} and {@link #putParserForIndex} both
* refer to the same column, {@link #putParserForName} takes priority.
*
* Used to force a single parser for a specific column, specified by 0-based column index. Specifying a single
* parser forgoes type inference for that column. If {@link #putParserForName} and {@link #putParserForIndex}
* both refer to the same column, {@link #putParserForName} takes priority.
*
* @param index The column index
* @param parser The parser
* @return self after modifying the parser property for the given column index.
*/
Builder putParserForIndex(int index, Parser<?> parser);
default Builder putParserForIndex(int index, Parser<?> parser) {
return putParsersForIndex(index, Collections.singletonList(parser));
}

/**
* Used to force a specific set of parsers for a specific column, specified by column name. If
* {@link #putParsersForName} and {@link #putParsersForIndex} both refer to the same column,
* {@link #putParsersForName} takes priority.
*
* @param columnName The column name
* @param elements The parsers
* @return self after modifying the parser property for the given columnName.
*/
Builder putParsersForName(String columnName, List<Parser<?>> elements);

/**
* Used to force a specific set of parsers for a specific column, specified by column name. If
* {@link #putParsersForName} and {@link #putParsersForIndex} both refer to the same column,
* {@link #putParsersForName} takes priority.
*
* @param index The column index
* @param elements The parsers
* @return self after modifying the parser property for the given column index.
*/
Builder putParsersForIndex(int index, List<Parser<?>> elements);

/**
* The default collection of strings that means "null value" in the input. These defaults are used for a column
Expand Down Expand Up @@ -468,18 +495,18 @@ public List<Parser<?>> parsers() {
}

/**
* See {@link Builder#putParserForName}.
* See {@link Builder#putParsersForName}.
*
* @return A map of the client-specified parsers, keyed by column name.
*/
public abstract Map<String, Parser<?>> parserForName();
public abstract Map<String, List<Parser<?>>> parsersForName();

/**
* See {@link Builder#putParserForIndex}.
* See {@link Builder#putParsersForIndex}.
*
* @return A map of the client-specified parsers, keyed by column index.
*/
public abstract Map<Integer, Parser<?>> parserForIndex();
public abstract Map<Integer, List<Parser<?>>> parsersForIndex();

/**
* See {@link Builder#nullValueLiterals}.
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/io/deephaven/csv/reading/CsvReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -247,13 +247,13 @@ private static Result commonReadLogic(final CsvSpecs specs, CellGrabber grabber,
*/
private static List<Parser<?>> calcParsersToUse(final CsvSpecs specs, final String columnName,
final int columnIndex) {
Parser<?> specifiedParser = specs.parserForName().get(columnName);
if (specifiedParser != null) {
return Collections.singletonList(specifiedParser);
List<Parser<?>> specifiedParsers = specs.parsersForName().get(columnName);
if (specifiedParsers != null) {
return specifiedParsers;
}
specifiedParser = specs.parserForIndex().get(columnIndex);
if (specifiedParser != null) {
return Collections.singletonList(specifiedParser);
specifiedParsers = specs.parsersForIndex().get(columnIndex);
if (specifiedParsers != null) {
return specifiedParsers;
}
return specs.parsers();
}
Expand Down
46 changes: 46 additions & 0 deletions src/test/java/io/deephaven/csv/PerColumnParsersTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.deephaven.csv;

import io.deephaven.csv.parsers.*;
import io.deephaven.csv.testutil.*;
import io.deephaven.csv.util.CsvReaderException;
import org.junit.jupiter.api.Test;

import java.util.*;

public class PerColumnParsersTest {
/**
* Tests per-column custom parser inferencing.
*/
@Test
public void testPerColumnParsers() throws CsvReaderException {
// Has four columns with the same values: 0, 10, 5000
// The columns are configured with different parser inferencers
// Col0: byte, string
// Col1: byte, short, string
// Col2: byte, int, string
// Col3: default parser, which is set to byte, double, string
final String input = "Col0,Col1,Col2,Col3\n" +
"0, 0, 0, 0\n" +
"10, 10, 10, 10\n" +
"5000, 5000, 5000, 5000\n";

final List<Parser<?>> col0Parsers = Arrays.asList(Parsers.BYTE, Parsers.STRING);
final List<Parser<?>> col1Parsers = Arrays.asList(Parsers.BYTE, Parsers.SHORT, Parsers.STRING);
final List<Parser<?>> col2Parsers = Arrays.asList(Parsers.BYTE, Parsers.INT, Parsers.STRING);
final List<Parser<?>> defaultParsers = Arrays.asList(Parsers.BYTE, Parsers.DOUBLE, Parsers.STRING);

final ColumnSet expected =
ColumnSet.of(
Column.ofRefs("Col0", "0", "10", "5000"),
Column.ofValues("Col1", (short) 0, (short) 10, (short) 5000),
Column.ofValues("Col2", (int) 0, (int) 10, (int) 5000),
Column.ofValues("Col3", (double) 0, (double) 10, (double) 5000));

CsvTestUtil.invokeTest(CsvTestUtil.defaultCsvBuilder()
.putParsersForIndex(0, col0Parsers)
.putParsersForIndex(1, col1Parsers)
.putParsersForIndex(2, col2Parsers)
.parsers(defaultParsers)
.build(), input, expected);
}
}