from pydantic import ConfigDict
from sqlalchemy import Index, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlmodel import Column, Field, ForeignKey, Integer, String
from app.model.base_model import BaseModel
[docs]
class UserPoints(BaseModel, table=True):
"""
Represents the points and associated data for a user.
Attributes:
points (int): The number of points.
caseName (str): The name of the case.
data (dict): A JSON object containing additional data.
description (str): A description of the user points.
userId (str): The ID of the user associated with the points.
taskId (str): The ID of the task associated with the points.
"""
__table_args__ = (
UniqueConstraint(
"userId",
"taskId",
"idempotencyKey",
name="uq_user_points_user_task_idempotency",
),
Index(
"ix_user_points_task_user_created",
"taskId",
"userId",
"created_at",
),
)
points: int = Field(sa_column=Column(Integer))
caseName: str = Field(sa_column=Column(String, nullable=True))
idempotencyKey: str = Field(sa_column=Column(String, nullable=True))
data: dict = Field(sa_column=Column(JSONB, nullable=True))
description: str = Field(sa_column=Column(String, nullable=True))
userId: str = Field(sa_column=Column(UUID(as_uuid=True), ForeignKey("users.id")))
taskId: str = Field(sa_column=Column(UUID(as_uuid=True), ForeignKey("tasks.id")))
apiKey_used: str = Field(
sa_column=Column(String, ForeignKey("apikey.apiKey"), nullable=True)
)
model_config = ConfigDict(from_attributes=True)
def __str__(self):
return (
f"UserPoints (id={self.id}, created_at={self.created_at},"
f" updated_at={self.updated_at}, points={self.points}, "
f"caseName={self.caseName}, idempotencyKey={self.idempotencyKey}, data={self.data}, " # noqa
f"description={self.description}, userId={self.userId}, "
f"taskId={self.taskId})"
)
def __repr__(self):
return (
f"UserPoints (id={self.id}, created_at={self.created_at}, "
f"updated_at={self.updated_at}, points={self.points}, "
f"caseName={self.caseName}, idempotencyKey={self.idempotencyKey}, data={self.data}, " # noqa
f"description={self.description}, userId={self.userId}, "
f"taskId={self.taskId})"
)
def __eq__(self, other):
return (
isinstance(other, UserPoints)
and self.id == other.id
and self.points == other.points
and self.caseName == other.caseName
and self.idempotencyKey == other.idempotencyKey
and self.data == other.data
and self.description == other.description
and self.userId == other.userId
and self.taskId == other.taskId
)
[docs]
def make_hashable(self, obj):
"""
Recursively convert a nested structure into a hashable form.
Lists/tuples become tuples and dicts become sorted tuples of
``(key, value)`` pairs, so the JSON ``data`` field can be folded into
``__hash__``. Scalars are returned unchanged.
Args:
obj: The value (possibly nested list/dict) to make hashable.
Returns:
A hashable equivalent of ``obj``.
"""
if isinstance(obj, (tuple, list)):
return tuple(self.make_hashable(e) for e in obj)
elif isinstance(obj, dict):
return tuple(sorted((k, self.make_hashable(v)) for k, v in obj.items()))
else:
return obj
def __hash__(self):
data_as_hashable = self.make_hashable(self.data)
return hash(
(
self.points,
self.caseName,
self.idempotencyKey,
data_as_hashable,
self.description,
self.userId,
self.taskId,
)
)