
from typing import Any, Dict
from psycopg.types.json import Jsonb

from nc_db.metadata.column_mappers.column_mapper import ColumnMapper, DbUpdate


class BodyMapper(ColumnMapper):
    """
    The body column requires special logic as it serializes and deserializes all class atributes that are not stored as a column.
    This class encapsulates that logic
    NOTE: This mapper MUST RUN LAST as the other mappers may modify the object dictionary (e.g. removing keys for values stored in
        other columns).
    """

    def __init__(self):
        super().__init__('body', 'JSONB', False, False)

    def db_row_to_object[T](self, from_db_row: Dict[str, Any], to_object_dict: Dict[str, Any]):
        #  Get a dictionary of all class attributes that aren't stored in their own column
        # and update the to_object_dict with it
        # NOTE: Custom select statements may query for results that don't have a body
        # column. Everything else should have one.
        partial_object_dict: Dict[str, Any] | None = from_db_row.get(self._name)
        if partial_object_dict is not None:
            to_object_dict.update(partial_object_dict)

    def object_to_db_update(self, obj_dict: Dict[str, Any]) -> DbUpdate:
        # Get the obj_dict and serialize it to jsonb
        # NOTE: This mapper must run last. It assumes all attributes that should be stored
        #   in their own columns have already been removed from obj_dict
        return DbUpdate(
            value=Jsonb(obj_dict),
            column_name=self.name
        )
