diff options
Diffstat (limited to 'opendc-trace/opendc-trace-api/src/main/kotlin')
15 files changed, 606 insertions, 251 deletions
diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/Table.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/Table.kt index 05d0234a..e6e97706 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/Table.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/Table.kt @@ -32,21 +32,16 @@ public interface Table { public val name: String /** - * The list of columns supported in this table. + * The columns in this table. */ - public val columns: List<TableColumn<*>> - - /** - * The columns by which the table is partitioned. - */ - public val partitionKeys: List<TableColumn<*>> + public val columns: List<TableColumn> /** * Open a [TableReader] for a projection of this table. * - * @param projection The list of columns to fetch from the table or `null` if no projection is performed. + * @param projection The names of the columns to fetch from the table or `null` if no projection is performed. */ - public fun newReader(projection: List<TableColumn<*>>? = null): TableReader + public fun newReader(projection: List<String>? = null): TableReader /** * Open a [TableWriter] for this table. diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumn.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumn.kt index b77a2982..0f75d890 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumn.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumn.kt @@ -22,47 +22,15 @@ package org.opendc.trace -import java.util.* - /** - * A column in a trace table. + * A column in a [Table]. * - * @param name The universal name of this column. + * @property name The universal name of this column. + * @property type The type of the column. + * @property isNullable A flag to indicate that the column is nullable. */ -public class TableColumn<out T>(public val name: String, type: Class<T>) { - /** - * The type of the column. - */ - public val type: Class<*> = type - - /** - * Determine whether the type of the column is a subtype of [column]. - */ - public fun isAssignableTo(column: TableColumn<*>): Boolean { - return name == column.name && type.isAssignableFrom(column.type) - } - - /** - * Compute a hash code for this column. - */ - public override fun hashCode(): Int = Objects.hash(name, type) - - /** - * Determine whether this column is equal to [other]. - */ - public override fun equals(other: Any?): Boolean { - // Fast-path: reference equality - if (this === other) { - return true - } else if (other == null || other !is TableColumn<*>) { - return false - } - - return name == other.name && type == other.type - } - - /** - * Return a string representation of this column. - */ - public override fun toString(): String = "TableColumn[$name,$type]" -} +public data class TableColumn( + public val name: String, + public val type: TableColumnType, + public val isNullable: Boolean = false +) diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumnType.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumnType.kt new file mode 100644 index 00000000..6cae47f9 --- /dev/null +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableColumnType.kt @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.trace + +/** + * The type of a [TableColumn]. + */ +public sealed class TableColumnType { + /** + * A column of booleans. + */ + public object Boolean : TableColumnType() + + /** + * A column of 32-bit integers. + */ + public object Int : TableColumnType() + + /** + * A column of 64-bit integers. + */ + public object Long : TableColumnType() + + /** + * A column of 32-bit floats. + */ + public object Float : TableColumnType() + + /** + * A column of 64-bit floats. + */ + public object Double : TableColumnType() + + /** + * A column of UUIDs. + */ + public object UUID : TableColumnType() + + /** + * A column of variable-length strings. + */ + public object String : TableColumnType() + + /** + * A column of timestamps, mapping to [java.time.Instant]. + */ + public object Instant : TableColumnType() + + /** + * A column of durations, mapping to [java.time.Duration] + */ + public object Duration : TableColumnType() + + /** + * A column containing embedded lists. + * + * @property elementType The type of the elements in the list. + */ + public data class List(public val elementType: TableColumnType) : TableColumnType() + + /** + * A column containing embedded sets. + * + * @property elementType The type of the elements in the sets. + */ + public data class Set(public val elementType: TableColumnType) : TableColumnType() + + /** + * A column containing embedded maps. + * + * @property keyType The type of the key. + * @property valueType The type of the value. + */ + public data class Map(public val keyType: TableColumnType, public val valueType: TableColumnType) : TableColumnType() +} diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableReader.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableReader.kt index 8a796e6c..42b1c690 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableReader.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableReader.kt @@ -22,8 +22,12 @@ package org.opendc.trace +import java.time.Duration +import java.time.Instant +import java.util.UUID + /** - * Base class for reading entities from a workload trace table in streaming fashion. + * Base class for reading entities from a [Table] in streaming fashion. */ public interface TableReader : AutoCloseable { /** @@ -34,20 +38,15 @@ public interface TableReader : AutoCloseable { public fun nextRow(): Boolean /** - * Resolve the index of the specified [column] for this reader. + * Resolve the index of the column by its [name]. * - * @param column The column to lookup. + * @param name The name of the column to lookup. * @return The zero-based index of the column or a negative value if the column is not present in this table. */ - public fun resolve(column: TableColumn<*>): Int - - /** - * Determine whether the [TableReader] supports the specified [column]. - */ - public fun hasColumn(column: TableColumn<*>): Boolean = resolve(column) >= 0 + public fun resolve(name: String): Int /** - * Determine whether the specified [column] has a `null` value for the current row. + * Determine whether the column with the specified [index] has a `null` value for the current row. * * @param index The zero-based index of the column to check for a null value. * @throws IllegalArgumentException if the column index is not valid for this reader. @@ -56,15 +55,6 @@ public interface TableReader : AutoCloseable { public fun isNull(index: Int): Boolean /** - * Obtain the object value of the column with the specified [index]. - * - * @param index The zero-based index of the column to obtain the value for. - * @throws IllegalArgumentException if the column index is not valid for this reader. - * @return The object value of the column. - */ - public fun get(index: Int): Any? - - /** * Obtain the boolean value of the column with the specified [index]. * * @param index The zero-based index of the column to obtain the value for. @@ -74,7 +64,7 @@ public interface TableReader : AutoCloseable { public fun getBoolean(index: Int): Boolean /** - * Obtain the integer value of the column with the specified [index]. + * Obtain the boolean value of the column with the specified [index]. * * @param index The zero-based index of the column to obtain the value for. * @throws IllegalArgumentException if the column index is not valid for this reader. @@ -92,6 +82,15 @@ public interface TableReader : AutoCloseable { public fun getLong(index: Int): Long /** + * Obtain the float value of the column with the specified [index]. + * + * @param index The zero-based index of the column to obtain the value for. + * @throws IllegalArgumentException if the column index is not valid for this reader. + * @return The float value of the column or [Float.NaN] if the column is `null`. + */ + public fun getFloat(index: Int): Float + + /** * Obtain the double value of the column with the specified [index]. * * @param index The zero-based index of the column to obtain the value for. @@ -101,62 +100,193 @@ public interface TableReader : AutoCloseable { public fun getDouble(index: Int): Double /** - * Determine whether the specified [column] has a `null` value for the current row. + * Obtain the [String] value of the column with the specified [index]. * - * @param column The column to lookup. - * @throws IllegalArgumentException if the column is not valid for this table. - * @return `true` if the column value for the current value has a `null` value, `false` otherwise. + * @param index The zero-based index of the column to obtain the value for. + * @throws IllegalArgumentException if the column index is not valid for this reader. + * @return The [String] value of the column or `null` if the column is `null`. */ - public fun isNull(column: TableColumn<*>): Boolean = isNull(resolve(column)) + public fun getString(index: Int): String? /** - * Obtain the value of the current column with type [T]. + * Obtain the [UUID] value of the column with the specified [index]. * - * @param column The column to obtain the value for. - * @throws IllegalArgumentException if the column is not valid for this reader. - * @return The object value of the column. + * @param index The zero-based index of the column to obtain the value for. + * @throws IllegalArgumentException if the column index is not valid for this reader. + * @return The [UUID] value of the column or `null` if the column is `null`. + */ + public fun getUUID(index: Int): UUID? + + /** + * Obtain the [Instant] value of the column with the specified [index]. + * + * @param index The zero-based index of the column to obtain the value for. + * @throws IllegalArgumentException if the column index is not valid for this reader. + * @return The [Instant] value of the column or `null` if the column is `null`. + */ + public fun getInstant(index: Int): Instant? + + /** + * Obtain the [Duration] value of the column with the specified [index]. + * + * @param index The zero-based index of the column to obtain the value for. + * @throws IllegalArgumentException if the column index is not valid for this reader. + * @return The [Duration] value of the column or `null` if the column is `null`. + */ + public fun getDuration(index: Int): Duration? + + /** + * Obtain the value of the column with the specified [index] as [List]. + * + * @param index The zero-based index of the column to obtain the value for. + * @param elementType Class representing the Java data type to convert elements of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `List` or `null` if the column is null. + */ + public fun <T> getList(index: Int, elementType: Class<T>): List<T>? + + /** + * Obtain the value of the column with the specified [index] as [Set]. + * + * @param index The zero-based index of the column to obtain the value for. + * @param elementType Class representing the Java data type to convert elements of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `Set` or `null` if the column is null. + */ + public fun <T> getSet(index: Int, elementType: Class<T>): Set<T>? + + /** + * Obtain the value of the column with the specified [index] as [Set]. + * + * @param index The zero-based index of the column to obtain the value for. + * @param keyType Class representing the Java data type to convert the keys of the designated column to. + * @param valueType Class representing the Java data type to convert the values of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `Map` or `null` if the column is null. + */ + public fun <K, V> getMap(index: Int, keyType: Class<K>, valueType: Class<V>): Map<K, V>? + + /** + * Determine whether a column named [name] has a `null` value for the current row. + * + * @param name The name of the column to lookup. + * @throws IllegalArgumentException if the column is not valid for this table. + * @return `true` if the column value for the current value has a `null` value, `false` otherwise. */ - public fun <T> get(column: TableColumn<T>): T { - // This cast should always succeed since the resolve the index of the typed column - @Suppress("UNCHECKED_CAST") - return get(resolve(column)) as T - } + public fun isNull(name: String): Boolean = isNull(resolve(name)) /** - * Read the specified [column] as boolean. + * Read the column named [name] as boolean. * - * @param column The column to obtain the value for. + * @param name The name of the column to get the value for. * @throws IllegalArgumentException if the column is not valid for this reader. * @return The boolean value of the column or `false` if the column is `null`. */ - public fun getBoolean(column: TableColumn<Boolean>): Boolean = getBoolean(resolve(column)) + public fun getBoolean(name: String): Boolean = getBoolean(resolve(name)) /** - * Read the specified [column] as integer. + * Read the column named [name] as integer. * - * @param column The column to obtain the value for. + * @param name The name of the column to get the value for. * @throws IllegalArgumentException if the column is not valid for this reader. * @return The integer value of the column or `0` if the column is `null`. */ - public fun getInt(column: TableColumn<Int>): Int = getInt(resolve(column)) + public fun getInt(name: String): Int = getInt(resolve(name)) /** - * Read the specified [column] as long. + * Read the column named [name] as long. * - * @param column The column to obtain the value for. + * @param name The name of the column to get the value for * @throws IllegalArgumentException if the column is not valid for this reader. * @return The long value of the column or `0` if the column is `null`. */ - public fun getLong(column: TableColumn<Long>): Long = getLong(resolve(column)) + public fun getLong(name: String): Long = getLong(resolve(name)) + + /** + * Read the column named [name] as float. + * + * @param name The name of the column to get the value for. + * @throws IllegalArgumentException if the column is not valid for this reader. + * @return The float value of the column or [Float.NaN] if the column is `null`. + */ + public fun getFloat(name: String): Float = getFloat(resolve(name)) /** - * Read the specified [column] as double. + * Read the column named [name] as double. * - * @param column The column to obtain the value for. + * @param name The name of the column to get the value for. * @throws IllegalArgumentException if the column is not valid for this reader. * @return The double value of the column or [Double.NaN] if the column is `null`. */ - public fun getDouble(column: TableColumn<Double>): Double = getDouble(resolve(column)) + public fun getDouble(name: String): Double = getDouble(resolve(name)) + + /** + * Read the column named [name] as [String]. + * + * @param name The name of the column to get the value for. + * @throws IllegalArgumentException if the column is not valid for this reader. + * @return The [String] value of the column or `null` if the column is `null`. + */ + public fun getString(name: String): String? = getString(resolve(name)) + + /** + * Read the column named [name] as [UUID]. + * + * @param name The name of the column to get the value for. + * @throws IllegalArgumentException if the column is not valid for this reader. + * @return The [UUID] value of the column or `null` if the column is `null`. + */ + public fun getUUID(name: String): UUID? = getUUID(resolve(name)) + + /** + * Read the column named [name] as [Instant]. + * + * @param name The name of the column to get the value for. + * @throws IllegalArgumentException if the column is not valid for this reader. + * @return The [Instant] value of the column or `null` if the column is `null`. + */ + public fun getInstant(name: String): Instant? = getInstant(resolve(name)) + + /** + * Read the column named [name] as [Duration]. + * + * @param name The name of the column to get the value for. + * @throws IllegalArgumentException if the column is not valid for this reader. + * @return The [Duration] value of the column or `null` if the column is `null`. + */ + public fun getDuration(name: String): Duration? = getDuration(resolve(name)) + + /** + * Obtain the value of the column named [name] as [List]. + * + * @param name The name of the column to get the value for. + * @param elementType Class representing the Java data type to convert elements of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `List` or `null` if the column is null. + */ + public fun <T> getList(name: String, elementType: Class<T>): List<T>? = getList(resolve(name), elementType) + + /** + * Obtain the value of the column named [name] as [Set]. + * + * @param name The name of the column to get the value for. + * @param elementType Class representing the Java data type to convert elements of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `Set` or `null` if the column is null. + */ + public fun <T> getSet(name: String, elementType: Class<T>): Set<T>? = getSet(resolve(name), elementType) + + /** + * Obtain the value of the column named [name] as [Set]. + * + * @param name The name of the column to get the value for. + * @param keyType Class representing the Java data type to convert the keys of the designated column to. + * @param valueType Class representing the Java data type to convert the values of the designated column to. + * @throws IllegalArgumentException if the column index is not valid for this reader or this type. + * @return The value of the column as `Map` or `null` if the column is null. + */ + public fun <K, V> getMap(name: String, keyType: Class<K>, valueType: Class<V>): Map<K, V>? = + getMap(resolve(name), keyType, valueType) /** * Closes the reader so that no further iteration or data access can be made. diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableWriter.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableWriter.kt index 423ce86a..a3122ec9 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableWriter.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/TableWriter.kt @@ -22,6 +22,10 @@ package org.opendc.trace +import java.time.Duration +import java.time.Instant +import java.util.* + /** * Base class for writing workload traces. */ @@ -37,107 +41,228 @@ public interface TableWriter : AutoCloseable { public fun endRow() /** - * Resolve the index of the specified [column] for this writer. + * Resolve the index of the column named [name] for this writer. * - * @param column The column to lookup. + * @param name The name of the column to lookup. * @return The zero-based index of the column or a negative value if the column is not present in this table. */ - public fun resolve(column: TableColumn<*>): Int + public fun resolve(name: String): Int /** - * Determine whether the [TableReader] supports the specified [column]. + * Set the column with index [index] to boolean [value]. + * + * @param index The zero-based index of the column to set the value for. + * @param value The boolean value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun hasColumn(column: TableColumn<*>): Boolean = resolve(column) >= 0 + public fun setBoolean(index: Int, value: Boolean) /** - * Set [column] to [value]. + * Set the column with index [index] to integer [value]. * * @param index The zero-based index of the column to set the value for. - * @param value The value to set the column to. + * @param value The integer value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun set(index: Int, value: Any) + public fun setInt(index: Int, value: Int) /** - * Set [column] to boolean [value]. + * Set the column with index [index] to long [value]. * * @param index The zero-based index of the column to set the value for. - * @param value The boolean value to set the column to. + * @param value The long value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setBoolean(index: Int, value: Boolean) + public fun setLong(index: Int, value: Long) /** - * Set [column] to integer [value]. + * Set the column with index [index] to float [value]. * * @param index The zero-based index of the column to set the value for. - * @param value The integer value to set the column to. + * @param value The float value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setInt(index: Int, value: Int) + public fun setFloat(index: Int, value: Float) /** - * Set [column] to long [value]. + * Set the column with index [index] to double [value]. * * @param index The zero-based index of the column to set the value for. - * @param value The long value to set the column to. + * @param value The double value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setLong(index: Int, value: Long) + public fun setDouble(index: Int, value: Double) /** - * Set [column] to double [value]. + * Set the column with index [index] to [String] [value]. * * @param index The zero-based index of the column to set the value for. - * @param value The double value to set the column to. + * @param value The [String] value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setDouble(index: Int, value: Double) + public fun setString(index: Int, value: String) + + /** + * Set the column with index [index] to [UUID] [value]. + * + * @param index The zero-based index of the column to set the value for. + * @param value The [UUID] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setUUID(index: Int, value: UUID) + + /** + * Set the column with index [index] to [Instant] [value]. + * + * @param index The zero-based index of the column to set the value for. + * @param value The [Instant] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setInstant(index: Int, value: Instant) /** - * Set [column] to [value]. + * Set the column with index [index] to [Duration] [value]. * - * @param column The column to set the value for. - * @param value The value to set the column to. + * @param index The zero-based index of the column to set the value for. + * @param value The [Duration] value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun <T : Any> set(column: TableColumn<T>, value: T): Unit = set(resolve(column), value) + public fun setDuration(index: Int, value: Duration) /** - * Set [column] to boolean [value]. + * Set the column with index [index] to [List] [value]. * - * @param column The column to set the value for. + * @param index The zero-based index of the column to set the value for. + * @param value The [Map] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <T> setList(index: Int, value: List<T>) + + /** + * Set the column with index [index] to [Set] [value]. + * + * @param index The zero-based index of the column to set the value for. + * @param value The [Set] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <T> setSet(index: Int, value: Set<T>) + + /** + * Set the column with index [index] to [Map] [value]. + * + * @param index The zero-based index of the column to set the value for. + * @param value The [Map] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <K, V> setMap(index: Int, value: Map<K, V>) + + /** + * Set the column named [name] to boolean [value]. + * + * @param name The name of the column to set the value for. * @param value The boolean value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setBoolean(column: TableColumn<Boolean>, value: Boolean): Unit = setBoolean(resolve(column), value) + public fun setBoolean(name: String, value: Boolean): Unit = setBoolean(resolve(name), value) /** - * Set [column] to integer [value]. + * Set the column named [name] to integer [value]. * - * @param column The column to set the value for. + * @param name The name of the column to set the value for. * @param value The integer value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setInt(column: TableColumn<Int>, value: Int): Unit = setInt(resolve(column), value) + public fun setInt(name: String, value: Int): Unit = setInt(resolve(name), value) /** - * Set [column] to long [value]. + * Set the column named [name] to long [value]. * - * @param column The column to set the value for. + * @param name The name of the column to set the value for. * @param value The long value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setLong(column: TableColumn<Long>, value: Long): Unit = setLong(resolve(column), value) + public fun setLong(name: String, value: Long): Unit = setLong(resolve(name), value) + + /** + * Set the column named [name] to float [value]. + * + * @param name The name of the column to set the value for. + * @param value The float value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setFloat(name: String, value: Float): Unit = setFloat(resolve(name), value) /** - * Set [column] to double [value]. + * Set the column named [name] to double [value]. * - * @param column The column to set the value for. + * @param name The name of the column to set the value for. * @param value The double value to set the column to. * @throws IllegalArgumentException if the column is not valid for this method. */ - public fun setDouble(column: TableColumn<Double>, value: Double): Unit = setDouble(resolve(column), value) + public fun setDouble(name: String, value: Double): Unit = setDouble(resolve(name), value) + + /** + * Set the column named [name] to [String] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [String] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setString(name: String, value: String): Unit = setString(resolve(name), value) + + /** + * Set the column named [name] to [UUID] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [UUID] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setUUID(name: String, value: UUID): Unit = setUUID(resolve(name), value) + + /** + * Set the column named [name] to [Instant] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [Instant] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setInstant(name: String, value: Instant): Unit = setInstant(resolve(name), value) + + /** + * Set the column named [name] to [Duration] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [Duration] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun setDuration(name: String, value: Duration): Unit = setDuration(resolve(name), value) + + /** + * Set the column named [name] to [List] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [List] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <T> setList(name: String, value: List<T>): Unit = setList(resolve(name), value) + + /** + * Set the column named [name] to [Set] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [Set] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <T> setSet(name: String, value: Set<T>): Unit = setSet(resolve(name), value) + + /** + * Set the column named [name] to [Map] [value]. + * + * @param name The name of the column to set the value for. + * @param value The [Map] value to set the column to. + * @throws IllegalArgumentException if the column is not valid for this method. + */ + public fun <K, V> setMap(name: String, value: Map<K, V>): Unit = setMap(resolve(name), value) /** * Flush any buffered content to the underlying target. diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/InterferenceGroupColumns.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/InterferenceGroupColumns.kt index 5e8859e4..2a80687c 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/InterferenceGroupColumns.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/InterferenceGroupColumns.kt @@ -23,22 +23,17 @@ @file:JvmName("InterferenceGroupColumns") package org.opendc.trace.conv -import org.opendc.trace.TableColumn - /** * Members of the interference group. */ -@JvmField -public val INTERFERENCE_GROUP_MEMBERS: TableColumn<Set<String>> = column("members") +public const val INTERFERENCE_GROUP_MEMBERS: String = "members" /** * Target load after which the interference occurs. */ -@JvmField -public val INTERFERENCE_GROUP_TARGET: TableColumn<Double> = column("target") +public const val INTERFERENCE_GROUP_TARGET: String = "target" /** * Performance score when the interference occurs. */ -@JvmField -public val INTERFERENCE_GROUP_SCORE: TableColumn<Double> = column("score") +public const val INTERFERENCE_GROUP_SCORE: String = "score" diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceColumns.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceColumns.kt index e602e534..9b7b8195 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceColumns.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceColumns.kt @@ -23,47 +23,44 @@ @file:JvmName("ResourceColumns") package org.opendc.trace.conv -import org.opendc.trace.TableColumn -import java.time.Instant - /** * Identifier of the resource. */ @JvmField -public val RESOURCE_ID: TableColumn<String> = column("id") +public val RESOURCE_ID: String = "id" /** * The cluster to which the resource belongs. */ @JvmField -public val RESOURCE_CLUSTER_ID: TableColumn<String> = column("cluster_id") +public val RESOURCE_CLUSTER_ID: String = "cluster_id" /** * Start time for the resource. */ @JvmField -public val RESOURCE_START_TIME: TableColumn<Instant> = column("start_time") +public val RESOURCE_START_TIME: String = "start_time" /** * End time for the resource. */ @JvmField -public val RESOURCE_STOP_TIME: TableColumn<Instant> = column("stop_time") +public val RESOURCE_STOP_TIME: String = "stop_time" /** * Number of CPUs for the resource. */ @JvmField -public val RESOURCE_CPU_COUNT: TableColumn<Int> = column("cpu_count") +public val RESOURCE_CPU_COUNT: String = "cpu_count" /** * Total CPU capacity of the resource in MHz. */ @JvmField -public val RESOURCE_CPU_CAPACITY: TableColumn<Double> = column("cpu_capacity") +public val RESOURCE_CPU_CAPACITY: String = "cpu_capacity" /** * Memory capacity for the resource in KB. */ @JvmField -public val RESOURCE_MEM_CAPACITY: TableColumn<Double> = column("mem_capacity") +public val RESOURCE_MEM_CAPACITY: String = "mem_capacity" diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceStateColumns.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceStateColumns.kt index 3a44f817..e9dd7673 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceStateColumns.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/ResourceStateColumns.kt @@ -23,78 +23,74 @@ @file:JvmName("ResourceStateColumns") package org.opendc.trace.conv -import org.opendc.trace.TableColumn -import java.time.Duration -import java.time.Instant - /** * The timestamp at which the state was recorded. */ @JvmField -public val RESOURCE_STATE_TIMESTAMP: TableColumn<Instant> = column("timestamp") +public val RESOURCE_STATE_TIMESTAMP: String = "timestamp" /** * Duration for the state. */ @JvmField -public val RESOURCE_STATE_DURATION: TableColumn<Duration> = column("duration") +public val RESOURCE_STATE_DURATION: String = "duration" /** * A flag to indicate that the resource is powered on. */ @JvmField -public val RESOURCE_STATE_POWERED_ON: TableColumn<Boolean> = column("powered_on") +public val RESOURCE_STATE_POWERED_ON: String = "powered_on" /** * Total CPU usage of the resource in MHz. */ @JvmField -public val RESOURCE_STATE_CPU_USAGE: TableColumn<Double> = column("cpu_usage") +public val RESOURCE_STATE_CPU_USAGE: String = "cpu_usage" /** * Total CPU usage of the resource in percentage. */ @JvmField -public val RESOURCE_STATE_CPU_USAGE_PCT: TableColumn<Double> = column("cpu_usage_pct") +public val RESOURCE_STATE_CPU_USAGE_PCT: String = "cpu_usage_pct" /** * Total CPU demand of the resource in MHz. */ @JvmField -public val RESOURCE_STATE_CPU_DEMAND: TableColumn<Double> = column("cpu_demand") +public val RESOURCE_STATE_CPU_DEMAND: String = "cpu_demand" /** * CPU ready percentage. */ @JvmField -public val RESOURCE_STATE_CPU_READY_PCT: TableColumn<Double> = column("cpu_ready_pct") +public val RESOURCE_STATE_CPU_READY_PCT: String = "cpu_ready_pct" /** * Memory usage of the resource in KB. */ @JvmField -public val RESOURCE_STATE_MEM_USAGE: TableColumn<Double> = column("mem_usage") +public val RESOURCE_STATE_MEM_USAGE: String = "mem_usage" /** * Disk read throughput of the resource in KB/s. */ @JvmField -public val RESOURCE_STATE_DISK_READ: TableColumn<Double> = column("disk_read") +public val RESOURCE_STATE_DISK_READ: String = "disk_read" /** * Disk write throughput of the resource in KB/s. */ @JvmField -public val RESOURCE_STATE_DISK_WRITE: TableColumn<Double> = column("disk_write") +public val RESOURCE_STATE_DISK_WRITE: String = "disk_write" /** * Network receive throughput of the resource in KB/s. */ @JvmField -public val RESOURCE_STATE_NET_RX: TableColumn<Double> = column("net_rx") +public val RESOURCE_STATE_NET_RX: String = "net_rx" /** * Network transmit throughput of the resource in KB/s. */ @JvmField -public val RESOURCE_STATE_NET_TX: TableColumn<Double> = column("net_tx") +public val RESOURCE_STATE_NET_TX: String = "net_tx" diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TableColumns.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TableColumns.kt deleted file mode 100644 index a58505e9..00000000 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TableColumns.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2021 AtLarge Research - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -@file:JvmName("TableColumns") -package org.opendc.trace.conv - -import org.opendc.trace.TableColumn - -/** - * Construct a [TableColumn] with the specified [name] and type [T]. - */ -public inline fun <reified T> column(name: String): TableColumn<T> = column(name, T::class.java) - -/** - * Construct a [TableColumn] with the specified [name] and [type]. - */ -public fun <T> column(name: String, type: Class<T>): TableColumn<T> = TableColumn(name, type) diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TaskColumns.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TaskColumns.kt index e6daafb7..da5c343f 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TaskColumns.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/conv/TaskColumns.kt @@ -23,78 +23,62 @@ @file:JvmName("TaskColumns") package org.opendc.trace.conv -import org.opendc.trace.TableColumn -import java.time.Duration -import java.time.Instant - /** * A column containing the task identifier. */ -@JvmField -public val TASK_ID: TableColumn<String> = column("id") +public const val TASK_ID: String = "id" /** * A column containing the identifier of the workflow. */ -@JvmField -public val TASK_WORKFLOW_ID: TableColumn<String> = column("workflow_id") +public const val TASK_WORKFLOW_ID: String = "workflow_id" /** * A column containing the submission time of the task. */ -@JvmField -public val TASK_SUBMIT_TIME: TableColumn<Instant> = column("submit_time") +public const val TASK_SUBMIT_TIME: String = "submit_time" /** * A column containing the wait time of the task. */ -@JvmField -public val TASK_WAIT_TIME: TableColumn<Instant> = column("wait_time") +public const val TASK_WAIT_TIME: String = "wait_time" /** * A column containing the runtime time of the task. */ -@JvmField -public val TASK_RUNTIME: TableColumn<Duration> = column("runtime") +public const val TASK_RUNTIME: String = "runtime" /** * A column containing the parents of a task. */ -@JvmField -public val TASK_PARENTS: TableColumn<Set<String>> = column("parents") +public const val TASK_PARENTS: String = "parents" /** * A column containing the children of a task. */ -@JvmField -public val TASK_CHILDREN: TableColumn<Set<String>> = column("children") +public const val TASK_CHILDREN: String = "children" /** * A column containing the requested CPUs of a task. */ -@JvmField -public val TASK_REQ_NCPUS: TableColumn<Int> = column("req_ncpus") +public const val TASK_REQ_NCPUS: String = "req_ncpus" /** * A column containing the allocated CPUs of a task. */ -@JvmField -public val TASK_ALLOC_NCPUS: TableColumn<Int> = column("alloc_ncpus") +public const val TASK_ALLOC_NCPUS: String = "alloc_ncpus" /** * A column containing the status of a task. */ -@JvmField -public val TASK_STATUS: TableColumn<Int> = column("status") +public const val TASK_STATUS: String = "status" /** * A column containing the group id of a task. */ -@JvmField -public val TASK_GROUP_ID: TableColumn<Int> = column("group_id") +public const val TASK_GROUP_ID: String = "group_id" /** * A column containing the user id of a task. */ -@JvmField -public val TASK_USER_ID: TableColumn<Int> = column("user_id") +public const val TASK_USER_ID: String = "user_id" diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/internal/TableImpl.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/internal/TableImpl.kt index b848e19a..1e1bf676 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/internal/TableImpl.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/internal/TableImpl.kt @@ -37,13 +37,10 @@ internal class TableImpl(val trace: TraceImpl, override val name: String) : Tabl */ private val details = trace.format.getDetails(trace.path, name) - override val columns: List<TableColumn<*>> + override val columns: List<TableColumn> get() = details.columns - override val partitionKeys: List<TableColumn<*>> - get() = details.partitionKeys - - override fun newReader(projection: List<TableColumn<*>>?): TableReader { + override fun newReader(projection: List<String>?): TableReader { return trace.format.newReader(trace.path, name, projection) } diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TableDetails.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TableDetails.kt index 1a9b9ee1..5206d02b 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TableDetails.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TableDetails.kt @@ -29,9 +29,5 @@ import org.opendc.trace.TableColumn * A class used by the [TraceFormat] interface for describing the metadata of a [Table]. * * @param columns The available columns in the table. - * @param partitionKeys The table columns that act as partition keys for the table. */ -public data class TableDetails( - val columns: List<TableColumn<*>>, - val partitionKeys: List<TableColumn<*>> = emptyList() -) +public data class TableDetails(val columns: List<TableColumn>) diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TraceFormat.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TraceFormat.kt index 47761e0f..eff6fa83 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TraceFormat.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/spi/TraceFormat.kt @@ -22,7 +22,6 @@ package org.opendc.trace.spi -import org.opendc.trace.TableColumn import org.opendc.trace.TableReader import org.opendc.trace.TableWriter import java.nio.file.Path @@ -69,11 +68,11 @@ public interface TraceFormat { * * @param path The path to the trace to open. * @param table The name of the table to open a [TableReader] for. - * @param projection The list of [TableColumn]s to project or `null` if no projection is performed. + * @param projection The name of the columns to project or `null` if no projection is performed. * @throws IllegalArgumentException If [table] does not exist. * @return A [TableReader] instance for the table. */ - public fun newReader(path: Path, table: String, projection: List<TableColumn<*>>?): TableReader + public fun newReader(path: Path, table: String, projection: List<String>?): TableReader /** * Open a [TableWriter] for the specified [table]. diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/CompositeTableReader.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/CompositeTableReader.kt index 11e032c7..c4854265 100644 --- a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/CompositeTableReader.kt +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/CompositeTableReader.kt @@ -22,8 +22,10 @@ package org.opendc.trace.util -import org.opendc.trace.TableColumn import org.opendc.trace.TableReader +import java.time.Duration +import java.time.Instant +import java.util.* /** * A helper class to chain multiple [TableReader]s. @@ -63,11 +65,11 @@ public abstract class CompositeTableReader : TableReader { return delegate != null } - override fun resolve(column: TableColumn<*>): Int { + override fun resolve(name: String): Int { tryStart() val delegate = delegate - return delegate?.resolve(column) ?: -1 + return delegate?.resolve(name) ?: -1 } override fun isNull(index: Int): Boolean { @@ -75,11 +77,6 @@ public abstract class CompositeTableReader : TableReader { return delegate.isNull(index) } - override fun get(index: Int): Any? { - val delegate = checkNotNull(delegate) { "Invalid reader state" } - return delegate.get(index) - } - override fun getBoolean(index: Int): Boolean { val delegate = checkNotNull(delegate) { "Invalid reader state" } return delegate.getBoolean(index) @@ -95,11 +92,51 @@ public abstract class CompositeTableReader : TableReader { return delegate.getLong(index) } + override fun getFloat(index: Int): Float { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getFloat(index) + } + override fun getDouble(index: Int): Double { val delegate = checkNotNull(delegate) { "Invalid reader state" } return delegate.getDouble(index) } + override fun getString(index: Int): String? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getString(index) + } + + override fun getUUID(index: Int): UUID? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getUUID(index) + } + + override fun getInstant(index: Int): Instant? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getInstant(index) + } + + override fun getDuration(index: Int): Duration? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getDuration(index) + } + + override fun <T> getList(index: Int, elementType: Class<T>): List<T>? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getList(index, elementType) + } + + override fun <T> getSet(index: Int, elementType: Class<T>): Set<T>? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getSet(index, elementType) + } + + override fun <K, V> getMap(index: Int, keyType: Class<K>, valueType: Class<V>): Map<K, V>? { + val delegate = checkNotNull(delegate) { "Invalid reader state" } + return delegate.getMap(index, keyType, valueType) + } + override fun close() { delegate?.close() } diff --git a/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/TableColumnConversion.kt b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/TableColumnConversion.kt new file mode 100644 index 00000000..8ef080b5 --- /dev/null +++ b/opendc-trace/opendc-trace-api/src/main/kotlin/org/opendc/trace/util/TableColumnConversion.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +@file:JvmName("TableColumnConversions") +package org.opendc.trace.util + +import org.opendc.trace.TableColumnType +import java.time.Duration +import java.time.Instant +import java.util.UUID + +/** + * Helper method to convert a [List] into a [List] with elements of [targetElementType]. + */ +public fun <T> TableColumnType.List.convertTo(value: List<*>?, targetElementType: Class<T>): List<T>? { + require(elementType.isCompatible(targetElementType)) { "Target element type is not compatible with $elementType" } + @Suppress("UNCHECKED_CAST") + return value as List<T>? +} + +/** + * Helper method to convert a [Set] into a [Set] with elements of [targetElementType]. + */ +public fun <T> TableColumnType.Set.convertTo(value: Set<*>?, targetElementType: Class<T>): Set<T>? { + require(elementType.isCompatible(targetElementType)) { "Target element type is not compatible with $elementType" } + @Suppress("UNCHECKED_CAST") + return value as Set<T>? +} + +/** + * Helper method to convert a [Map] into a [Map] with [targetKeyType] keys and [targetValueType] values. + */ +public fun <K, V> TableColumnType.Map.convertTo(value: Map<*, *>?, targetKeyType: Class<K>, targetValueType: Class<V>): Map<K, V>? { + require(keyType.isCompatible(targetKeyType)) { "Target key type $targetKeyType is not compatible with $keyType" } + require(valueType.isCompatible(targetValueType)) { "Target value type $targetValueType is not compatible with $valueType" } + @Suppress("UNCHECKED_CAST") + return value as Map<K, V>? +} + +/** + * Helper method to determine [javaType] is compatible with this [TableColumnType]. + */ +private fun TableColumnType.isCompatible(javaType: Class<*>): Boolean { + return when (this) { + is TableColumnType.Boolean -> javaType.isAssignableFrom(Boolean::class.java) + is TableColumnType.Int -> javaType.isAssignableFrom(Int::class.java) + is TableColumnType.Long -> javaType.isAssignableFrom(Long::class.java) + is TableColumnType.Float -> javaType.isAssignableFrom(Float::class.java) + is TableColumnType.Double -> javaType.isAssignableFrom(Double::class.java) + is TableColumnType.String -> javaType.isAssignableFrom(String::class.java) + is TableColumnType.UUID -> javaType.isAssignableFrom(UUID::class.java) + is TableColumnType.Instant -> javaType.isAssignableFrom(Instant::class.java) + is TableColumnType.Duration -> javaType.isAssignableFrom(Duration::class.java) + is TableColumnType.List -> javaType.isAssignableFrom(List::class.java) + is TableColumnType.Set -> javaType.isAssignableFrom(Set::class.java) + is TableColumnType.Map -> javaType.isAssignableFrom(Map::class.java) + } +} |
