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

Support different types of search filters (SQLAlchemy) #558

Open
gdoctor opened this issue Feb 27, 2024 · 4 comments
Open

Support different types of search filters (SQLAlchemy) #558

gdoctor opened this issue Feb 27, 2024 · 4 comments

Comments

@gdoctor
Copy link

gdoctor commented Feb 27, 2024

Filter Version: SQLAlchemy

Currently, the search query parameter translates to a SQL query with this form:

SELECT * FROM example WHERE example.name ILIKE '%test_string%' OR example.description ILIKE '%test_string%';

For my use case, I prefer to create trigram indexes and search on that index with this form:

SELECT * FROM example WHERE (example.name || ' ' || coalesce(example.description, '')) ILIKE '%test_string%';

Additionally, I will want to search using tsvectors/tsqueries in the near future. I propose we create a search Enum, specific to the sqlalchemy filter code, that will have the values ILIKE_OR (current version), TRIGRAM, TSVECTOR (maybe a few others). It's actually quite easy to implement and I am running it in my project. I would be happy to put together a PR if there is interest in search customization like this.

I would also take care of coalescing nullable columns to ensure our search results are accurate.

Adding just the TRIGRAM search looks roughly like this but my PR would be much cleaner:

def get_ilike_field(model: Any, field: Any) -> Any:
    column = getattr(model, field)
    if column.nullable:
        return func.coalesce(column, "")
    return column


         def filter(self, query: Union[Query, Select]):
               
                ....
               
                if field_name == self.Constants.search_field_name and hasattr(self.Constants, "search_model_fields"):

                    if hasattr(self.Constants, "search_type") and self.Constants.search_type == "trigram":
                        search_value = None
                        for i, field in enumerate(self.Constants.search_model_fields):
                            ilike_value = get_ilike_field(self.Constants.model, field)
                            search_value = ilike_value if search_value is None else search_value + ilike_value
                            if i < len(self.Constants.search_model_fields) - 1:
                                search_value += " "

                        query = query.filter(ilike_op(search_value, f"%{value.lower()}%"))
                    else:  # current default search
                        search_filters = [
                            getattr(self.Constants.model, field).ilike(f"%{value}%")
                            for field in self.Constants.search_model_fields
                        ]
                        query = query.filter(or_(*search_filters))
                else:
                    model_field = getattr(self.Constants.model, field_name)
                    query = query.filter(getattr(model_field, operator)(value))

        return query
@agusmdev
Copy link

@gdoctor I'd love to have this included in fastapi-filter I'm trying to search by Vector with Euclidean distance and I wasn't able to make it work like the others

Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label May 18, 2024
@arthurio arthurio removed the Stale label May 18, 2024
Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Sep 26, 2024
@arthurio arthurio removed the Stale label Sep 26, 2024
Copy link

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot added the Stale label Nov 26, 2024
@arthurio arthurio removed the Stale label Nov 26, 2024
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

No branches or pull requests

3 participants