truegrain.filters
Constructors for structured filters.
A filter is never a SQL fragment. That is what keeps an ungoverned predicate inexpressible, and it is the reason these are small functions rather than a string builder.
Using them instead of hand-written dictionaries catches a misspelled operator at the call site rather than as a refusal from the server.
1"""Constructors for structured filters. 2 3A filter is never a SQL fragment. That is what keeps an ungoverned predicate 4inexpressible, and it is the reason these are small functions rather than a 5string builder. 6 7Using them instead of hand-written dictionaries catches a misspelled operator at 8the call site rather than as a refusal from the server. 9""" 10 11from __future__ import annotations 12 13from typing import Any 14 15Filter = dict[str, Any] 16 17 18def _filter(dimension: str, op: str, *values: Any) -> Filter: 19 out: Filter = {"dimension": dimension, "op": op} 20 if values: 21 out["values"] = list(values) 22 return out 23 24 25def eq(dimension: str, value: Any) -> Filter: 26 """`dimension = value`.""" 27 return _filter(dimension, "eq", value) 28 29 30def ne(dimension: str, value: Any) -> Filter: 31 """`dimension <> value`.""" 32 return _filter(dimension, "ne", value) 33 34 35def in_(dimension: str, *values: Any) -> Filter: 36 """`dimension IN (...)`. Named with a trailing underscore; `in` is a keyword.""" 37 if not values: 38 raise ValueError("in_ needs at least one value") 39 return _filter(dimension, "in", *values) 40 41 42def not_in(dimension: str, *values: Any) -> Filter: 43 """`dimension NOT IN (...)`.""" 44 if not values: 45 raise ValueError("not_in needs at least one value") 46 return _filter(dimension, "not_in", *values) 47 48 49def gt(dimension: str, value: Any) -> Filter: 50 """`dimension > value`.""" 51 return _filter(dimension, "gt", value) 52 53 54def gte(dimension: str, value: Any) -> Filter: 55 """`dimension >= value`.""" 56 return _filter(dimension, "gte", value) 57 58 59def lt(dimension: str, value: Any) -> Filter: 60 """`dimension < value`.""" 61 return _filter(dimension, "lt", value) 62 63 64def lte(dimension: str, value: Any) -> Filter: 65 """`dimension <= value`.""" 66 return _filter(dimension, "lte", value) 67 68 69def between(dimension: str, low: Any, high: Any) -> Filter: 70 """`dimension BETWEEN low AND high`. 71 72 The engine refuses a reversed range rather than matching no rows, because an 73 empty result that looks like a real answer is worse than an error. 74 """ 75 return _filter(dimension, "between", low, high) 76 77 78def is_null(dimension: str) -> Filter: 79 """`dimension IS NULL`.""" 80 return _filter(dimension, "is_null") 81 82 83def is_not_null(dimension: str) -> Filter: 84 """`dimension IS NOT NULL`.""" 85 return _filter(dimension, "is_not_null")
26def eq(dimension: str, value: Any) -> Filter: 27 """`dimension = value`.""" 28 return _filter(dimension, "eq", value)
dimension = value.
31def ne(dimension: str, value: Any) -> Filter: 32 """`dimension <> value`.""" 33 return _filter(dimension, "ne", value)
dimension <> value.
36def in_(dimension: str, *values: Any) -> Filter: 37 """`dimension IN (...)`. Named with a trailing underscore; `in` is a keyword.""" 38 if not values: 39 raise ValueError("in_ needs at least one value") 40 return _filter(dimension, "in", *values)
dimension IN (...). Named with a trailing underscore; in is a keyword.
43def not_in(dimension: str, *values: Any) -> Filter: 44 """`dimension NOT IN (...)`.""" 45 if not values: 46 raise ValueError("not_in needs at least one value") 47 return _filter(dimension, "not_in", *values)
dimension NOT IN (...).
50def gt(dimension: str, value: Any) -> Filter: 51 """`dimension > value`.""" 52 return _filter(dimension, "gt", value)
dimension > value.
55def gte(dimension: str, value: Any) -> Filter: 56 """`dimension >= value`.""" 57 return _filter(dimension, "gte", value)
dimension >= value.
60def lt(dimension: str, value: Any) -> Filter: 61 """`dimension < value`.""" 62 return _filter(dimension, "lt", value)
dimension < value.
65def lte(dimension: str, value: Any) -> Filter: 66 """`dimension <= value`.""" 67 return _filter(dimension, "lte", value)
dimension <= value.
70def between(dimension: str, low: Any, high: Any) -> Filter: 71 """`dimension BETWEEN low AND high`. 72 73 The engine refuses a reversed range rather than matching no rows, because an 74 empty result that looks like a real answer is worse than an error. 75 """ 76 return _filter(dimension, "between", low, high)
dimension BETWEEN low AND high.
The engine refuses a reversed range rather than matching no rows, because an empty result that looks like a real answer is worse than an error.
79def is_null(dimension: str) -> Filter: 80 """`dimension IS NULL`.""" 81 return _filter(dimension, "is_null")
dimension IS NULL.
84def is_not_null(dimension: str) -> Filter: 85 """`dimension IS NOT NULL`.""" 86 return _filter(dimension, "is_not_null")
dimension IS NOT NULL.