from dataclasses import dataclass
TODO: 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 re
class 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 None
class IsNotNull(FilterExpression):
slug = "isnotnull"
def execute(self, value):
return value is not None
class Equals(FilterExpression):
slug = "eq"
def execute(self, value):
return value == self.value
class NotEquals(FilterExpression):
slug = "neq"
def execute(self, value):
return value != self.value
class GreaterThan(FilterExpression):
slug = "gt"
def execute(self, value):
return value > self.value
class GreaterThanOrEquals(FilterExpression):
slug = "gte"
def execute(self, value):
return value >= self.value
class LittleThan(FilterExpression):
slug = "lt"
def execute(self, value):
return value < self.value
class LittleThanOrEquals(FilterExpression):
slug = "lte"
def execute(self, value):
return value <= self.value
class 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 row
isnull 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)