Failing test: Criteria matching on fields with custom column types#11897
Failing test: Criteria matching on fields with custom column types#11897mpdude wants to merge 1 commit intodoctrine:2.20.xfrom
Conversation
7b74b56 to
8cfa174
Compare
|
Not sure wheter #7102 is about the same issue |
| public function provideMatchingExpressions(): Generator | ||
| { | ||
| yield [Criteria::expr()->eq('field', 'match this')]; | ||
| yield [Criteria::expr()->in('field', ['match this'])]; |
There was a problem hiding this comment.
Not sure if it's related to custom types at all, but this test fails because the following code doesn't properly handle the IN operator:
orm/src/Persisters/Collection/ManyToManyPersister.php
Lines 257 to 263 in fd041fb
It should:
- Add parentheses to the SQL.
- Repeat the placeholder,
$params[]and$paramTypes[]for each element of the value.
| public function provideMatchingExpressions(): Generator | ||
| { | ||
| yield [Criteria::expr()->eq('field', 'match this')]; | ||
| yield [Criteria::expr()->in('field', ['match this'])]; |
There was a problem hiding this comment.
And this one fails because by the time when the following line is executed
$types contains [ArrayParameterType::STRING, 'rot13'], so at this point, the information about the custom type is lost.
Right now, the DBAL only supports a fixed set of array types (see ArrayParameterType).
For this to work, we can try introducing the ArrayType class and have it eventually replace the ArrayParameterType enum. This class should accepts the element type in its constructor. For example, new ArrayType(ParameterType::INTEGER) would represent what's currently represented as ArrayParameterType::INTEGER, and new ArrayType('rot13') would represent an array of custom type.
Not sure what effort it would take and how doable this is within the current type system.
There was a problem hiding this comment.
Yeah, something like this was my assumption... that we currently cannot combine the array type hint with custom types. If I get you right, your suggestion is to have the ArrayType as a wrapper (not necessarily decorator) around other types.
There was a problem hiding this comment.
What's the difference between a wrapper and a decorator? I believe I want to see "typed array" as one of the standard types. It will (I guess) wrap (or be parameterized with) its value type. This way, we can build queries with the array values of any standard or custom type.
There was a problem hiding this comment.
The distinction between wrapper and decorator was not sharp enough. What I meant was that ArrayType could be wrapped around any other base type, but (to my understanding) need not implement the same interface as the base types themselves.
A textbook decorator – to my understanding – implements at least the same interface as the objects it wraps, it's transparent from the interface point of view.
There was a problem hiding this comment.
Yeah, in this case I mean the decorator. It should wrap a type and be a type.
There was a problem hiding this comment.
Let’s discuss this over at doctrine/dbal#6883
|
There hasn't been any activity on this pull request in the past 90 days, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days. |
|
This pull request was closed due to inactivity. |
|
Retrying to fix this in #12190 |
…ype conversions This PR fixes the `Criteria` matching API for `IN` and `NIN` conditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly. Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level. Memory-based collections (`ArrayCollection`s or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results. But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison. One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a [limited list of types](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion) is supported. I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like `?, ?, ?`) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them. Previous stalled attempt to fix this was in doctrine#11897.
…ype conversions This PR fixes the `Criteria` matching API for `IN` and `NIN` conditions with values that are arrays, by making sure that type information for the matched field is passed to the DBAL level correctly. Passing the right parameter type to DBAL is important to make sure parameter conversions are applied before matching at the database level. Memory-based collections (`ArrayCollection`s or initialized collection fields) would perform matching on the objects in memory where no type conversion to the database representation is required, giving correct results. But uninitialized collections that have their conditions evaluated at the database level need to convert parameter values to the database representation before performing the comparison. One extra challenge is that the DBAL type system does currently not support array-valued parameters for custom types. Only a [limited list of types](https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion) is supported. I discussed this with @morozov at the Doctrine Hackathon and came to the conclusion that it would be best to work around this limitation at the ORM level. Thus, this fix recognizes array-valued parameters and creates multiple placeholders (like `?, ?, ?`) for them, flattening out the arrays in the parameter list and repeating the type information for each one of them. Previous stalled attempt to fix this was in doctrine#11897.
This adds failing tests that show that
Criteriamatching with at leastinandeqexpressions does not work for the case of SQL-based lookups (uninitializedPersistentCollections) when the targeted field uses custom types.In that case, we need to convert the value used within the expression to what it looks like in the database.
The challenging part is that I do not know how to combine the handling of custom types with the fact that the
inandnotInexpressions need to deal with query parameters that are arrays.https://www.doctrine-project.org/projects/doctrine-dbal/en/4.2/reference/data-retrieval-and-manipulation.html#list-of-parameters-conversion seems to be part of the puzzle, but I guess we somehow have to apply the type conversion (derive the value that would be found at the DBMS level) before constructing such a list?
Maybe @morozov or @derrabus could advise, you guys are much more knowledgeable with the DBAL type system.