diff --git a/tailbone/newgrids/filters.py b/tailbone/newgrids/filters.py index be51c63e..d6cf51cd 100644 --- a/tailbone/newgrids/filters.py +++ b/tailbone/newgrids/filters.py @@ -179,12 +179,15 @@ class GridFilter(object): current verb/value by default. """ verb = verb or self.verb - value = value if value is not UNSPECIFIED else self.value + value = self.get_value(value) filtr = getattr(self, 'filter_{0}'.format(verb), None) if not filtr: raise ValueError("Unknown filter verb: {0}".format(repr(verb))) return filtr(data, value) + def get_value(self, value=UNSPECIFIED): + return value if value is not UNSPECIFIED else self.value + def filter_is_any(self, data, value): """ Special no-op filter which does no actual filtering. Useful in some @@ -300,7 +303,7 @@ class AlchemyStringFilter(AlchemyGridFilter): if value is None or value == '': return query return query.filter(sa.and_( - *[self.column.ilike('%{0}%'.format(v)) for v in value.split()])) + *[self.column.ilike('%{}%'.format(v)) for v in value.split()])) def filter_does_not_contain(self, query, value): """ @@ -318,6 +321,45 @@ class AlchemyStringFilter(AlchemyGridFilter): )) +class AlchemyByteStringFilter(AlchemyStringFilter): + """ + String filter for SQLAlchemy, which encodes value as bytestring before + passing it along to the query. Useful when querying certain databases + (esp. via FreeTDS) which like to throw the occasional segfault... + """ + value_encoding = 'utf-8' + + def get_value(self, value=UNSPECIFIED): + value = super(AlchemyByteStringFilter, self).get_value(value) + if isinstance(value, unicode): + value = value.encode(self.value_encoding) + return value + + def filter_contains(self, query, value): + """ + Filter data with a full 'ILIKE' query. + """ + if value is None or value == '': + return query + return query.filter(sa.and_( + *[self.column.ilike(b'%{}%'.format(v)) for v in value.split()])) + + def filter_does_not_contain(self, query, value): + """ + Filter data with a full 'NOT ILIKE' query. + """ + if value is None or value == '': + return query + + # 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()]), + )) + + class AlchemyNumericFilter(AlchemyGridFilter): """ Numeric filter for SQLAlchemy.