62 lines
1.6 KiB
Python
62 lines
1.6 KiB
Python
|
import json
|
||
|
from typing import TypeAlias, TypedDict, TypeVar
|
||
|
|
||
|
from django.db.models import Model, Q
|
||
|
from django.db.models.query import QuerySet
|
||
|
|
||
|
filter_types = {
|
||
|
"session_start": {
|
||
|
"equals": "timestamp_start__year__exact=",
|
||
|
"isnull": "timestamp_start__exact=None",
|
||
|
"greater_than": "timestamp_start__gt=",
|
||
|
"less_than": "timestamp_start__lt=",
|
||
|
},
|
||
|
}
|
||
|
|
||
|
|
||
|
class Filter(TypedDict):
|
||
|
name: str
|
||
|
operator: str
|
||
|
value: str
|
||
|
|
||
|
|
||
|
FilterList: TypeAlias = list[Filter]
|
||
|
|
||
|
|
||
|
def string_to_django_filter_dict(s: str, value: str = "") -> dict[str, str | int]:
|
||
|
if s[-1] == "=":
|
||
|
s += value
|
||
|
key, value = s.split("=")
|
||
|
return {key: value}
|
||
|
|
||
|
|
||
|
T = TypeVar("T", bound=Model)
|
||
|
|
||
|
|
||
|
def apply_json_filter[T](s: str, queryset: QuerySet[T]) -> QuerySet[T]:
|
||
|
filter_obj = urlsafe_json_decode(s)
|
||
|
name, operator, value = (filter_obj[k] for k in ["name", "operator", "value"])
|
||
|
if name in filter_types:
|
||
|
if operator in filter_types[name]:
|
||
|
filtered = queryset.filter(
|
||
|
Q(**string_to_django_filter_dict(filter_types[name][operator], value))
|
||
|
)
|
||
|
return filtered
|
||
|
return queryset
|
||
|
|
||
|
|
||
|
urlsafe_encode_table = str.maketrans({",": "^", ":": "-", " ": ""})
|
||
|
urlsafe_decode_table = str.maketrans({"^": ",", "-": ":"})
|
||
|
|
||
|
|
||
|
def urlsafe_json_encode[T](obj: T) -> str:
|
||
|
json_string = json.dumps(obj)
|
||
|
safe_string = json_string.translate(urlsafe_encode_table)
|
||
|
return safe_string
|
||
|
|
||
|
|
||
|
def urlsafe_json_decode[T](s: str) -> T:
|
||
|
unsafe_string = s.translate(urlsafe_decode_table)
|
||
|
obj = json.loads(unsafe_string)
|
||
|
return obj
|