@@ -10,8 +10,7 @@ import java.sql.{Connection, Date, PreparedStatement, ResultSet}
10
10
import java .time .LocalDate
11
11
import java .util .UUID
12
12
import scala .collection .mutable .ListBuffer
13
- import scala .util .Try
14
-
13
+ import scala .util .{Failure , Success , Try }
15
14
object DatabaseTablesDAO {
16
15
17
16
def all (schema : String = " public" )(implicit conn : Connection ): List [DatabaseTable ] = {
@@ -73,6 +72,37 @@ object DatabaseTablesDAO {
73
72
""" .as(foreignKeyParser.* )
74
73
}
75
74
75
+ private def columnTypeIsDouble (columnType : String ): Boolean = {
76
+ // 'contains' is used because PostgreSQL types may include additional details like precision or scale
77
+ // https://www.postgresql.org/docs/8.1/datatype.html
78
+ List (" float" , " decimal" ).exists(columnType.contains)
79
+ }
80
+
81
+ private def columnTypeIsInt (columnType : String ): Boolean = {
82
+ List (" int" , " serial" ).exists(columnType.contains)
83
+ }
84
+
85
+ private def isUUID (value : String , columnType : String ): Boolean = {
86
+ Try (UUID .fromString(value)) match {
87
+ case Success (_) => columnType == " uuid"
88
+ case Failure (_) => false
89
+ }
90
+ }
91
+
92
+ private def isInt (value : String , columnType : String ): Boolean = {
93
+ value.toIntOption.isDefined && columnTypeIsInt(columnType)
94
+ }
95
+
96
+ private def isDecimal (value : String , columnType : String ): Boolean = {
97
+ value.toDoubleOption.isDefined && columnTypeIsDouble(columnType)
98
+ }
99
+
100
+ private def isNumberOrUUID (value : String , columnType : String ): Boolean = {
101
+ isInt(value, columnType) ||
102
+ isDecimal(value, columnType) ||
103
+ isUUID(value, columnType)
104
+ }
105
+
76
106
def getTableData (
77
107
settings : TableSettings ,
78
108
columns : List [TableColumn ],
@@ -88,12 +118,16 @@ object DatabaseTablesDAO {
88
118
89
119
val conditionsSql = queryParameters.filters
90
120
.map { case FilterParameter (filterField, filterValue) =>
121
+ val columnType = columns.find(_.name == filterField) match {
122
+ case Some (column) => column.`type`
123
+ case None => throw Exception (s " Column with name ' $filterField' not found. " )
124
+ }
91
125
filterValue match {
92
- case dateRegex(_, _, _) =>
126
+ case dateRegex(_, _, _) if columnType == " date " =>
93
127
s " DATE( $filterField) = ? "
94
128
95
129
case _ =>
96
- if (filterValue.toIntOption.isDefined || filterValue.toDoubleOption.isDefined )
130
+ if (isNumberOrUUID( filterValue, columnType) )
97
131
s " $filterField = ? "
98
132
else
99
133
s " $filterField LIKE ? "
@@ -111,20 +145,25 @@ object DatabaseTablesDAO {
111
145
val preparedStatement = conn.prepareStatement(sql)
112
146
113
147
queryParameters.filters.zipWithIndex
114
- .foreach { case (FilterParameter (_ , filterValue), index) =>
148
+ .foreach { case (FilterParameter (filterField , filterValue), index) =>
115
149
// We have to increment index by 1 because SQL parameterIndex starts in 1
116
150
val sqlIndex = index + 1
117
-
151
+ val columnType = columns.find(_.name == filterField) match {
152
+ case Some (column) => column.`type`
153
+ case None => throw Exception (s " Column with name ' $filterField' not found. " )
154
+ }
118
155
filterValue match {
119
156
case dateRegex(year, month, day) =>
120
157
val parsedDate = LocalDate .of(year.toInt, month.toInt, day.toInt)
121
158
preparedStatement.setDate(sqlIndex, Date .valueOf(parsedDate))
122
159
123
160
case _ =>
124
- if (filterValue.toIntOption.isDefined )
161
+ if (isInt( filterValue, columnType) )
125
162
preparedStatement.setInt(sqlIndex, filterValue.toInt)
126
- else if (filterValue.toDoubleOption.isDefined )
163
+ else if (isDecimal( filterValue, columnType) )
127
164
preparedStatement.setDouble(sqlIndex, filterValue.toDouble)
165
+ else if (isUUID(filterValue, columnType))
166
+ preparedStatement.setObject(sqlIndex, UUID .fromString(filterValue))
128
167
else
129
168
preparedStatement.setString(sqlIndex, s " % $filterValue% " )
130
169
}
0 commit comments