The issue occurs while testing (nette/tester), as when actually running the code, the comparison is using CompareXXXFunction::evaluateInDb(), which behaves as expected (produces an SQL query with WHERE statement evaluated according to SQL logic), whereas the tests work with CompareXXXFunction::evaluateInPhp() and thus produces a different results from SQL queries for A < B expressions when NULLs are involved.
Example:
"Select random records deleted in year 2025 and earlier"
| random_records
| id | deleted_at
| 1 | 2026-02-02
| 2 | 2025-12-02
| 3 | NULL
I believe appropriate (SQL-aligned) Nextras code would be:
$collection = $randomRecordsRepository->findBy(['deletedAt<' => new DateTimeImmutable::createFromFormat('Y-m-d','2026-01-01')]);, which produces arguably correct and without a doubt aligned-with-SQL-logic result (record ID 2 selected) normally, but during testing, it additionally selects the record with ID 3 (as in PHP, null < $anyDate), making e.g. a RandomRecordsControllerTest::testGetRecordsDeletedInPreviousYears() essentially invalid.
I think reasonable solution would be to provide out of the box "SqlAlignedCompareXXXFunction" classes, which override evaluateInPhp() methods in a way which automatically return false when either of their arguments is null.
One step further would be to make those default when parsing 'property<' => $value conditions, but I realise that would potentially break a lot of things in lot of peoples' codebases.
I have considered:
- extending the CompareXXXFunction classes with my own methods, as suggested (implemented)
- adding additional conditions and constraints for either a comparison value (>=, >), or property value (<=, <) to not be nulls, where relevant (not implemented, I don't think this is the correct approach)
The issue occurs while testing (nette/tester), as when actually running the code, the comparison is using
CompareXXXFunction::evaluateInDb(), which behaves as expected (produces an SQL query with WHERE statement evaluated according to SQL logic), whereas the tests work withCompareXXXFunction::evaluateInPhp()and thus produces a different results from SQL queries forA < Bexpressions when NULLs are involved.Example:
"Select random records deleted in year 2025 and earlier"
| random_records
| id | deleted_at
| 1 | 2026-02-02
| 2 | 2025-12-02
| 3 | NULL
I believe appropriate (SQL-aligned) Nextras code would be:
$collection = $randomRecordsRepository->findBy(['deletedAt<' => new DateTimeImmutable::createFromFormat('Y-m-d','2026-01-01')]);, which produces arguably correct and without a doubt aligned-with-SQL-logic result (record ID 2 selected) normally, but during testing, it additionally selects the record with ID 3 (as in PHP,null < $anyDate), making e.g. aRandomRecordsControllerTest::testGetRecordsDeletedInPreviousYears()essentially invalid.I think reasonable solution would be to provide out of the box "SqlAlignedCompareXXXFunction" classes, which override
evaluateInPhp()methods in a way which automatically returnfalsewhen either of their arguments isnull.One step further would be to make those default when parsing
'property<' => $valueconditions, but I realise that would potentially break a lot of things in lot of peoples' codebases.I have considered: