54 lines
1.7 KiB
Python
54 lines
1.7 KiB
Python
# -*- 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'
|