fix: EXPOSED-474 Unexpected value of type when using a ColumnTransfor… #2191
+89
−7
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
An interesting issue with the new column conversion feature was found.
Transformed value actually cannot be read from the insert statement directly and via DAO entity.
The reason is that statements and entities work via
ResultRow
that has mappting of expressions to the values. AndResultRow
works in the way that it accepts as values both user values and db values. It works because internallyResultRow
callsColumnType::valueFromDB()
for all the values, andColumnType
s should convert the values into correct kotlin types.And the column types are implemented in the way that if they receive already valid value, they just return it. For example
IntegerColumnType
in this context looks like this:So it was not a problem to recall
valueFromDB
several times for the value.But with introduced transforms this logic breaks, because every try to call
valueFromDB
method leads to the transformation process.So the flow was looking like:
statement = table.insert { it[field] = CustomData() }
// insert value, soResultRow
will containCustomData
objectstatement[field]
fails, because it tries to callexpression.columnType.valueFromDB(raw)
internally, whereraw
isCustomData
object. It leads to class cast exception.Solution
At the current I found a way to unwrap (recursively for chained transforms) the values before setting them to
ResultRow
. It will allow keeping only original column type values insideResultRow
as before.Alternatively, I tried two other options.
Store in the
ResultRow
only reallyraw
values (the values produced byColumnType::valueToDB
method). But it causes other problems, the main reason, as I understand, is that the values which we put to the database and the values we get back from the database are not always of the same data types, and not all column types are ready for it. And potentially it adds lots of unnecessary conversions.Store in the
ResultRow
only wrapped values, so no conversion is necessary. It can be an interesting solution, but it would require much more refactoring (as I can see now, but not sure), because many places of creatingResultRow
should be extended. The positive side here is that the user will get theResultRow
object with final data, and no extra conversion magic would be applied on reading the data. I have a feeling that I will face many obstacles in this way, so I didn't invest more time here, but if you see that it's a good way in general, I could try to do a separate refactoring.Type of Change
Affected databases:
Related Issues
EXPOSED-474 Unexpected value of type when using a ColumnTransformer in a DAO object