Escape underscore char for "contains" query filter

since underscore has special meaning for LIKE clause
This commit is contained in:
Lance Edgar 2024-04-15 12:44:46 -05:00
parent 666c16b74e
commit d0d568b3a5

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 Lance Edgar
# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
@ -484,9 +484,13 @@ class AlchemyStringFilter(AlchemyGridFilter):
"""
if value is None or value == '':
return query
return query.filter(sa.and_(
*[self.column.ilike(self.encode_value('%{}%'.format(v)))
for v in value.split()]))
criteria = []
for val in value.split():
val = val.replace('_', r'\_')
val = self.encode_value(f'%{val}%')
criteria.append(self.column.ilike(val))
return query.filter(sa.and_(*criteria))
def filter_does_not_contain(self, query, value):
"""
@ -495,14 +499,17 @@ class AlchemyStringFilter(AlchemyGridFilter):
if value is None or value == '':
return query
criteria = []
for val in value.split():
val = val.replace('_', r'\_')
val = self.encode_value(f'%{val}%')
criteria.append(~self.column.ilike(val))
# When saying something is 'not like' something else, we must also
# include things which are nothing at all, in our result set.
return query.filter(sa.or_(
self.column == None,
sa.and_(
*[~self.column.ilike(self.encode_value('%{}%'.format(v)))
for v in value.split()]),
))
sa.and_(*criteria)))
def filter_contains_any_of(self, query, value):
"""
@ -531,9 +538,12 @@ class AlchemyStringFilter(AlchemyGridFilter):
conditions = []
for value in values:
conditions.append(sa.and_(
*[self.column.ilike(self.encode_value('%{}%'.format(v)))
for v in value.split()]))
criteria = []
for val in value.split():
val = val.replace('_', r'\_')
val = self.encode_value(f'%{val}%')
criteria.append(self.column.ilike(val))
conditions.append(sa.and_(*criteria))
return query.filter(sa.or_(*conditions))
@ -588,8 +598,13 @@ class AlchemyByteStringFilter(AlchemyStringFilter):
"""
if value is None or value == '':
return query
return query.filter(sa.and_(
*[self.column.ilike(b'%{}%'.format(v)) for v in value.split()]))
criteria = []
for val in value.split():
val = val.replace('_', r'\_')
val = b'%{}%'.format(val)
criteria.append(self.column.ilike(val))
return query.filters(sa.and_(*criteria))
def filter_does_not_contain(self, query, value):
"""
@ -598,13 +613,16 @@ class AlchemyByteStringFilter(AlchemyStringFilter):
if value is None or value == '':
return query
for val in value.split():
val = val.replace('_', '\_')
val = b'%{}%'.format(val)
criteria.append(~self.column.ilike(val))
# When saying something is 'not like' something else, we must also
# include things which are nothing at all, in our result set.
return query.filter(sa.or_(
self.column == None,
sa.and_(
*[~self.column.ilike(b'%{}%'.format(v)) for v in value.split()]),
))
sa.and_(*criteria)))
class AlchemyNumericFilter(AlchemyGridFilter):