From be92326c8b84931db9a5217e54f551d00a3565f0 Mon Sep 17 00:00:00 2001 From: Devin Smith Date: Fri, 4 Jun 2021 16:13:00 -0500 Subject: [PATCH] Initial QST prototype --- qst/build.gradle | 12 ++ .../java/io/deephaven/qst/AllowNulls.java | 13 ++ .../main/java/io/deephaven/qst/Examples4.java | 159 ++++++++++++++++++ .../main/java/io/deephaven/qst/QSTStyle.java | 16 ++ .../java/io/deephaven/qst/package-info.java | 2 + .../io/deephaven/qst/table/EmptyTable.java | 30 ++++ .../io/deephaven/qst/table/HeadTable.java | 22 +++ .../java/io/deephaven/qst/table/NewTable.java | 79 +++++++++ .../qst/table/NewTableBuildable.java | 13 ++ .../deephaven/qst/table/NewTableColumn.java | 8 + .../java/io/deephaven/qst/table/Table.java | 16 ++ .../io/deephaven/qst/table/TableBase.java | 14 ++ .../io/deephaven/qst/table/TableHeader.java | 53 ++++++ .../io/deephaven/qst/table/TailTable.java | 22 +++ .../io/deephaven/qst/table/column/Column.java | 103 ++++++++++++ .../qst/table/column/ColumnBuilder.java | 8 + .../qst/table/column/header/ColumnHeader.java | 147 ++++++++++++++++ .../table/column/header/ColumnHeaders2.java | 69 ++++++++ .../table/column/header/ColumnHeaders3.java | 69 ++++++++ .../table/column/header/ColumnHeaders4.java | 69 ++++++++ .../table/column/header/ColumnHeaders5.java | 69 ++++++++ .../table/column/header/ColumnHeaders6.java | 69 ++++++++ .../table/column/header/ColumnHeaders7.java | 69 ++++++++ .../table/column/header/ColumnHeaders8.java | 69 ++++++++ .../table/column/header/ColumnHeaders9.java | 56 ++++++ .../qst/table/column/type/BooleanType.java | 22 +++ .../qst/table/column/type/ByteType.java | 22 +++ .../qst/table/column/type/CharType.java | 22 +++ .../qst/table/column/type/ColumnType.java | 87 ++++++++++ .../qst/table/column/type/ColumnTypeBase.java | 10 ++ .../table/column/type/ColumnTypeMappings.java | 89 ++++++++++ .../qst/table/column/type/DoubleType.java | 22 +++ .../qst/table/column/type/FloatType.java | 22 +++ .../qst/table/column/type/GenericType.java | 31 ++++ .../qst/table/column/type/IntType.java | 22 +++ .../qst/table/column/type/LongType.java | 22 +++ .../qst/table/column/type/ShortType.java | 22 +++ .../qst/table/column/type/StringType.java | 22 +++ .../io/deephaven/qst/ColumnHeaderTest.java | 70 ++++++++ .../java/io/deephaven/qst/ColumnTest.java | 32 ++++ .../java/io/deephaven/qst/ColumnTypeTest.java | 100 +++++++++++ .../io/deephaven/qst/GenericTypeTest.java | 59 +++++++ .../io/deephaven/qst/table/NewTableTest.java | 75 +++++++++ settings.gradle | 2 +- 44 files changed, 2008 insertions(+), 1 deletion(-) create mode 100644 qst/build.gradle create mode 100644 qst/src/main/java/io/deephaven/qst/AllowNulls.java create mode 100644 qst/src/main/java/io/deephaven/qst/Examples4.java create mode 100644 qst/src/main/java/io/deephaven/qst/QSTStyle.java create mode 100644 qst/src/main/java/io/deephaven/qst/package-info.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/EmptyTable.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/HeadTable.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/NewTable.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/NewTableBuildable.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/NewTableColumn.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/Table.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/TableBase.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/TableHeader.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/TailTable.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/Column.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/ColumnBuilder.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeader.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders2.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders3.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders4.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders5.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders6.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders7.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders8.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders9.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/BooleanType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/ByteType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/CharType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/ColumnType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeBase.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeMappings.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/DoubleType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/FloatType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/GenericType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/IntType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/LongType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/ShortType.java create mode 100644 qst/src/main/java/io/deephaven/qst/table/column/type/StringType.java create mode 100644 qst/src/test/java/io/deephaven/qst/ColumnHeaderTest.java create mode 100644 qst/src/test/java/io/deephaven/qst/ColumnTest.java create mode 100644 qst/src/test/java/io/deephaven/qst/ColumnTypeTest.java create mode 100644 qst/src/test/java/io/deephaven/qst/GenericTypeTest.java create mode 100644 qst/src/test/java/io/deephaven/qst/table/NewTableTest.java diff --git a/qst/build.gradle b/qst/build.gradle new file mode 100644 index 00000000000..c7ae34b691d --- /dev/null +++ b/qst/build.gradle @@ -0,0 +1,12 @@ +dependencies { + annotationProcessor 'org.immutables:value:2.8.1' + compileOnly 'org.immutables:value-annotations:2.8.1' + + testImplementation(platform('org.junit:junit-bom:5.7.2')) + testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'org.assertj:assertj-core:3.19.0' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/qst/src/main/java/io/deephaven/qst/AllowNulls.java b/qst/src/main/java/io/deephaven/qst/AllowNulls.java new file mode 100644 index 00000000000..8275dcebf94 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/AllowNulls.java @@ -0,0 +1,13 @@ +package io.deephaven.qst; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE}) +public @interface AllowNulls { + +} + diff --git a/qst/src/main/java/io/deephaven/qst/Examples4.java b/qst/src/main/java/io/deephaven/qst/Examples4.java new file mode 100644 index 00000000000..23a47ad1213 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/Examples4.java @@ -0,0 +1,159 @@ +package io.deephaven.qst; + +import io.deephaven.qst.table.NewTable; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.header.ColumnHeader; +import io.deephaven.qst.table.column.header.ColumnHeaders3; + +public class Examples4 { + + + + + + + + + + + + + + + + + + + + + + static NewTable example1() { + return NewTable.of( + Column.of("LastName", "Rafferty", "Jones", "Steiner", "Robins", "Smith", "Rogers"), + Column.of("DeptId", 31, 33, 33, 34, 34, null), + Column.of("Telephone", "(347) 555-0123", "(917) 555-0198", "(212) 555-0167", "(952) 555-0110", null, null)); + } + + // --------------------------------------------------------------- + + static NewTable example2() { + return NewTable + .header("LastName", String.class) + .header("DeptId", int.class) + .header("Telephone", String.class) + .row("Rafferty", 31, "(347) 555-0123") + .row("Jones", 33, "(917) 555-0198") + .row("Steiner", 33, "(212) 555-0167") + .row("Robins", 34, "(952) 555-0110") + .row("Smith", 34, null) + .row("Rogers", null, null) + .build(); + } + + // --------------------------------------------------------------- + + static final ColumnHeader DEPT_ID = ColumnHeader.ofInt("DeptId"); + static final ColumnHeader TELEPHONE = ColumnHeader.ofString("Telephone"); + + static final ColumnHeaders3 EMPLOYEE_HEADER = ColumnHeader + .of("LastName", String.class) + .header(DEPT_ID) + .header(TELEPHONE); + + static final ColumnHeaders3 DEPARTMENT_HEADER = + DEPT_ID + .header("DeptName", String.class) + .header(TELEPHONE); + + static NewTable example3a() { + return EMPLOYEE_HEADER + .row("Rafferty", 31, "(347) 555-0123") + .row("Jones", 33, "(917) 555-0198") + .row("Steiner", 33, "(212) 555-0167") + .row("Robins", 34, "(952) 555-0110") + .row("Smith", 34, null) + .row("Rogers", null, null) + .build(); + } + + static NewTable example3b() { + return EMPLOYEE_HEADER + .row("Foo", null, "(555) 555-5555") + .row("Bar", null, "(555) 555-5555") + .build(); + } + + static NewTable example3c() { + return DEPARTMENT_HEADER + .row(31, "Sales", "(646) 555-0134") + .row(33, "Engineering", "(646) 555-0178") + .row(34, "Clerical", "(646) 555-0159") + .row(35, "Marketing", "(212) 555-0111") + .build(); + } + + // --------------------------------------------------------------- + + interface Employee { + String name(); + Integer deptId(); + String telephone(); + } + + interface Department { + int id(); + String name(); + String telephone(); + } + + // impls out-of-scope + + static Employee RAFFERTY = null; + static Employee JONES = null; + static Employee STEINER = null; + static Employee ROBINS = null; + static Employee SMITH = null; + static Employee ROGERS = null; + + static Department SALES = null; + static Department ENGINEERING = null; + static Department CLERICAL = null; + static Department MARKETING = null; + + static NewTable example4a(Employee... employees) { + ColumnHeaders3.Rows builder = EMPLOYEE_HEADER.start(); + for (Employee employee : employees) { + builder.row(employee.name(), employee.deptId(), employee.telephone()); + } + return builder.build(); + } + + static NewTable example4a() { + return example4a( + RAFFERTY, + JONES, + STEINER, + ROBINS, + SMITH, + ROGERS); + } + + static NewTable example4b(Department... departments) { + ColumnHeaders3.Rows builder = DEPARTMENT_HEADER.start(); + for (Department d : departments) { + builder.row(d.id(), d.name(), d.telephone()); + } + return builder.build(); + } + + static NewTable example4b() { + return example4b( + SALES, + ENGINEERING, + CLERICAL, + MARKETING); + } + + // --------------------------------------------------------------- + +} diff --git a/qst/src/main/java/io/deephaven/qst/QSTStyle.java b/qst/src/main/java/io/deephaven/qst/QSTStyle.java new file mode 100644 index 00000000000..e1add935195 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/QSTStyle.java @@ -0,0 +1,16 @@ +package io.deephaven.qst; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.immutables.value.Value; +import org.immutables.value.Value.Style.ImplementationVisibility; + +@Target({ElementType.PACKAGE, ElementType.TYPE}) +@Retention(RetentionPolicy.CLASS) +@Value.Style( + visibility = ImplementationVisibility.PACKAGE, + defaults = @Value.Immutable(copy = false), + strictBuilder = true) +public @interface QSTStyle {} \ No newline at end of file diff --git a/qst/src/main/java/io/deephaven/qst/package-info.java b/qst/src/main/java/io/deephaven/qst/package-info.java new file mode 100644 index 00000000000..0da02c88e7e --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/package-info.java @@ -0,0 +1,2 @@ +@QSTStyle +package io.deephaven.qst; \ No newline at end of file diff --git a/qst/src/main/java/io/deephaven/qst/table/EmptyTable.java b/qst/src/main/java/io/deephaven/qst/table/EmptyTable.java new file mode 100644 index 00000000000..298a03a3620 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/EmptyTable.java @@ -0,0 +1,30 @@ +package io.deephaven.qst.table; + +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class EmptyTable extends TableBase { + + public static EmptyTable of(long size) { + return ImmutableEmptyTable.of(size, TableHeader.empty()); + } + + public static EmptyTable of(long size, TableHeader header) { + return ImmutableEmptyTable.of(size, header); + } + + @Parameter + public abstract long size(); + + @Parameter + public abstract TableHeader header(); + + @Check + final void checkSize() { + if (size() < 0) { + throw new IllegalArgumentException("Must have non-negative size"); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/HeadTable.java b/qst/src/main/java/io/deephaven/qst/table/HeadTable.java new file mode 100644 index 00000000000..1b668be4e4b --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/HeadTable.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table; + +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class HeadTable extends TableBase { + + @Parameter + public abstract Table parent(); + + @Parameter + public abstract long size(); + + @Check + final void checkSize() { + if (size() <= 0) { + throw new IllegalArgumentException("Must have positive size"); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/NewTable.java b/qst/src/main/java/io/deephaven/qst/table/NewTable.java new file mode 100644 index 00000000000..4e591acfcb5 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/NewTable.java @@ -0,0 +1,79 @@ +package io.deephaven.qst.table; + +import io.deephaven.qst.table.ImmutableTableHeader.Builder; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.header.ColumnHeader; +import java.util.Iterator; +import java.util.List; +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; + +@Immutable +public abstract class NewTable extends TableBase { + + public static NewTable empty(TableHeader header) { + ImmutableNewTable.Builder builder = ImmutableNewTable.builder().size(0); + for (ColumnHeader columnHeader : header.headers()) { + builder.addColumns(columnHeader.emptyData()); + } + return builder.build(); + } + + public static NewTable of(Column... columns) { + final int size = columns.length > 0 ? columns[0].size() : 0; + return ImmutableNewTable.builder().addColumns(columns).size(size).build(); + } + + public static NewTable of(Iterable> columns) { + Iterator> it = columns.iterator(); + final int size = it.hasNext() ? it.next().size() : 0; + return ImmutableNewTable.builder().addAllColumns(columns).size(size).build(); + } + + public static ColumnHeader header(String name, Class clazz) { + return ColumnHeader.of(name, clazz); + } + + public abstract List> columns(); + + public abstract int size(); + + public final int numColumns() { + return columns().size(); + } + + public final TableHeader header() { + Builder builder = ImmutableTableHeader.builder(); + for (Column column : columns()) { + builder.addHeaders(column.header()); + } + return builder.build(); + } + + public final NewTable with(Column column) { + return ImmutableNewTable.builder() + .size(size()) + .addAllColumns(columns()) + .addColumns(column) + .build(); + } + + @Check + final void checkColumnsSizes() { + if (!columns() + .stream() + .map(Column::values) + .mapToInt(List::size) + .allMatch(s -> s == size())) { + throw new IllegalArgumentException("All columns must be the same size"); + } + } + + @Check + final void checkValidHeader() { + // ensure we can build the header + if (header().numColumns() != numColumns()) { + throw new IllegalArgumentException("All headers must have distinct names"); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/NewTableBuildable.java b/qst/src/main/java/io/deephaven/qst/table/NewTableBuildable.java new file mode 100644 index 00000000000..bc7a45ff8ac --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/NewTableBuildable.java @@ -0,0 +1,13 @@ +package io.deephaven.qst.table; + +import io.deephaven.qst.table.column.Column; +import java.util.stream.Stream; + +public abstract class NewTableBuildable { + + protected abstract Stream> columns(); + + public final NewTable build() { + return NewTable.of(() -> columns().iterator()); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/NewTableColumn.java b/qst/src/main/java/io/deephaven/qst/table/NewTableColumn.java new file mode 100644 index 00000000000..c82e29bfcb7 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/NewTableColumn.java @@ -0,0 +1,8 @@ +package io.deephaven.qst.table; + +import org.immutables.value.Value.Immutable; + +@Immutable +public abstract class NewTableColumn { + +} diff --git a/qst/src/main/java/io/deephaven/qst/table/Table.java b/qst/src/main/java/io/deephaven/qst/table/Table.java new file mode 100644 index 00000000000..1c223522332 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/Table.java @@ -0,0 +1,16 @@ +package io.deephaven.qst.table; + +public interface Table { + + static EmptyTable empty(long size) { + return EmptyTable.of(size); + } + + static EmptyTable empty(long size, TableHeader header) { + return EmptyTable.of(size, header); + } + + HeadTable head(long size); + + TailTable tail(long size); +} diff --git a/qst/src/main/java/io/deephaven/qst/table/TableBase.java b/qst/src/main/java/io/deephaven/qst/table/TableBase.java new file mode 100644 index 00000000000..8941bc2293d --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/TableBase.java @@ -0,0 +1,14 @@ +package io.deephaven.qst.table; + +public abstract class TableBase implements Table { + + @Override + public final HeadTable head(long size) { + return ImmutableHeadTable.of(this, size); + } + + @Override + public final TailTable tail(long size) { + return ImmutableTailTable.of(this, size); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/TableHeader.java b/qst/src/main/java/io/deephaven/qst/table/TableHeader.java new file mode 100644 index 00000000000..bb94e7b4162 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/TableHeader.java @@ -0,0 +1,53 @@ +package io.deephaven.qst.table; + +import io.deephaven.qst.table.column.header.ColumnHeader; +import java.util.Iterator; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; + +@Immutable +public abstract class TableHeader implements Iterable> { + + public static TableHeader empty() { + return ImmutableTableHeader.builder().build(); + } + + public static TableHeader of(ColumnHeader... headers) { + return ImmutableTableHeader.builder().addHeaders(headers).build(); + } + + public static TableHeader of(Iterable> headers) { + return ImmutableTableHeader.builder().addAllHeaders(headers).build(); + } + + public abstract List> headers(); + + public final int numColumns() { + return headers().size(); + } + + @Check + final void checkDistinctColumnNames() { + if (headers().size() != headers().stream().map(ColumnHeader::name).distinct().count()) { + throw new IllegalArgumentException("All headers must have distinct names"); + } + } + + @Override + public final Iterator> iterator() { + return headers().iterator(); + } + + @Override + public final void forEach(Consumer> action) { + headers().forEach(action); + } + + @Override + public final Spliterator> spliterator() { + return headers().spliterator(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/TailTable.java b/qst/src/main/java/io/deephaven/qst/table/TailTable.java new file mode 100644 index 00000000000..0b8c25c0953 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/TailTable.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table; + +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class TailTable extends TableBase { + + @Parameter + public abstract Table parent(); + + @Parameter + public abstract long size(); + + @Check + final void checkSize() { + if (size() <= 0) { + throw new IllegalArgumentException("Must have positive size"); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/Column.java b/qst/src/main/java/io/deephaven/qst/table/column/Column.java new file mode 100644 index 00000000000..c65813fa07b --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/Column.java @@ -0,0 +1,103 @@ +package io.deephaven.qst.table.column; + +import io.deephaven.qst.AllowNulls; +import io.deephaven.qst.table.NewTable; +import io.deephaven.qst.table.column.header.ColumnHeader; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.List; +import org.immutables.value.Value.Immutable; + +@Immutable +public abstract class Column { + + public static Column empty(ColumnHeader header) { + return ImmutableColumn.builder().header(header).build(); + } + + public static Column of(ColumnHeader header, T... data) { + return ImmutableColumn.builder().header(header).addValues(data).build(); + } + + public static Column of(ColumnHeader header, Iterable data) { + return ImmutableColumn.builder().header(header).addAllValues(data).build(); + } + + public static Column of(String name, Class clazz, Iterable values) { + return ColumnHeader.of(name, clazz).withData(values); + } + + public static Column of(String name, Class clazz, T... values) { + return ColumnHeader.of(name, clazz).withData(values); + } + + public static Column of(String name, Byte... values) { + return ColumnHeader.ofByte(name).withData(values); + } + + public static Column of(String name, Character... values) { + return ColumnHeader.ofChar(name).withData(values); + } + + public static Column of(String name, Short... values) { + return ColumnHeader.ofShort(name).withData(values); + } + + public static Column of(String name, Integer... values) { + return ColumnHeader.ofInt(name).withData(values); + } + + public static Column of(String name, Long... values) { + return ColumnHeader.ofLong(name).withData(values); + } + + public static Column of(String name, Float... values) { + return ColumnHeader.ofFloat(name).withData(values); + } + + public static Column of(String name, Double... values) { + return ColumnHeader.ofDouble(name).withData(values); + } + + public static Column of(String name, String... values) { + return ColumnHeader.ofString(name).withData(values); + } + + public static ColumnBuilder builder(ColumnHeader header) { + return ImmutableColumn.builder().header(header); + } + + public static Column cast(@SuppressWarnings("unused") ColumnType type, Column column) { + //noinspection unchecked + return (Column)column; + } + + public abstract ColumnHeader header(); + + @AllowNulls + public abstract List values(); + + public final String name() { + return header().name(); + } + + public final ColumnType type() { + return header().type(); + } + + public final int size() { + return values().size(); + } + + public final NewTable toTable() { + return NewTable.of(this); + } + + abstract static class Builder implements ColumnBuilder { + @Override + public final ColumnBuilder add(T item) { + return addValues(item); + } + + abstract Builder addValues(T element); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/ColumnBuilder.java b/qst/src/main/java/io/deephaven/qst/table/column/ColumnBuilder.java new file mode 100644 index 00000000000..161292307cd --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/ColumnBuilder.java @@ -0,0 +1,8 @@ +package io.deephaven.qst.table.column; + +public interface ColumnBuilder { + + ColumnBuilder add(T item); + + Column build(); +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeader.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeader.java new file mode 100644 index 00000000000..42b9c36f939 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeader.java @@ -0,0 +1,147 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeader { + + public static ColumnHeader of(String name, Class clazz) { + return of(name, ColumnType.find(clazz)); + } + + public static ColumnHeader of(String name, ColumnType type) { + return ImmutableColumnHeader.of(name, type); + } + + public static ColumnHeader ofBoolean(String name) { + return of(name, ColumnType.booleanType()); + } + + public static ColumnHeader ofByte(String name) { + return of(name, ColumnType.byteType()); + } + + public static ColumnHeader ofChar(String name) { + return of(name, ColumnType.charType()); + } + + public static ColumnHeader ofShort(String name) { + return of(name, ColumnType.shortType()); + } + + public static ColumnHeader ofInt(String name) { + return of(name, ColumnType.intType()); + } + + public static ColumnHeader ofLong(String name) { + return of(name, ColumnType.longType()); + } + + public static ColumnHeader ofFloat(String name) { + return of(name, ColumnType.floatType()); + } + + public static ColumnHeader ofDouble(String name) { + return of(name, ColumnType.doubleType()); + } + + public static ColumnHeader ofString(String name) { + return of(name, ColumnType.stringType()); + } + + public static ColumnHeaders2 of(ColumnHeader a, ColumnHeader b) { + return a.header(b); + } + + public static ColumnHeaders3 of(ColumnHeader a, ColumnHeader b, ColumnHeader c) { + return a.header(b).header(c); + } + + public static ColumnHeaders4 of(ColumnHeader a, ColumnHeader b, ColumnHeader c, ColumnHeader d) { + return a.header(b).header(c).header(d); + } + + public static ColumnHeaders5 of(ColumnHeader a, ColumnHeader b, ColumnHeader c, ColumnHeader d, ColumnHeader e) { + return a.header(b).header(c).header(d).header(e); + } + + @Parameter + public abstract String name(); + + @Parameter + public abstract ColumnType type(); + + public final ColumnHeaders2 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders2 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders2 header(ColumnHeader header) { + return ImmutableColumnHeaders2.of(this, header); + } + + public final ColumnHeader headerA() { + return this; + } + + public final Stream> headers() { + return Stream.of(headerA()); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Column emptyData() { + return Column.empty(this); + } + + public final Column withData(T... data) { + return Column.of(this, data); + } + + public final Column withData(Iterable data) { + return Column.of(this, data); + } + + public final ColumnBuilder columnBuilder() { + return Column.builder(this); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(T a) { + return start().row(a); + } + + public class Rows extends NewTableBuildable { + + private final ColumnBuilder builder; + + Rows() { + builder = Column.builder(ColumnHeader.this); + } + + public final Rows row(T a) { + builder.add(a); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.of(builder.build()); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders2.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders2.java new file mode 100644 index 00000000000..e1660a0172a --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders2.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders2 { + + @Parameter + public abstract ColumnHeader headerA(); + + @Parameter + public abstract ColumnHeader headerB(); + + public final ColumnHeaders3 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders3 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders3 header(ColumnHeader header) { + return ImmutableColumnHeaders3.of(header, this); + } + + public final Stream> headers() { + return Stream.of(headerA(), headerB()); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b) { + return start().row(a, b); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeader.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = headerA().start(); + builder = Column.builder(headerB()); + } + + public final Rows row(A a, B b) { + others.row(a); + builder.add(b); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders3.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders3.java new file mode 100644 index 00000000000..37e6c7a6986 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders3.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders3 { + + @Parameter + public abstract ColumnHeader headerC(); + + @Parameter + public abstract ColumnHeaders2 others(); + + public final ColumnHeaders4 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders4 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders4 header(ColumnHeader header) { + return ImmutableColumnHeaders4.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerC())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c) { + return start().row(a, b, c); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders2.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerC()); + } + + public final Rows row(A a, B b, C c) { + others.row(a, b); + builder.add(c); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders4.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders4.java new file mode 100644 index 00000000000..6e2e6f697c6 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders4.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders4 { + + @Parameter + public abstract ColumnHeader headerD(); + + @Parameter + public abstract ColumnHeaders3 others(); + + public final ColumnHeaders5 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders5 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders5 header(ColumnHeader header) { + return ImmutableColumnHeaders5.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerD())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d) { + return start().row(a, b, c, d); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders3.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerD()); + } + + public final Rows row(A a, B b, C c, D d) { + others.row(a, b, c); + builder.add(d); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders5.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders5.java new file mode 100644 index 00000000000..fcf8f3e4322 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders5.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders5 { + + @Parameter + public abstract ColumnHeader headerE(); + + @Parameter + public abstract ColumnHeaders4 others(); + + public final ColumnHeaders6 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders6 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders6 header(ColumnHeader header) { + return ImmutableColumnHeaders6.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerE())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d, E e) { + return start().row(a, b, c, d, e); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders4.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerE()); + } + + public final Rows row(A a, B b, C c, D d, E e) { + others.row(a, b, c, d); + builder.add(e); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders6.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders6.java new file mode 100644 index 00000000000..2801ff03cfa --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders6.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders6 { + + @Parameter + public abstract ColumnHeader headerF(); + + @Parameter + public abstract ColumnHeaders5 others(); + + public final ColumnHeaders7 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders7 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders7 header(ColumnHeader header) { + return ImmutableColumnHeaders7.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerF())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d, E e, F f) { + return start().row(a, b, c, d, e, f); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders5.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerF()); + } + + public final Rows row(A a, B b, C c, D d, E e, F f) { + others.row(a, b, c, d, e); + builder.add(f); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders7.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders7.java new file mode 100644 index 00000000000..9ccd41a53c7 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders7.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders7 { + + @Parameter + public abstract ColumnHeader headerG(); + + @Parameter + public abstract ColumnHeaders6 others(); + + public final ColumnHeaders8 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders8 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders8 header(ColumnHeader header) { + return ImmutableColumnHeaders8.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerG())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g) { + return start().row(a, b, c, d, e, f, g); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders6.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerG()); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g) { + others.row(a, b, c, d, e, f); + builder.add(g); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders8.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders8.java new file mode 100644 index 00000000000..fa9eeefa85c --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders8.java @@ -0,0 +1,69 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders8 { + + @Parameter + public abstract ColumnHeader headerH(); + + @Parameter + public abstract ColumnHeaders7 others(); + + public final ColumnHeaders9 header(String name, Class clazz) { + return header(ColumnHeader.of(name, clazz)); + } + + public final ColumnHeaders9 header(String name, ColumnType type) { + return header(ColumnHeader.of(name, type)); + } + + public final ColumnHeaders9 header(ColumnHeader header) { + return ImmutableColumnHeaders9.of(header, this); + } + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerH())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g, H h) { + return start().row(a, b, c, d, e, f, g, h); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders7.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerH()); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g, H h) { + others.row(a, b, c, d, e, f, g); + builder.add(h); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders9.java b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders9.java new file mode 100644 index 00000000000..d018bfef092 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/header/ColumnHeaders9.java @@ -0,0 +1,56 @@ +package io.deephaven.qst.table.column.header; + +import io.deephaven.qst.table.NewTableBuildable; +import io.deephaven.qst.table.TableHeader; +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.ColumnBuilder; +import java.util.stream.Stream; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class ColumnHeaders9 { + + @Parameter + public abstract ColumnHeader headerI(); + + @Parameter + public abstract ColumnHeaders8 others(); + + public final Stream> headers() { + return Stream.concat(others().headers(), Stream.of(headerI())); + } + + public final TableHeader toTableHeader() { + return TableHeader.of(() -> headers().iterator()); + } + + public final Rows start() { + return new Rows(); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + return start().row(a, b, c, d, e, f, g, h, i); + } + + public class Rows extends NewTableBuildable { + private final ColumnHeaders8.Rows others; + private final ColumnBuilder builder; + + Rows() { + others = others().start(); + builder = Column.builder(headerI()); + } + + public final Rows row(A a, B b, C c, D d, E e, F f, G g, H h, I i) { + others.row(a, b, c, d, e, f, g, h); + builder.add(i); + return this; + } + + @Override + protected final Stream> columns() { + return Stream.concat(others.columns(), Stream.of(builder.build())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/BooleanType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/BooleanType.java new file mode 100644 index 00000000000..a04b2639517 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/BooleanType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class BooleanType extends ColumnTypeBase { + + public static BooleanType instance() { + return ImmutableBooleanType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return BooleanType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/ByteType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/ByteType.java new file mode 100644 index 00000000000..196e40aabf6 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/ByteType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class ByteType extends ColumnTypeBase { + + public static ByteType instance() { + return ImmutableByteType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return ByteType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/CharType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/CharType.java new file mode 100644 index 00000000000..e1b5587c9e0 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/CharType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class CharType extends ColumnTypeBase { + + public static CharType instance() { + return ImmutableCharType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return CharType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnType.java new file mode 100644 index 00000000000..fd971421e40 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnType.java @@ -0,0 +1,87 @@ +package io.deephaven.qst.table.column.type; + +import java.util.stream.Stream; + +public interface ColumnType { + + static ColumnType find(Class clazz) { + return ColumnTypeMappings + .findStatic(clazz) + .orElseGet(() -> GenericType.of(clazz)); + } + + static BooleanType booleanType() { + return BooleanType.instance(); + } + + static ByteType byteType() { + return ByteType.instance(); + } + + static CharType charType() { + return CharType.instance(); + } + + static ShortType shortType() { + return ShortType.instance(); + } + + static IntType intType() { + return IntType.instance(); + } + + static LongType longType() { + return LongType.instance(); + } + + static FloatType floatType() { + return FloatType.instance(); + } + + static DoubleType doubleType() { + return DoubleType.instance(); + } + + static StringType stringType() { + return StringType.instance(); + } + + static GenericType ofGeneric(Class clazz) { + return GenericType.of(clazz); + } + + static Stream> staticTypes() { + return Stream.of( + booleanType(), + byteType(), + charType(), + shortType(), + intType(), + longType(), + floatType(), + doubleType(), + stringType()); + } + + static T castValue(@SuppressWarnings("unused") ColumnType columnType, Object value) { + //noinspection unchecked + return (T)value; + } + + V walk(V visitor); + + T castValue(Object value); + + interface Visitor { + void visit(BooleanType booleanType); + void visit(ByteType byteType); + void visit(CharType charType); + void visit(ShortType shortType); + void visit(IntType intType); + void visit(LongType longType); + void visit(FloatType floatType); + void visit(DoubleType doubleType); + void visit(StringType stringType); + void visit(GenericType genericType); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeBase.java b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeBase.java new file mode 100644 index 00000000000..e1a6c05301c --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeBase.java @@ -0,0 +1,10 @@ +package io.deephaven.qst.table.column.type; + +public abstract class ColumnTypeBase implements ColumnType { + + @Override + public final T castValue(Object value) { + //noinspection unchecked + return (T)value; + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeMappings.java b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeMappings.java new file mode 100644 index 00000000000..6d06466015f --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/ColumnTypeMappings.java @@ -0,0 +1,89 @@ +package io.deephaven.qst.table.column.type; + +import io.deephaven.qst.table.column.type.ColumnType.Visitor; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; + +class ColumnTypeMappings { + private static final Map, ColumnType> MAPPINGS; + + static { + final AddMappings addMappings = new AddMappings(); + final Iterator> it = ColumnType.staticTypes().iterator(); + while (it.hasNext()) { + it.next().walk(addMappings); + } + MAPPINGS = Collections.unmodifiableMap(addMappings.mappings); + } + + static Optional> findStatic(Class clazz) { + //noinspection unchecked + return Optional.ofNullable((ColumnType)MAPPINGS.get(clazz)); + } + + static class AddMappings implements Visitor { + + private final Map, ColumnType> mappings = new HashMap<>(); + + @Override + public void visit(BooleanType booleanType) { + mappings.put(boolean.class, booleanType); + mappings.put(Boolean.class, booleanType); + } + + @Override + public void visit(ByteType byteType) { + mappings.put(byte.class, byteType); + mappings.put(Byte.class, byteType); + } + + @Override + public void visit(CharType charType) { + mappings.put(char.class, charType); + mappings.put(Character.class, charType); + } + + @Override + public void visit(ShortType shortType) { + mappings.put(short.class, shortType); + mappings.put(Short.class, shortType); + } + + @Override + public void visit(IntType intType) { + mappings.put(int.class, intType); + mappings.put(Integer.class, intType); + } + + @Override + public void visit(LongType longType) { + mappings.put(long.class, longType); + mappings.put(Long.class, longType); + } + + @Override + public void visit(FloatType floatType) { + mappings.put(float.class, floatType); + mappings.put(Float.class, floatType); + } + + @Override + public void visit(DoubleType doubleType) { + mappings.put(double.class, doubleType); + mappings.put(Double.class, doubleType); + } + + @Override + public void visit(StringType stringType) { + mappings.put(String.class, stringType); + } + + @Override + public void visit(GenericType genericType) { + + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/DoubleType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/DoubleType.java new file mode 100644 index 00000000000..7bedf7e444e --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/DoubleType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class DoubleType extends ColumnTypeBase { + + public static DoubleType instance() { + return ImmutableDoubleType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return DoubleType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/FloatType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/FloatType.java new file mode 100644 index 00000000000..2a05a503470 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/FloatType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class FloatType extends ColumnTypeBase { + + public static FloatType instance() { + return ImmutableFloatType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return FloatType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/GenericType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/GenericType.java new file mode 100644 index 00000000000..8a720ff72f2 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/GenericType.java @@ -0,0 +1,31 @@ +package io.deephaven.qst.table.column.type; + +import java.util.Optional; +import org.immutables.value.Value.Check; +import org.immutables.value.Value.Immutable; +import org.immutables.value.Value.Parameter; + +@Immutable(builder = false, copy = false) +public abstract class GenericType extends ColumnTypeBase { + + public static GenericType of(Class clazz) { + return ImmutableGenericType.of(clazz); + } + + @Parameter + public abstract Class clazz(); + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Check + final void checkClazz() { + final Optional> staticType = ColumnTypeMappings.findStatic(clazz()); + if (staticType.isPresent()) { + throw new IllegalArgumentException(String.format("Use static type %s instead", staticType.get())); + } + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/IntType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/IntType.java new file mode 100644 index 00000000000..c6223421360 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/IntType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class IntType extends ColumnTypeBase { + + public static IntType instance() { + return ImmutableIntType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return IntType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/LongType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/LongType.java new file mode 100644 index 00000000000..12d40d80b87 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/LongType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class LongType extends ColumnTypeBase { + + public static LongType instance() { + return ImmutableLongType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return LongType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/ShortType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/ShortType.java new file mode 100644 index 00000000000..481552c1493 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/ShortType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class ShortType extends ColumnTypeBase { + + public static ShortType instance() { + return ImmutableShortType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return ShortType.class.getName(); + } +} diff --git a/qst/src/main/java/io/deephaven/qst/table/column/type/StringType.java b/qst/src/main/java/io/deephaven/qst/table/column/type/StringType.java new file mode 100644 index 00000000000..6e798f33958 --- /dev/null +++ b/qst/src/main/java/io/deephaven/qst/table/column/type/StringType.java @@ -0,0 +1,22 @@ +package io.deephaven.qst.table.column.type; + +import org.immutables.value.Value.Immutable; + +@Immutable(builder = false, copy = false) +public abstract class StringType extends ColumnTypeBase { + + public static StringType instance() { + return ImmutableStringType.of(); + } + + @Override + public final V walk(V visitor) { + visitor.visit(this); + return visitor; + } + + @Override + public final String toString() { + return StringType.class.getName(); + } +} diff --git a/qst/src/test/java/io/deephaven/qst/ColumnHeaderTest.java b/qst/src/test/java/io/deephaven/qst/ColumnHeaderTest.java new file mode 100644 index 00000000000..5035b89d08b --- /dev/null +++ b/qst/src/test/java/io/deephaven/qst/ColumnHeaderTest.java @@ -0,0 +1,70 @@ +package io.deephaven.qst; + +import static io.deephaven.qst.table.column.header.ColumnHeader.ofBoolean; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofByte; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofChar; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofDouble; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofFloat; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofInt; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofLong; +import static io.deephaven.qst.table.column.header.ColumnHeader.ofShort; +import static io.deephaven.qst.table.column.type.ColumnType.booleanType; +import static io.deephaven.qst.table.column.type.ColumnType.byteType; +import static io.deephaven.qst.table.column.type.ColumnType.charType; +import static io.deephaven.qst.table.column.type.ColumnType.doubleType; +import static io.deephaven.qst.table.column.type.ColumnType.floatType; +import static io.deephaven.qst.table.column.type.ColumnType.intType; +import static io.deephaven.qst.table.column.type.ColumnType.longType; +import static io.deephaven.qst.table.column.type.ColumnType.shortType; +import static org.assertj.core.api.Assertions.assertThat; + +import io.deephaven.qst.table.column.header.ColumnHeader; +import org.junit.jupiter.api.Test; + +public class ColumnHeaderTest { + + @Test + void name() { + assertThat(ColumnHeader.of("TheName", intType()).name()).isEqualTo("TheName"); + } + + @Test + void ofBooleanType() { + assertThat(ofBoolean("X").type()).isEqualTo(booleanType()); + } + + @Test + void ofByteType() { + assertThat(ofByte("X").type()).isEqualTo(byteType()); + } + + @Test + void ofCharType() { + assertThat(ofChar("X").type()).isEqualTo(charType()); + } + + @Test + void ofShortType() { + assertThat(ofShort("X").type()).isEqualTo(shortType()); + } + + @Test + void ofIntType() { + assertThat(ofInt("X").type()).isEqualTo(intType()); + } + + @Test + void ofLongType() { + assertThat(ofLong("X").type()).isEqualTo(longType()); + } + + @Test + void ofFloatType() { + assertThat(ofFloat("X").type()).isEqualTo(floatType()); + } + + @Test + void ofDoubleType() { + assertThat(ofDouble("X").type()).isEqualTo(doubleType()); + } +} diff --git a/qst/src/test/java/io/deephaven/qst/ColumnTest.java b/qst/src/test/java/io/deephaven/qst/ColumnTest.java new file mode 100644 index 00000000000..a9993e6a668 --- /dev/null +++ b/qst/src/test/java/io/deephaven/qst/ColumnTest.java @@ -0,0 +1,32 @@ +package io.deephaven.qst; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.header.ColumnHeader; +import org.junit.jupiter.api.Test; + +public class ColumnTest { + + @Test + public void intHelper() { + Column expected = Column.builder(ColumnHeader.ofInt("AnInt")) + .add(1).add(null).add(3) + .build(); + + Column actual = Column.of("AnInt", 1, null, 3); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void doubleHelper() { + Column expected = Column.builder(ColumnHeader.ofDouble("ADouble")) + .add(1.).add(null).add(3.) + .build(); + + Column actual = Column.of("ADouble", 1., null, 3.); + + assertThat(actual).isEqualTo(expected); + } +} diff --git a/qst/src/test/java/io/deephaven/qst/ColumnTypeTest.java b/qst/src/test/java/io/deephaven/qst/ColumnTypeTest.java new file mode 100644 index 00000000000..0e8086e864e --- /dev/null +++ b/qst/src/test/java/io/deephaven/qst/ColumnTypeTest.java @@ -0,0 +1,100 @@ +package io.deephaven.qst; + +import static io.deephaven.qst.table.column.type.ColumnType.booleanType; +import static io.deephaven.qst.table.column.type.ColumnType.byteType; +import static io.deephaven.qst.table.column.type.ColumnType.charType; +import static io.deephaven.qst.table.column.type.ColumnType.doubleType; +import static io.deephaven.qst.table.column.type.ColumnType.find; +import static io.deephaven.qst.table.column.type.ColumnType.floatType; +import static io.deephaven.qst.table.column.type.ColumnType.intType; +import static io.deephaven.qst.table.column.type.ColumnType.longType; +import static io.deephaven.qst.table.column.type.ColumnType.ofGeneric; +import static io.deephaven.qst.table.column.type.ColumnType.shortType; +import static io.deephaven.qst.table.column.type.ColumnType.staticTypes; +import static io.deephaven.qst.table.column.type.ColumnType.stringType; +import static org.assertj.core.api.Assertions.assertThat; + +import io.deephaven.qst.table.column.type.ColumnType; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +public class ColumnTypeTest { + + @Test + void numberOfStaticTypes() { + // A reminder that when the number of static types increases, we should + // add tests in this class for it specifically + assertThat(staticTypes()).hasSize(9); + } + + @Test + void findBooleans() { + assertThat(find(boolean.class)).isEqualTo(booleanType()); + assertThat(find(Boolean.class)).isEqualTo(booleanType()); + } + + @Test + void findBytes() { + assertThat(find(byte.class)).isEqualTo(byteType()); + assertThat(find(Byte.class)).isEqualTo(byteType()); + } + + @Test + void findChars() { + assertThat(find(char.class)).isEqualTo(charType()); + assertThat(find(Character.class)).isEqualTo(charType()); + } + + @Test + void findShorts() { + assertThat(find(short.class)).isEqualTo(shortType()); + assertThat(find(Short.class)).isEqualTo(shortType()); + } + + @Test + void findInts() { + assertThat(find(int.class)).isEqualTo(intType()); + assertThat(find(Integer.class)).isEqualTo(intType()); + } + + @Test + void findLongs() { + assertThat(find(long.class)).isEqualTo(longType()); + assertThat(find(Long.class)).isEqualTo(longType()); + } + + @Test + void findFloats() { + assertThat(find(float.class)).isEqualTo(floatType()); + assertThat(find(Float.class)).isEqualTo(floatType()); + } + + @Test + void findDoubles() { + assertThat(find(double.class)).isEqualTo(doubleType()); + assertThat(find(Double.class)).isEqualTo(doubleType()); + } + + @Test + void findString() { + assertThat(find(String.class)).isEqualTo(stringType()); + } + + @Test + void findGenericObject() { + assertThat(find(Object.class)).isEqualTo(ofGeneric(Object.class)); + } + + @Test + void nonEqualityCheck() { + final List> staticTypes = staticTypes().collect(Collectors.toList()); + final int L = staticTypes.size(); + for (int i = 0; i < L - 1; ++i) { + for (int j = i + 1; j < L; ++j) { + assertThat(staticTypes.get(i)).isNotEqualTo(staticTypes.get(j)); + assertThat(staticTypes.get(j)).isNotEqualTo(staticTypes.get(i)); + } + } + } +} diff --git a/qst/src/test/java/io/deephaven/qst/GenericTypeTest.java b/qst/src/test/java/io/deephaven/qst/GenericTypeTest.java new file mode 100644 index 00000000000..1010910ac22 --- /dev/null +++ b/qst/src/test/java/io/deephaven/qst/GenericTypeTest.java @@ -0,0 +1,59 @@ +package io.deephaven.qst; + +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import io.deephaven.qst.table.column.type.GenericType; +import org.junit.jupiter.api.Test; + +public class GenericTypeTest { + + @Test + public void noGenericInt() { + try { + GenericType.of(int.class); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void noGenericInteger() { + try { + GenericType.of(Integer.class); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void noGenericDoublePrimitive() { + try { + GenericType.of(double.class); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void noGenericDouble() { + try { + GenericType.of(Double.class); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void noGenericString() { + try { + GenericType.of(String.class); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } +} diff --git a/qst/src/test/java/io/deephaven/qst/table/NewTableTest.java b/qst/src/test/java/io/deephaven/qst/table/NewTableTest.java new file mode 100644 index 00000000000..09a84a47cf5 --- /dev/null +++ b/qst/src/test/java/io/deephaven/qst/table/NewTableTest.java @@ -0,0 +1,75 @@ +package io.deephaven.qst.table; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import io.deephaven.qst.table.column.Column; +import io.deephaven.qst.table.column.header.ColumnHeader; +import org.junit.jupiter.api.Test; + +public class NewTableTest { + + @Test + public void checkColumnSize() { + try { + NewTable.of( + Column.of("Size1", 1), + Column.of("Size2", 1, 2)); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void checkDistinctNames() { + try { + NewTable.of( + Column.of("Size1", 1), + Column.of("Size1", 2)); + failBecauseExceptionWasNotThrown(IllegalArgumentException.class); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void newTableHelperColumnOriented() { + NewTable expected = ImmutableNewTable.builder() + .size(3) + .addColumns(Column.builder(ColumnHeader.ofInt("X")) + .add(1).add(null).add(3) + .build()) + .build(); + + NewTable actual = NewTable.of(Column.of("X", 1, null, 3)); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void newTableHelperRowOriented() { + + Column x = Column.builder(ColumnHeader.ofInt("X")) + .add(1).add(2) + .build(); + + Column y = Column.builder(ColumnHeader.ofString("Y")) + .add("one").add("two") + .build(); + + NewTable expected = ImmutableNewTable.builder() + .size(2) + .addColumns(x, y) + .build(); + + NewTable actual = NewTable + .header("X", int.class) + .header("Y", String.class) + .row(1, "one") + .row(2, "two") + .build(); + + assertThat(actual).isEqualTo(expected); + } +} diff --git a/settings.gradle b/settings.gradle index fcda198bd99..fb251bfedef 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,7 @@ String[] mods = [ 'Util', 'Numerics', 'TableLogger', 'DB', 'Plot', 'CompilerTools', 'Generators', 'Integrations', 'ModelFarm', 'ClientSupport', 'BenchmarkSupport', 'DB-test', 'DbTypes', 'DbTypesImpl', 'Parquet', - 'KafkaIngester', 'grpc-api'] + 'KafkaIngester', 'grpc-api', 'qst'] // new web projects; these modules are intended to form a complete, modular web application, // with heavy dependency isolation that should enable very fast rebuilds.