from typing import Any, Union
from .operator import (
Operator,
compare,
invert_operator
)
[docs]class Comparator:
def __call__(self, item: dict) -> bool:
return self.evaluate(item)
[docs] def evaluate(self, other: dict) -> bool:
pass
[docs]class Condition(Comparator):
key: str
value: Any
operator: Operator
def __init__(self, key: str, value: Any, operator: Operator) -> None:
self.key = key
self.value = value
self.operator = operator
def __repr__(self) -> str:
s = [
f"key='{self.key}'",
f"operator={self.operator}",
f"value={repr(self.value)}",
]
return f"Condition({', '.join(s)})"
[docs] def copy(self) -> 'Condition':
return Condition(key=self.key, value=self.value, operator=self.operator)
def __invert__(self) -> 'Condition':
copy = self.copy()
copy.operator = invert_operator(self.operator)
return copy
def __and__(self, other: 'Condition') -> 'Conditions':
return Conditions(lvalue=self, rvalue=other, operator=Operator.AND)
def __rand__(self, other: 'Condition') -> 'Conditions':
return Conditions(lvalue=other, rvalue=self, operator=Operator.AND)
def __or__(self, other: 'Condition') -> 'Conditions':
return Conditions(lvalue=self, rvalue=other, operator=Operator.OR)
def __ror__(self, other: 'Condition') -> 'Conditions':
return Conditions(lvalue=other, rvalue=self, operator=Operator.OR)
[docs] def evaluate(self, item: dict) -> bool:
key = str(self.key)
if not key in item:
return None
return compare(item[key], self.value, self.operator)
[docs]class Conditions(Comparator):
_left: Union[Condition, 'Conditions']
_right: Union[Condition, 'Conditions']
_oper: Operator
def __init__(
self,
lvalue: Union[Condition, 'Conditions'],
rvalue: Union[Condition, 'Conditions'],
operator: Operator
) -> None:
self._left = lvalue
self._right = rvalue
self._oper = operator
[docs] def evaluate(self, other: dict) -> bool:
l, r, op = self._left, self._right, self._oper
return compare(l(other), r(other), op)
[docs] def copy(self) -> 'Conditions':
return Conditions(
lvalue=self._left,
rvalue=self._right,
operator=self._oper,
)
def __invert__(self) -> 'Conditions':
"""This is for NOT operation.
For example, when you call `~(a & b)` it means `not (a and b)`.
"""
inst = self.copy()
inst._oper = invert_operator(inst._oper)
return inst
[docs] def invert(self) -> 'Conditions':
"""According boolean algebra that satisfies De Morgan's laws
In case of `(a & b).invert()`, it returns having the meaning of
`(not a) or (not b)` that is equivalent to `(a and b)` in logical.
"""
return Conditions(
lvalue=~self._left,
rvalue=~self._right,
operator=invert_operator(self._oper),
)
def __and__(self, other: Union[Condition, 'Conditions']) -> 'Conditions':
return Conditions(lvalue=self, rvalue=other, operator=Operator.AND)
def __rand__(self, other: Union[Condition, 'Conditions']) -> 'Conditions':
return Conditions(lvalue=other, rvalue=self, operator=Operator.AND)
def __or__(self, other: Union[Condition, 'Conditions']) -> 'Conditions':
return Conditions(lvalue=self, rvalue=other, operator=Operator.OR)
def __ror__(self, other: Union[Condition, 'Conditions']) -> 'Conditions':
return Conditions(lvalue=other, rvalue=self, operator=Operator.OR)
def __repr__(self) -> str:
res = [self._left, self._oper, self._right]
return "({})".format(', '.join(list(map(repr, res))))
[docs]class Key(str):
def __lt__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.LESS_THAN)
def __le__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.LESS_EQUAL)
def __eq__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.EQUAL)
def __ne__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.NOT_EQUAL)
def __gt__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.GREATER_THAN)
def __ge__(self, value: Any) -> Condition:
return self.__generate_condition__(value, Operator.GREATER_EQUAL)
def __generate_condition__(self, value: Any, operator: Operator):
return Condition(key=self, value=value, operator=operator)