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