Escape underscore char for "contains" query filter
since underscore has special meaning for LIKE clause
This commit is contained in:
parent
666c16b74e
commit
d0d568b3a5
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -484,9 +484,13 @@ class AlchemyStringFilter(AlchemyGridFilter):
|
||||||
"""
|
"""
|
||||||
if value is None or value == '':
|
if value is None or value == '':
|
||||||
return query
|
return query
|
||||||
return query.filter(sa.and_(
|
|
||||||
*[self.column.ilike(self.encode_value('%{}%'.format(v)))
|
criteria = []
|
||||||
for v in value.split()]))
|
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):
|
def filter_does_not_contain(self, query, value):
|
||||||
"""
|
"""
|
||||||
|
@ -495,14 +499,17 @@ class AlchemyStringFilter(AlchemyGridFilter):
|
||||||
if value is None or value == '':
|
if value is None or value == '':
|
||||||
return query
|
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
|
# When saying something is 'not like' something else, we must also
|
||||||
# include things which are nothing at all, in our result set.
|
# include things which are nothing at all, in our result set.
|
||||||
return query.filter(sa.or_(
|
return query.filter(sa.or_(
|
||||||
self.column == None,
|
self.column == None,
|
||||||
sa.and_(
|
sa.and_(*criteria)))
|
||||||
*[~self.column.ilike(self.encode_value('%{}%'.format(v)))
|
|
||||||
for v in value.split()]),
|
|
||||||
))
|
|
||||||
|
|
||||||
def filter_contains_any_of(self, query, value):
|
def filter_contains_any_of(self, query, value):
|
||||||
"""
|
"""
|
||||||
|
@ -531,9 +538,12 @@ class AlchemyStringFilter(AlchemyGridFilter):
|
||||||
|
|
||||||
conditions = []
|
conditions = []
|
||||||
for value in values:
|
for value in values:
|
||||||
conditions.append(sa.and_(
|
criteria = []
|
||||||
*[self.column.ilike(self.encode_value('%{}%'.format(v)))
|
for val in value.split():
|
||||||
for v 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))
|
return query.filter(sa.or_(*conditions))
|
||||||
|
|
||||||
|
@ -588,8 +598,13 @@ class AlchemyByteStringFilter(AlchemyStringFilter):
|
||||||
"""
|
"""
|
||||||
if value is None or value == '':
|
if value is None or value == '':
|
||||||
return query
|
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):
|
def filter_does_not_contain(self, query, value):
|
||||||
"""
|
"""
|
||||||
|
@ -598,13 +613,16 @@ class AlchemyByteStringFilter(AlchemyStringFilter):
|
||||||
if value is None or value == '':
|
if value is None or value == '':
|
||||||
return query
|
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
|
# When saying something is 'not like' something else, we must also
|
||||||
# include things which are nothing at all, in our result set.
|
# include things which are nothing at all, in our result set.
|
||||||
return query.filter(sa.or_(
|
return query.filter(sa.or_(
|
||||||
self.column == None,
|
self.column == None,
|
||||||
sa.and_(
|
sa.and_(*criteria)))
|
||||||
*[~self.column.ilike(b'%{}%'.format(v)) for v in value.split()]),
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
class AlchemyNumericFilter(AlchemyGridFilter):
|
class AlchemyNumericFilter(AlchemyGridFilter):
|
||||||
|
|
Loading…
Reference in a new issue