From 6864ff827bc11c19696692a2a98f9d1cdc9d4448 Mon Sep 17 00:00:00 2001 From: Antonio171003 Date: Tue, 10 Sep 2024 20:26:16 -0700 Subject: [PATCH] Refactor the columnType field in TableColumn to use an ADT (ColumnType). --- .../spra/admin/models/ColumnType.scala | 37 +++++++++++++++++++ .../repositories/daos/DatabaseTablesDAO.scala | 3 +- .../admin/repositories/daos/package.scala | 13 +++++-- .../repositories/models/TableColumn.scala | 4 +- .../spra/admin/services/AdminService.scala | 2 +- .../spra/admin/utils/QueryBuilder.scala | 4 +- 6 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 spra-play-server/src/main/scala/net/wiringbits/spra/admin/models/ColumnType.scala diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/models/ColumnType.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/models/ColumnType.scala new file mode 100644 index 0000000..5ef9e7e --- /dev/null +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/models/ColumnType.scala @@ -0,0 +1,37 @@ +package net.wiringbits.spra.admin.models + +sealed trait ColumnType { + val value: String +} + +object ColumnType { + case class Date(value: String) extends ColumnType + case class Text(value: String) extends ColumnType + case class Bytea(value: String) extends ColumnType + case class Int(value: String) extends ColumnType + case class Decimal(value: String) extends ColumnType + case class UUID(value: String) extends ColumnType + + def parseColumnType(columnType: String): ColumnType = { + // 'contains' is used because PostgreSQL types may include additional details like precision or scale + // https://www.postgresql.org/docs/8.1/datatype.html + val isInt = List("int", "serial").exists(columnType.contains) + val isDecimal = List("float", "decimal").exists(columnType.contains) + val isBytea = columnType == "bytea" + val isUUID = columnType == "uuid" + val isDate = List("date", "time").exists(columnType.contains) + + if (isDate) + Date(columnType) + else if (isDecimal) + Decimal(columnType) + else if (isBytea) + Bytea(columnType) + else if (isInt) + Int(columnType) + else if (isUUID) + UUID(columnType) + else + Text(columnType) + } +} diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala index 2aed493..d539fbd 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/DatabaseTablesDAO.scala @@ -2,6 +2,7 @@ package net.wiringbits.spra.admin.repositories.daos import anorm.{SqlParser, SqlStringInterpolation} import net.wiringbits.spra.admin.config.{CustomDataType, PrimaryKeyDataType, TableSettings} +import net.wiringbits.spra.admin.models.ColumnType import net.wiringbits.spra.admin.repositories.models.* import net.wiringbits.spra.admin.utils.models.{FilterParameter, QueryParameters} import net.wiringbits.spra.admin.utils.{QueryBuilder, StringRegex} @@ -38,7 +39,7 @@ object DatabaseTablesDAO { val fields = for { columnNumber <- 1 to numberOfColumns columnName = metadata.getColumnName(columnNumber) - columnType = metadata.getColumnTypeName(columnNumber) + columnType = ColumnType.parseColumnType(metadata.getColumnTypeName(columnNumber)) } yield TableColumn(columnName, columnType) fields.toList } finally { diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala index 691e958..6a57807 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/daos/package.scala @@ -1,6 +1,8 @@ package net.wiringbits.spra.admin.repositories import anorm.* +import anorm.SqlParser.get +import net.wiringbits.spra.admin.models.ColumnType import net.wiringbits.spra.admin.repositories.models.{DatabaseTable, ForeignKey, TableColumn} package object daos { @@ -28,10 +30,13 @@ package object daos { } val tableColumnParser: RowParser[TableColumn] = { - Macro.parser[TableColumn]( - "column_name", - "data_type" - ) + get[String]("column_name") ~ + get[String]("data_type") map { case name ~ columnTypeStr => + TableColumn( + name = name, + `type` = ColumnType.parseColumnType(columnTypeStr) + ) + } } val foreignKeyParser: RowParser[ForeignKey] = { diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/models/TableColumn.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/models/TableColumn.scala index 437a0c4..a813694 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/models/TableColumn.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/repositories/models/TableColumn.scala @@ -1,6 +1,8 @@ package net.wiringbits.spra.admin.repositories.models +import net.wiringbits.spra.admin.models.ColumnType + case class TableColumn( name: String, - `type`: String + `type`: ColumnType ) diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala index c7b3f21..c489a3a 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/services/AdminService.scala @@ -66,7 +66,7 @@ class AdminService @Inject() ( None AdminGetTables.Response.TableColumn( name = fieldName, - `type` = column.`type`, + `type` = column.`type`.value, editable = isEditable, reference = reference, filterable = isFilterable, diff --git a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/utils/QueryBuilder.scala b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/utils/QueryBuilder.scala index 8193eba..90756a8 100644 --- a/spra-play-server/src/main/scala/net/wiringbits/spra/admin/utils/QueryBuilder.scala +++ b/spra-play-server/src/main/scala/net/wiringbits/spra/admin/utils/QueryBuilder.scala @@ -20,7 +20,7 @@ object QueryBuilder { } for ((tableColumn, _) <- fieldsAndValues) { sqlFields.append(s", ${tableColumn.name}") - sqlValues.append(s", ?::${tableColumn.`type`}") + sqlValues.append(s", ?::${tableColumn.`type`.value}") } s""" @@ -36,7 +36,7 @@ object QueryBuilder { def update(tableName: String, body: Map[TableColumn, String], primaryKeyField: String): String = { val updateStatement = new mutable.StringBuilder("SET") for ((tableField, value) <- body) { - val resultStatement = if (value == "null") "NULL" else s"?::${tableField.`type`}" + val resultStatement = if (value == "null") "NULL" else s"?::${tableField.`type`.value}" val statement = s" ${tableField.name} = $resultStatement," updateStatement.append(statement) }