Skip to content

Commit

Permalink
Merge pull request #39 from hasura/codedmart/type-rep
Browse files Browse the repository at this point in the history
ndc-spec type representation
  • Loading branch information
gneeri authored Jan 23, 2025
2 parents fe771ad + 67126aa commit 6556883
Show file tree
Hide file tree
Showing 16 changed files with 1,212 additions and 315 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import io.hasura.ndc.app.interfaces.ISchemaGenerator
import io.hasura.ndc.common.ConnectorConfiguration
import io.hasura.ndc.common.*
import io.hasura.ndc.ir.*
import jakarta.enterprise.context.ApplicationScoped
import jakarta.enterprise.inject.Default

abstract class JDBCSchemaGenerator(
private val supportsMutations: Boolean = false
Expand All @@ -15,6 +13,7 @@ abstract class JDBCSchemaGenerator(

abstract fun mapScalarType(
columnTypeStr: String,
numericPrecision: Int?,
numericScale: Int?
): NDCScalar

Expand Down Expand Up @@ -52,8 +51,8 @@ abstract class JDBCSchemaGenerator(
description = it.description,
arguments = emptyMap(),
type = when (it.nullable) {
true -> Type.Nullable(Type.Named(mapScalarType(it.type, it.numeric_scale).name))
false -> Type.Named(mapScalarType(it.type, it.numeric_scale).name)
true -> Type.Nullable(Type.Named(mapScalarType(it.type, it.numeric_precision, it.numeric_scale).name))
false -> Type.Named(mapScalarType(it.type, it.numeric_precision, it.numeric_scale).name)
}
)
}
Expand Down Expand Up @@ -87,7 +86,7 @@ abstract class JDBCSchemaGenerator(
name = function.function_name,
description = function.comment,
arguments = emptyMap(),
result_type = Type.Named(mapScalarType(function.data_type, null).name)
result_type = Type.Named(mapScalarType(function.data_type, null, null).name)
)
}

Expand All @@ -111,4 +110,30 @@ abstract class JDBCSchemaGenerator(
override fun getSchema(config: ConnectorConfiguration): SchemaResponse {
return buildSchema(config.tables, config.functions, config.nativeQueries)
}

fun mapNumericPrecisionAndScaleToNDCScalar(
precision: Int,
scale: Int
): NDCScalar {
return when {
scale != 0 -> when {
// FLOAT32: Up to 7 digits (values from -3.4028235E+38 to 3.4028235E+38).
precision <= 7 -> NDCScalar.FLOAT32
// FLOAT64: Up to 15 digits (values from -1.7976931348623157E+308 to 1.7976931348623157E+308).
precision <= 15 -> NDCScalar.FLOAT64
// BIGDECIMAL: More than 15 digits.
else -> NDCScalar.BIGDECIMAL
}
// INT8: Up to 3 digits (values from -128 to 127).
precision <= 3 -> NDCScalar.INT8
// INT16: Up to 5 digits (values from -32,768 to 32,767).
precision <= 5 -> NDCScalar.INT16
// INT32: Up to 10 digits (values from -2,147,483,648 to 2,147,483,647).
precision <= 10 -> NDCScalar.INT32
// INT64: Up to 19 digits (values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).
precision <= 19 -> NDCScalar.INT64
// BIGINTEGER: More than 19 digits.
else -> NDCScalar.BIGINTEGER
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ object MySQLConfigGenerator : IConfigGenerator {

//language=MySQL
val sql = """
SELECT
SELECT
concat(tables.TABLE_SCHEMA, '.', tables.TABLE_NAME) AS TABLE_NAME,
tables.TABLE_TYPE,
tables.table_COMMENT as DESCRIPTION,
Expand All @@ -45,6 +45,7 @@ object MySQLConfigGenerator : IConfigGenerator {
'name', columns.column_name,
'description', columns.column_comment,
'type', columns.data_type,
'numeric_precision', columns.numeric_precision,
'numeric_scale', columns.numeric_scale,
'nullable', if (columns.is_nullable = 'yes', true, false),
'auto_increment', if(columns.extra = 'auto_increment',true,false),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ object OracleConfigGenerator : IConfigGenerator {
'description' VALUE column_comments.COMMENTS,
'type' VALUE columns.DATA_TYPE,
'numeric_scale' VALUE columns.DATA_SCALE,
'numeric_precision' VALUE columns.DATA_PRECISION,
'nullable' VALUE case when columns.NULLABLE = 'Y' then 'true' else 'false' end,
'auto_increment' VALUE case when columns.IDENTITY_COLUMN = 'YES' then 'true' else 'false' end
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ object SnowflakeConfigGenerator : IConfigGenerator {
'name', columns.column_name,
'description', columns.comment,
'type', columns.data_type,
'numeric_precision', columns.numeric_precision,
'numeric_scale', columns.numeric_scale,
'nullable', to_boolean(columns.is_nullable),
'auto_increment', to_boolean(columns.is_identity)
Expand Down
27 changes: 26 additions & 1 deletion ndc-cli/src/main/kotlin/io/hasura/cli/TrinoConfigGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ object TrinoConfigGenerator : IConfigGenerator {
WHERE table_schema = current_schema
""".trimIndent()


// Take a string of the format "decimal(20)" or "decimal(20,2)" and extract the numeric precision and scale
fun extractNumericPrecisionAndScale(
decimalString: String
): Pair<Int, Int> {
val (precision, scale) = decimalString
.substringAfter("(")
.substringBefore(")")
.let {
when {
it.contains(",") -> it.split(",")
else -> listOf(it, "0")
}
}
.map { it.toInt() }
return precision to scale
}

// fetch every column, use jOOQ's fetchGroups to group them by table_name
val tables = ctx.resultQuery(sql).fetchGroups("table_name").map { (tableName, rows) ->
TableSchemaRow(
Expand All @@ -38,19 +56,26 @@ object TrinoConfigGenerator : IConfigGenerator {
pks = emptyList(),
fks = emptyMap(),
columns = rows.map { row ->
val dataType = row.get("data_type", String::class.java)
val (numericPrecision, numericScale) = when {
dataType.startsWith("decimal") -> extractNumericPrecisionAndScale(dataType)
else -> null to null
}
ColumnSchemaRow(
name = row.get("column_name", String::class.java),
type = row.get("data_type", String::class.java),
nullable = row.get("is_nullable", String::class.java) == "YES",
auto_increment = false,
is_primarykey = false,
description = null,
numeric_scale = null
numeric_precision = numericPrecision,
numeric_scale = numericScale
)
},
)
}


return ConnectorConfiguration(
jdbcUrl = jdbcUrl,
jdbcProperties = emptyMap(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.hasura.ndc.common.NDCScalar
import io.hasura.ndc.ir.*
import io.hasura.ndc.ir.Field.ColumnField
import io.hasura.ndc.ir.Field as IRField
import io.hasura.ndc.ir.Type
import io.hasura.ndc.sqlgen.BaseQueryGenerator
import org.jooq.*
import org.jooq.Field
Expand Down Expand Up @@ -123,12 +124,16 @@ object JsonQueryGenerator : BaseQueryGenerator() {
(request.query.fields ?: emptyMap()).map { (alias, field) ->
when (field) {
is ColumnField -> {
val columnField = DSL.field(DSL.name(field.column))
val (columnType, ndcScalar) = columnTypeTojOOQType(
MySQLJDBCSchemaGenerator::mapScalarType,
request.collection,
field
)
val castedField = castToSQLDataType(MYSQL, columnField, ndcScalar)
DSL.jsonEntry(
alias,
DSL.field(
DSL.name(field.column),
// columnTypeTojOOQType(request.collection, field)
)
castedField
)
}

Expand Down Expand Up @@ -230,31 +235,6 @@ object JsonQueryGenerator : BaseQueryGenerator() {
}
}

private fun ndcScalarTypeToSQLDataType(scalarType: NDCScalar): DataType<out Any> = when (scalarType) {
NDCScalar.BOOLEAN -> SQLDataType.BOOLEAN
NDCScalar.INT -> SQLDataType.INTEGER
NDCScalar.FLOAT -> SQLDataType.FLOAT
NDCScalar.STRING -> SQLDataType.CLOB
NDCScalar.DATE -> SQLDataType.DATE
NDCScalar.DATETIME -> SQLDataType.TIMESTAMP
NDCScalar.DATETIME_WITH_TIMEZONE -> SQLDataType.TIMESTAMP
NDCScalar.TIME -> SQLDataType.TIME
NDCScalar.TIME_WITH_TIMEZONE -> SQLDataType.TIME
}

private fun columnTypeTojOOQType(collection: String, field: ColumnField): org.jooq.DataType<out Any> {
val connectorConfig = ConnectorConfiguration.Loader.config

val table = connectorConfig.tables.find { it.tableName == collection }
?: error("Table $collection not found in connector configuration")

val column = table.columns.find { it.name == field.column }
?: error("Column ${field.column} not found in table $collection")

val scalarType = MySQLJDBCSchemaGenerator.mapScalarType(column.type, column.numeric_scale)
return ndcScalarTypeToSQLDataType(scalarType)
}

private fun getAggregatejOOQFunction(aggregate: Aggregate) = when (aggregate) {
is Aggregate.StarCount -> DSL.count()
is Aggregate.SingleColumn -> {
Expand Down
Loading

0 comments on commit 6556883

Please sign in to comment.