from dataclasses import dataclassTODO: construct QuerySet from data (filters) + iterable, like: QuerySet( iterable, filters=[ ( “AND”, (“age”, “lte”, 30), (“name”, “startswith”, “A”), ), ], ) TODO: create QuerySet class from data (metaclass to create filter methods from JSON) TODO: QuerySet(iterable).filter(RowClass.field_name >= 10) <=> QuerySet(iterable).filter(field_name__gte=10)
import reclass FilterExpression:
slug = None def __init__(self, value):TODO: should save field name?
self.value = value
self.validate() def validate(self):
pass def __str__(self):
return "<FilterExpression {} {}>".format(self.slug, repr(self.value)) def __repr__(self):
return "<FilterExpression {} {}>".format(self.slug, repr(self.value))class IsNull(FilterExpression):
slug = "isnull" def execute(self, value):
return value is Noneclass IsNotNull(FilterExpression):
slug = "isnotnull" def execute(self, value):
return value is not Noneclass Equals(FilterExpression):
slug = "eq" def execute(self, value):
return value == self.valueclass NotEquals(FilterExpression):
slug = "neq" def execute(self, value):
return value != self.valueclass GreaterThan(FilterExpression):
slug = "gt" def execute(self, value):
return value > self.valueclass GreaterThanOrEquals(FilterExpression):
slug = "gte" def execute(self, value):
return value >= self.valueclass LittleThan(FilterExpression):
slug = "lt" def execute(self, value):
return value < self.valueclass LittleThanOrEquals(FilterExpression):
slug = "lte" def execute(self, value):
return value <= self.valueclass StartsWith(FilterExpression):
slug = "startswith" def validate(self):
if not isinstance(self.value, str):
raise ValueError("Value is not str") def execute(self, value):
if not isinstance(value, str):
raise ValueError("Value is not str")
return value.startswith(self.value)class EndsWith(FilterExpression):
slug = "endswith" def validate(self):
if not isinstance(self.value, str):
raise ValueError("Value is not str") def execute(self, value):
if not isinstance(value, str):
raise ValueError("Value is not str")
return value.endswith(self.value)class Regexp(FilterExpression):
slug = "regexp" def validate(self):
self.regexp = re.compile(self.value) def execute(self, value):
return bool(self.value.match(value))class QuerySet: def __init__(self, iterable, filters=None):
self.__iterable = iterable
self.__filters = filters or {}TODO: filters may be a list of expressions
def filter(self, **filters):
new_filters = self.__filters.copy()
new_filters.update(filters)
return QuerySet(iterable=self.iterable, filters=new_filters) def exclude(self, **filters):TODO: implement
pass def matches(self, row):
for filter_name, filter_value in self.__filters.items():
print(f"test if {row} matches {filter_name}, {filter_value}"TODO: implement
return True def __iter__(self):
return self def __getitem__(self):
for row in self.iterable:
if self.matches(row):
yield rowisnull startswith endswith gt gte lt lte in Q
@dataclass
class Expression:
field_name = None
operation = None
value = None
class Not(Expression):
@classmethod
def execute(self, op1):
return not bool(op1)
class And(Expression):
@classmethod
def execute(self, op1, op2):
return bool(op1) and bool(op2)
class Or(Expression):
@classmethod
def execute(self, op1, op2):
return bool(op1) or bool(op2)