Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate field type logic to an ADT #43

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -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] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand All @@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package net.wiringbits.spra.admin

import net.wiringbits.spra.admin.models.ColumnType
import net.wiringbits.spra.admin.repositories.models.TableColumn
import net.wiringbits.spra.admin.utils.QueryBuilder
import org.scalatest.matchers.must.Matchers.{be, must}
Expand All @@ -20,7 +21,10 @@ class QueryBuilderSpec extends AnyWordSpec {
|""".stripMargin
val tableName = "users"
val body =
Map(TableColumn("email", "citext") -> "[email protected]", TableColumn("name", "text") -> "wiringbits")
Map(
TableColumn("email", ColumnType.parseColumnType("citext")) -> "[email protected]",
TableColumn("name", ColumnType.parseColumnType("text")) -> "wiringbits"
)
val primaryKeyField = "user_id"

val response = QueryBuilder.create(tableName, body, primaryKeyField)
Expand Down Expand Up @@ -58,8 +62,8 @@ class QueryBuilderSpec extends AnyWordSpec {
|""".stripMargin
val tableName = "users"
val body = Map(
TableColumn("email", "citext") -> "[email protected]",
TableColumn("name", "text") -> "[email protected]"
TableColumn("email", ColumnType.parseColumnType("citext")) -> "[email protected]",
TableColumn("name", ColumnType.parseColumnType("text")) -> "[email protected]"
)
val primaryKeyField = "user_id"

Expand All @@ -76,9 +80,9 @@ class QueryBuilderSpec extends AnyWordSpec {
|""".stripMargin
val tableName = "users"
val body = Map(
TableColumn("email", "citext") -> "[email protected]",
TableColumn("name", "text") -> "[email protected]",
TableColumn("phone_number", "text") -> "null"
TableColumn("email", ColumnType.parseColumnType("citext")) -> "[email protected]",
TableColumn("name", ColumnType.parseColumnType("text")) -> "[email protected]",
TableColumn("phone_number", ColumnType.parseColumnType("text")) -> "null"
)
val primaryKeyField = "user_id"

Expand Down
Loading