|
1 | 1 | package org.jetbrains.kotlinx.dataframe.examples.jdbc.customdb |
2 | 2 |
|
3 | | -import org.jetbrains.kotlinx.dataframe.io.TableColumnMetadata |
4 | | -import org.jetbrains.kotlinx.dataframe.io.TableMetadata |
| 3 | +import kotlinx.datetime.LocalDate |
| 4 | +import kotlinx.datetime.toKotlinLocalDate |
| 5 | +import org.jetbrains.kotlinx.dataframe.DataColumn |
| 6 | +import org.jetbrains.kotlinx.dataframe.examples.jdbc.customdb.HSQLDB.getPreprocessedValueType |
| 7 | +import org.jetbrains.kotlinx.dataframe.examples.jdbc.customdb.HSQLDB.preprocessValue |
5 | 8 | import org.jetbrains.kotlinx.dataframe.io.db.DbType |
6 | | -import org.jetbrains.kotlinx.dataframe.schema.ColumnSchema |
| 9 | +import org.jetbrains.kotlinx.dataframe.io.db.TableColumnMetadata |
| 10 | +import org.jetbrains.kotlinx.dataframe.io.db.TableMetadata |
7 | 11 | import java.sql.ResultSet |
8 | | -import java.util.Locale |
| 12 | +import java.sql.Types |
9 | 13 | import kotlin.reflect.KType |
| 14 | +import kotlin.reflect.full.isSubtypeOf |
| 15 | +import kotlin.reflect.full.withNullability |
| 16 | +import kotlin.reflect.typeOf |
| 17 | +import java.sql.Date as SqlDate |
10 | 18 |
|
11 | 19 | /** |
12 | 20 | * Represents the HSQLDB database type. |
13 | 21 | * |
14 | | - * This class provides methods to convert data from a ResultSet to the appropriate type for HSQLDB, |
15 | | - * and to generate the corresponding column schema. |
| 22 | + * This object provides all functions to read data from a HSQLDB [ResultSet], |
| 23 | + * preprocess the values, and build [columns][DataColumn]. |
16 | 24 | */ |
17 | | -public object HSQLDB : DbType("hsqldb") { |
18 | | - override val driverClassName: String |
19 | | - get() = "org.hsqldb.jdbcDriver" |
| 25 | +object HSQLDB : DbType("hsqldb") { |
20 | 26 |
|
21 | | - override fun convertSqlTypeToColumnSchemaValue(tableColumnMetadata: TableColumnMetadata): ColumnSchema? { |
22 | | - return null |
| 27 | + /** The JDBC driver class name. */ |
| 28 | + override val driverClassName: String = "org.hsqldb.jdbcDriver" |
| 29 | + |
| 30 | + /** |
| 31 | + * This function should return the correct type of the value returned by [ResultSet.getObject] from JDBC |
| 32 | + * for the column with the given [tableColumnMetadata]. |
| 33 | + * [DbType] has a good default type-map, but your database type might deviate. |
| 34 | + * |
| 35 | + * Supplying these types helps you and DataFrame to correctly interpret and handle data from the database. |
| 36 | + */ |
| 37 | + override fun getExpectedJdbcType(tableColumnMetadata: TableColumnMetadata): KType = |
| 38 | + when (tableColumnMetadata.jdbcType) { |
| 39 | + // For example, here we say that we expect .getObject() to return a Java SQL Date |
| 40 | + // when the given JDBC SQL type is DATE |
| 41 | + Types.DATE -> typeOf<SqlDate>().withNullability(tableColumnMetadata.isNullable) |
| 42 | + |
| 43 | + // TODO this list is likely incomplete for HSQLDB |
| 44 | + |
| 45 | + // Else, we follow the default behavior |
| 46 | + else -> super.getExpectedJdbcType(tableColumnMetadata) |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * If you want to preprocess certain values before creating a [DataColumn], you can override this function. |
| 51 | + * [DbType] already has a few types of values being preprocessed, but you can customize this behavior. |
| 52 | + * |
| 53 | + * This function just specifies the type-behavior, [preprocessValue] actually does the preprocessing. |
| 54 | + */ |
| 55 | + override fun getPreprocessedValueType( |
| 56 | + tableColumnMetadata: TableColumnMetadata, |
| 57 | + expectedJdbcType: KType |
| 58 | + ): KType = |
| 59 | + when { |
| 60 | + // Let's say we want to convert java.sql.Date to kotlinx.datetime.LocalDate (taking nullability into account) |
| 61 | + expectedJdbcType.isSubtypeOf(typeOf<SqlDate?>()) -> |
| 62 | + typeOf<LocalDate>().withNullability(tableColumnMetadata.isNullable) |
| 63 | + |
| 64 | + // Else, we follow the default behavior |
| 65 | + else -> |
| 66 | + super.getPreprocessedValueType(tableColumnMetadata, expectedJdbcType) |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * This function actually preprocesses the values returned by [ResultSet.getObject], following the |
| 71 | + * [getPreprocessedValueType] type-behavior. |
| 72 | + */ |
| 73 | + override fun <J, D> preprocessValue( |
| 74 | + value: J, |
| 75 | + tableColumnMetadata: TableColumnMetadata, |
| 76 | + expectedJdbcType: KType, |
| 77 | + expectedPreprocessedValueType: KType |
| 78 | + ): D = when { |
| 79 | + // Here we actually perform the conversion from java.sql.Date to kotlinx.datetime.LocalDate |
| 80 | + expectedJdbcType.isSubtypeOf(typeOf<SqlDate?>()) -> |
| 81 | + (value as SqlDate?)?.toLocalDate()?.toKotlinLocalDate() as D |
| 82 | + |
| 83 | + // Else, we follow the default behavior |
| 84 | + else -> |
| 85 | + super.preprocessValue(value, tableColumnMetadata, expectedJdbcType, expectedPreprocessedValueType) |
23 | 86 | } |
24 | 87 |
|
25 | 88 | override fun isSystemTable(tableMetadata: TableMetadata): Boolean { |
26 | | - val locale = Locale.getDefault() |
27 | | - fun String?.containsWithLowercase(substr: String) = this?.lowercase(locale)?.contains(substr) == true |
28 | | - val schemaName = tableMetadata.schemaName |
29 | | - val name = tableMetadata.name |
30 | | - return schemaName.containsWithLowercase("information_schema") || |
31 | | - schemaName.containsWithLowercase("system") || |
32 | | - name.containsWithLowercase("system_") |
| 89 | + val schemaName = tableMetadata.schemaName.orEmpty().lowercase() |
| 90 | + val name = tableMetadata.name.lowercase() |
| 91 | + |
| 92 | + return "information_schema" in schemaName || |
| 93 | + "system" in schemaName || |
| 94 | + "system_" in name |
33 | 95 | } |
34 | 96 |
|
35 | 97 | override fun buildTableMetadata(tables: ResultSet): TableMetadata = |
36 | 98 | TableMetadata( |
37 | | - tables.getString("TABLE_NAME"), |
38 | | - tables.getString("TABLE_SCHEM"), |
39 | | - tables.getString("TABLE_CAT"), |
| 99 | + name = tables.getString("TABLE_NAME"), |
| 100 | + schemaName = tables.getString("TABLE_SCHEM"), |
| 101 | + catalogue = tables.getString("TABLE_CAT"), |
40 | 102 | ) |
41 | | - |
42 | | - override fun convertSqlTypeToKType(tableColumnMetadata: TableColumnMetadata): KType? { |
43 | | - return null |
44 | | - } |
45 | 103 | } |
0 commit comments