# -*- coding: utf-8 -*- from __future__ import annotations import typing from django.db.models.fields import Field from django.db.models.lookups import PatternLookup class BaseLikeLookup(PatternLookup): """ This class provides base for custom LIKE/ILIKE lookups for PostgreSQL. Unlike the builtin `contains` and `icontains`, these lookups do not do any DB-side processing of parameters. This opens up the ability to use index ops provided by `pg_trgm` to better index text columns for pattern searches. These lookups currently support only PostgreSQL 15+. """ # This is the pattern operator used to generate SQL for the lookup # when the right hand side isn't a raw string. Subclasses must specify this # or the whole thing will blow up ;). PATTERN_OP: str | None = None # This is the rhs operator used to generate SQL for the lookup when the # right hand side is a raw string. Subclasses must specify this or the # whole thing will blow up ;). RHS_OP: str | None = None def get_rhs_op(self, connection: typing.Any, rhs: typing.Any) -> typing.Any: if hasattr(self.rhs, 'as_sql') or self.bilateral_transforms: pattern = typing.cast(str, self.PATTERN_OP).format( connection.pattern_esc, ) return pattern.format(rhs) else: return typing.cast(str, self.RHS_OP) @Field.register_lookup class Like(BaseLikeLookup): PATTERN_OP = "LIKE '%%' || {} || '%%'" RHS_OP = 'LIKE %s' lookup_name = 'like' @Field.register_lookup class ILike(BaseLikeLookup): PATTERN_OP = "ILIKE '%%' || {} || '%%'" RHS_OP = 'ILIKE %s' lookup_name = 'ilike'