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

Fixed broken search in PostgreSQL #6262

Closed
wants to merge 3 commits into from

Conversation

alshenetsky
Copy link
Contributor

See #6242
A recent change (which I shamefully commited) broke search for the PostgreSQL platform. This PR should fix the issue.

@alshenetsky alshenetsky mentioned this pull request Apr 17, 2024
@janklan
Copy link

janklan commented Apr 17, 2024

No need to lynch yourself :)

Do you think this is a real fix, though? If I understand things correctly, the initial problem was an incorrect query with an empty WHERE statement, because there are no any $queryTermConditions.

Adding a bogus condition just to make the $queryTermConditions to contain something doesn't seem right. If the WHERE can't be removed from the query, can't we instead add 1 = 1 when $queryTermConditions is empty?

@alshenetsky
Copy link
Contributor Author

alshenetsky commented Apr 17, 2024

Adding a bogus condition just to make the $queryTermConditions to contain something doesn't seem right. If the WHERE can't be removed from the query, can't we instead add 1 = 1 when $queryTermConditions is empty?

That would be counter-intuitive. Imagine: you type text into the search box and see ALL entries as if they all contained that text (in fact none of them).

You could add an infeasible condition, like WHERE 1 = 2 😄 But that wouldn't be any better: some developer would go crazy once he uses the profiler and sees the queries.

@janklan
Copy link

janklan commented Apr 17, 2024

Right, so the problem you have is when someone searches for a string in a controller that only deals with numbers. Then the array of conditions is empty, and the result is intended to be always empty as well as there can't be any matches.

Wouldn't in this case make sense to just return an empty iterator instead of running a SQL query that we know will yield no results?


Looking at the code, it's probably not as easy to do that. With that in mind, I think this would be a viable solution developers would not freak about.

Right under the massive if/else statement:

if ($queryTermConditions->count() > 0) {
    if (SearchMode::ALL_TERMS === $searchDto->getSearchMode()) {
        $queryBuilder->andWhere($queryTermConditions);
    } else {
        $queryBuilder->orWhere($queryTermConditions);
    }
} else {
    /**
     * When the above if/else block doesn't add any conditions to $queryTermsConditions, we know the search
     * will never return any results. Passing an empty Expr object to Doctrine's QueryBuilder produces an invalid
     * SQL query, causing the search function to fail.
     *
     * Adding the `1 = 'look-for-this-string-in-the-source-code-for-more-info'` condition creates a valid SQL
     * query that returns no results.
     *
     * @see https://github.com/EasyCorp/EasyAdminBundle/pull/6262
     */
    $queryBuilder->andWhere("1 = 'look-for-this-string-in-the-source-code-for-more-info'");
}

At least you can easily find the source of the query by searching for "look-for-this-string-in-the-source-code-for-more-info" in the code :D

@alshenetsky
Copy link
Contributor Author

alshenetsky commented Apr 17, 2024

In general, you're right. But I'm pretty sure it's impossible without extensive refactoring, which will be backwards-incompatible. This QueryBuilder already exists in the user-space, and all we can/should do is refine its conditions.


Just saw the second part of your comment. I hope you're not serious :D

@alshenetsky
Copy link
Contributor Author

The aesthetics of this if condition is a separate issue. However, I believe that queries should be generated in a predictable way.

@janklan
Copy link

janklan commented Apr 17, 2024

I was dead serious.

Another thought: } elseif ($propertyConfig['is_text'] || ($propertyConfig['is_integer'] && !$isPostgreSql)) {- doesn't this keep the buggy behaviour in place for PostgreSQL?

@Seb33300
Copy link
Contributor

Seb33300 commented Apr 17, 2024

I would suggest similar solution as suggested by @janklan but without imbricated conditions:

$queryTermConditions = new Orx();
foreach ($searchablePropertiesConfig as $propertyConfig) {
    // All conditions...
}

/** Add this */
// No searchable property => return empty result
if ($queryTermConditions->count() === 0) {
    $queryTermConditions->add('1 = 2');
}
/** End add this */

if (SearchMode::ALL_TERMS === $searchDto->getSearchMode()) {
	$queryBuilder->andWhere($queryTermConditions);
} else {
	$queryBuilder->orWhere($queryTermConditions);
}

@alshenetsky
Copy link
Contributor Author

So be it. Please review :)

@alshenetsky
Copy link
Contributor Author

Oh, no... I think someone already fixed this, but no one saw his PR
https://github.com/EasyCorp/EasyAdminBundle/pull/6227/files

I should close this.

@Seb33300
Copy link
Contributor

Right, but you code still need to be reverted

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants