# retoor from __future__ import annotations from datetime import date, datetime from pathlib import Path from typing import Any WRITE_PREFIXES = ( "set_", "add_", "delete_", "create_", "update_", "upsert_", "record_", "migrate_", "backfill_", "mark_", "invalidate_", "ensure_", "restore", "purge", "revoke_", "recompute_", "soft_delete", "bump_", "init_", "clear_settings", ) WRITE_EXACT = frozenset( { "soft_delete_in", "restore_event", "purge_event", "delete_engagement", "soft_delete_engagement", "delete_fork_relations", "soft_delete_fork_relations", "delete_attachments", "delete_attachment_record", "_delete_attachment_file", "_index", "_drop_index", "_uid_index", "_ensure_cache_state", "_refresh_query_planner_stats", "_backfill_gamification", } ) REMOTE_TABLE_MARKER = "__remote_table__" def is_write(name: str) -> bool: if name in WRITE_EXACT: return True return any(name.startswith(prefix) for prefix in WRITE_PREFIXES) SQL_WRITE_KEYWORDS = frozenset( {"INSERT", "UPDATE", "DELETE", "REPLACE", "CREATE", "ALTER", "DROP"} ) def is_write_sql(sql: str) -> bool: first_word = sql.strip().split(None, 1)[0].upper() if sql.strip() else "" return first_word in SQL_WRITE_KEYWORDS def encode_value(value: Any) -> Any: if value is None or isinstance(value, (bool, int, float, str)): return value if type(value).__name__ == "RemoteTable": return {REMOTE_TABLE_MARKER: value._name} if isinstance(value, (datetime, date)): return value.isoformat() if isinstance(value, Path): return str(value) if isinstance(value, frozenset): return [encode_value(item) for item in value] if isinstance(value, set): return [encode_value(item) for item in value] if isinstance(value, tuple): return [encode_value(item) for item in value] if isinstance(value, list): return [encode_value(item) for item in value] if isinstance(value, dict): return {str(key): encode_value(item) for key, item in value.items()} if hasattr(value, "items") and callable(value.items): try: return {str(key): encode_value(item) for key, item in value.items()} except TypeError: pass return str(value) def encode_args(args: tuple | list, kwargs: dict) -> tuple[list, dict]: return [encode_value(item) for item in args], { str(key): encode_value(value) for key, value in kwargs.items() } def decode_value(value: Any) -> Any: if isinstance(value, list): return [decode_value(item) for item in value] if isinstance(value, dict): return {key: decode_value(item) for key, item in value.items()} return value def decode_arg(value: Any) -> Any: if isinstance(value, list): return [decode_arg(item) for item in value] if isinstance(value, dict): if set(value) == {REMOTE_TABLE_MARKER}: from devplacepy.db_client import get_table return get_table(value[REMOTE_TABLE_MARKER]) return {key: decode_arg(item) for key, item in value.items()} return value def encode_result(value: Any) -> Any: return encode_value(value)