"""Issuer Database Tables/Models.

Models of the Traction tables for Issuer and related data.

"""
import uuid
from datetime import datetime
from typing import List, Optional

from sqlalchemy.orm import selectinload
from sqlmodel import Field, Relationship
from sqlalchemy import (
    Column,
    func,
    String,
    select,
    desc,
    JSON,
    text,
)
from sqlalchemy.dialects.postgresql import UUID, TIMESTAMP, ARRAY
from sqlmodel.ext.asyncio.session import AsyncSession

from api.db.models.base import BaseModel
from api.db.models.v1.contact import Contact
from api.db.models.v1.governance import CredentialTemplate

from api.endpoints.models.v1.errors import (
    NotFoundError,
)


class IssuerCredential(BaseModel, table=True):
    """Issuer Credential.

    Model for the Issuer Credential table (postgresql specific dialects in use).
    This will track Issuer Credentials for the Tenants.

    Attributes:
      issuer_credential_id: Traction ID for issuer credential
      credential_template_id: Traction Credential Template ID
      contact_id: Traction Contact ID
      cred_def_id: Credential Definition ID (ledger)
      tenant_id: Traction Tenant ID
      status: Business and Tenant indicator for Credential state; independent of AcaPy
        Credential Exchange state
      external_reference_id: Set by tenant to correlate this Credential with entity in
        external system
      revoked: when True, this credential has been revoked
      deleted: Issuer Credential "soft" delete indicator.
      preview_persisted: when True, store the credential attributes and preview
      tags: Set by tenant for arbitrary grouping of Credentials
      comment: Comment supplied when issuing
      credential_preview: attributes (list of name / values ) for offered/issued cred.
        This will be empty once offer is made and preview_persisted = False.
      revocation_comment: comment entered when revoking Credential
      state: The underlying AcaPy credential exchange state
      thread_id: AcaPy thread id
      credential_exchange_id: AcaPy id for the credential exchange
      revoc_reg_id: revocation registry id (needed for revocation)
      revocation_id: credential revocation id (needed for revocation)
      created_at: Timestamp when record was created in Traction
      updated_at: Timestamp when record was last modified in Traction
    """

    __tablename__ = "issuer_credential"

    issuer_credential_id: uuid.UUID = Field(
        sa_column=Column(
            UUID(as_uuid=True),
            primary_key=True,
            server_default=text("gen_random_uuid()"),
        )
    )
    credential_template_id: uuid.UUID = Field(
        foreign_key="credential_template.credential_template_id", index=True
    )
    tenant_id: uuid.UUID = Field(foreign_key="tenant.id", index=True)
    contact_id: uuid.UUID = Field(foreign_key="contact.contact_id", index=True)
    status: str = Field(nullable=False)
    external_reference_id: str = Field(nullable=True)
    revoked: bool = Field(nullable=False, default=False)
    deleted: bool = Field(nullable=False, default=False)
    tags: List[str] = Field(sa_column=Column(ARRAY(String)))
    preview_persisted: bool = Field(nullable=False, default=False)

    comment: str = Field(nullable=True)
    revocation_comment: str = Field(nullable=True)

    # acapy data ---
    state: str = Field(nullable=False)
    cred_def_id: str = Field(nullable=False, index=True)
    thread_id: str = Field(nullable=True)
    credential_exchange_id: str = Field(nullable=True)
    revoc_reg_id: str = Field(nullable=True)
    revocation_id: str = Field(nullable=True)
    credential_preview: dict = Field(default={}, sa_column=Column(JSON))
    # --- acapy data

    # relationships ---
    contact: Optional[Contact] = Relationship(back_populates="issuer_credentials")
    credential_template: Optional[CredentialTemplate] = Relationship(
        back_populates="issuer_credentials"
    )
    # --- relationships

    created_at: datetime = Field(
        sa_column=Column(TIMESTAMP, nullable=False, server_default=func.now())
    )
    updated_at: datetime = Field(
        sa_column=Column(
            TIMESTAMP, nullable=False, server_default=func.now(), onupdate=func.now()
        )
    )

    @classmethod
    async def get_by_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        issuer_credential_id: uuid.UUID,
        deleted: bool | None = False,
    ) -> "IssuerCredential":
        """Get IssuerCredential by id.

        Find and return the database CredentialDefinition record

        Args:
          db: database session
          tenant_id: Traction ID of tenant making the call
          issuer_credential_id: Traction ID of IssuerCredential

        Returns: The Traction IssuerCredential (db) record

        Raises:
          NotFoundError: if the IssuerCredential cannot be found by ID and deleted
          flag
        """

        q = (
            select(cls)
            .where(cls.tenant_id == tenant_id)
            .where(cls.issuer_credential_id == issuer_credential_id)
            .where(cls.deleted == deleted)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
        )
        q_result = await db.execute(q)
        db_rec = q_result.scalar_one_or_none()
        if not db_rec:
            raise NotFoundError(
                code="issuer_credential.id_not_found",
                title="Issuer Credential does not exist",
                detail=f"Issuer Credential does not exist for id<{issuer_credential_id}>",  # noqa: E501
            )
        return db_rec

    @classmethod
    async def get_by_credential_exchange_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        credential_exchange_id: str,
    ) -> "IssuerCredential":
        """Get IssuerCredential by Credential Exchange ID.

        Find and return the database IssuerCredential record

        Args:
          db: database session
          tenant_id: Traction ID of tenant making the call
          credential_exchange_id: acapy message Credential Exchange ID

        Returns: The Traction IssuerCredential (db) record

        Raises:
          NotFoundError: if the IssuerCredential cannot be found by ID and deleted
          flag
        """

        q = (
            select(cls)
            .where(cls.tenant_id == tenant_id)
            .where(cls.credential_exchange_id == credential_exchange_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
        )
        q_result = await db.execute(q)
        db_rec = q_result.scalar_one_or_none()
        if not db_rec:
            raise NotFoundError(
                code="issuer_credential.credential_exchange_id_not_found",
                title="Issuer Credential does not exist",
                detail=f"Issuer Credential does not exist for credential exchange id<{credential_exchange_id}>",  # noqa: E501
            )
        return db_rec

    @classmethod
    async def list_by_credential_template_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        credential_template_id: uuid.UUID,
    ) -> List["IssuerCredential"]:
        """List by Credential Template ID.

        Find and return list of Issuer Credential records for Credential Template.

          tenant_id: Traction ID of tenant making the call
          credential_template_id: Traction ID of Credential Template

        Returns: List of Traction IssuerCredential (db) records in descending order
        """

        q = (
            select(cls)
            .where(cls.credential_template_id == credential_template_id)
            .where(cls.tenant_id == tenant_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
            .order_by(desc(cls.updated_at))
        )
        q_result = await db.execute(q)
        db_recs = q_result.scalars()
        return db_recs

    @classmethod
    async def list_by_cred_def_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        cred_def_id: str,
    ) -> List["IssuerCredential"]:
        """List by Cred Def ID.

        Find and return list of Issuer Credential records for Cred. Def.

          tenant_id: Traction ID of tenant making the call
          cred_def_id: Traction ID of Credential Definition

        Returns: List of Traction IssuerCredential (db) records in descending order
        """

        q = (
            select(cls)
            .where(cls.cred_def_id == cred_def_id)
            .where(cls.tenant_id == tenant_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
            .order_by(desc(cls.updated_at))
        )
        q_result = await db.execute(q)
        db_recs = q_result.scalars()
        return db_recs

    @classmethod
    async def list_by_contact_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        contact_id: uuid.UUID,
    ) -> List["IssuerCredential"]:
        """List by Contact ID.

        Find and return list of Issuer Credential records for Contact.

          tenant_id: Traction ID of tenant making the call
          contact_id: Traction ID of Contact

        Returns: List of Traction IssuerCredential (db) records in descending order
        """

        q = (
            select(cls)
            .where(cls.contact_id == contact_id)
            .where(cls.tenant_id == tenant_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
            .order_by(desc(cls.updated_at))
        )
        q_result = await db.execute(q)
        db_recs = q_result.scalars()
        return db_recs

    @classmethod
    async def list_by_tenant_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
    ) -> List["IssuerCredential"]:
        """List by Tenant ID.

        Find and return list of Issuer Credential records for Tenant.

          tenant_id: Traction ID of tenant making the call

        Returns: List of Traction Issuer Credential (db) records in descending order
        """

        q = (
            select(cls)
            .where(cls.tenant_id == tenant_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
            .order_by(desc(cls.updated_at))
        )
        q_result = await db.execute(q)
        db_recs = q_result.scalars()
        return db_recs

    @classmethod
    async def list_by_thread_id(
        cls: "IssuerCredential",
        db: AsyncSession,
        tenant_id: uuid.UUID,
        thread_id: str,
    ) -> List["IssuerCredential"]:
        """List by Thread ID.

        Find and return list of Issuer Credential records for Thread ID.

          tenant_id: Traction ID of tenant making the call
          thread_id: AcaPy Thread ID of Issuer Credential

        Returns: List of Traction IssuerCredential (db) records in descending order
        """

        q = (
            select(cls)
            .where(cls.thread_id == thread_id)
            .where(cls.tenant_id == tenant_id)
            .options(selectinload(cls.contact), selectinload(cls.credential_template))
            .order_by(desc(cls.updated_at))
        )
        q_result = await db.execute(q)
        db_recs = q_result.scalars()
        return db_recs


class IssuerCredentialTimeline(BaseModel, table=True):
    """Issuer Credential Timeline.

    Model for Issuer Credential Timeline table (postgresql specific dialects in use).
    Timeline represents history of changes to status and/or state.

    Attributes:
      issuer_credential_timeline_id: Unique ID in table
      issuer_credential_id: Traction Issuer Credential ID
      status: Business and Tenant indicator for Issuer Credential state; independent of
        AcaPy Credential State
      state: The underlying AcaPy Credential state
      created_at: Timestamp when record was created in Traction
    """

    __tablename__ = "issuer_credential_timeline"

    issuer_credential_timeline_id: uuid.UUID = Field(
        sa_column=Column(
            UUID(as_uuid=True),
            primary_key=True,
            server_default=text("gen_random_uuid()"),
        )
    )
    issuer_credential_id: uuid.UUID = Field(
        foreign_key="issuer_credential.issuer_credential_id", index=True
    )

    status: str = Field(nullable=False)
    state: str = Field(nullable=False)
    created_at: datetime = Field(
        sa_column=Column(TIMESTAMP, nullable=False, server_default=func.now())
    )

    @classmethod
    async def list_by_issuer_credential_id(
        cls: "IssuerCredentialTimeline",
        db: AsyncSession,
        issuer_credential_id: UUID,
    ) -> List:
        """List by Issuer Credential ID.

        Find and return list of Timeline records for Issuer Credential.

        Args:
          db: database session
          issuer_credential_id: Traction ID of Issuer Credential

        Returns: List of Traction Issuer Credential Timeline (db) records in descending
          order
        """

        q = (
            select(cls)
            .where(cls.issuer_credential_id == issuer_credential_id)
            .order_by(desc(cls.created_at))
        )
        q_result = await db.execute(q)
        db_items = q_result.scalars()
        return db_items

sqlmodel.Relationship sqlalchemy.select sqlalchemy.func.now sqlmodel.Field sqlalchemy.orm.selectinload sqlalchemy.dialects.postgresql.ARRAY sqlalchemy.dialects.postgresql.UUID sqlalchemy.text api.endpoints.models.v1.errors.NotFoundError sqlalchemy.Column sqlalchemy.desc
[((2667, 2742), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""credential_template.credential_template_id"""', 'index': '(True)'}), "(foreign_key='credential_template.credential_template_id', index=True)\n", (2672, 2742), False, 'from sqlmodel import Field, Relationship\n'), ((2784, 2826), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""tenant.id"""', 'index': '(True)'}), "(foreign_key='tenant.id', index=True)\n", (2789, 2826), False, 'from sqlmodel import Field, Relationship\n'), ((2855, 2906), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""contact.contact_id"""', 'index': '(True)'}), "(foreign_key='contact.contact_id', index=True)\n", (2860, 2906), False, 'from sqlmodel import Field, Relationship\n'), ((2925, 2946), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)'}), '(nullable=False)\n', (2930, 2946), False, 'from sqlmodel import Field, Relationship\n'), ((2980, 3000), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (2985, 3000), False, 'from sqlmodel import Field, Relationship\n'), ((3021, 3057), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)', 'default': '(False)'}), '(nullable=False, default=False)\n', (3026, 3057), False, 'from sqlmodel import Field, Relationship\n'), ((3078, 3114), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)', 'default': '(False)'}), '(nullable=False, default=False)\n', (3083, 3114), False, 'from sqlmodel import Field, Relationship\n'), ((3206, 3242), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)', 'default': '(False)'}), '(nullable=False, default=False)\n', (3211, 3242), False, 'from sqlmodel import Field, Relationship\n'), ((3263, 3283), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3268, 3283), False, 'from sqlmodel import Field, Relationship\n'), ((3314, 3334), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3319, 3334), False, 'from sqlmodel import Field, Relationship\n'), ((3374, 3395), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)'}), '(nullable=False)\n', (3379, 3395), False, 'from sqlmodel import Field, Relationship\n'), ((3419, 3452), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)', 'index': '(True)'}), '(nullable=False, index=True)\n', (3424, 3452), False, 'from sqlmodel import Field, Relationship\n'), ((3474, 3494), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3479, 3494), False, 'from sqlmodel import Field, Relationship\n'), ((3529, 3549), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3534, 3549), False, 'from sqlmodel import Field, Relationship\n'), ((3574, 3594), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3579, 3594), False, 'from sqlmodel import Field, Relationship\n'), ((3620, 3640), 'sqlmodel.Field', 'Field', ([], {'nullable': '(True)'}), '(nullable=True)\n', (3625, 3640), False, 'from sqlmodel import Field, Relationship\n'), ((3793, 3842), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""issuer_credentials"""'}), "(back_populates='issuer_credentials')\n", (3805, 3842), False, 'from sqlmodel import Field, Relationship\n'), ((3899, 3948), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""issuer_credentials"""'}), "(back_populates='issuer_credentials')\n", (3911, 3948), False, 'from sqlmodel import Field, Relationship\n'), ((12401, 12472), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""issuer_credential.issuer_credential_id"""', 'index': '(True)'}), "(foreign_key='issuer_credential.issuer_credential_id', index=True)\n", (12406, 12472), False, 'from sqlmodel import Field, Relationship\n'), ((12506, 12527), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)'}), '(nullable=False)\n', (12511, 12527), False, 'from sqlmodel import Field, Relationship\n'), ((12545, 12566), 'sqlmodel.Field', 'Field', ([], {'nullable': '(False)'}), '(nullable=False)\n', (12550, 12566), False, 'from sqlmodel import Field, Relationship\n'), ((3700, 3712), 'sqlalchemy.Column', 'Column', (['JSON'], {}), '(JSON)\n', (3706, 3712), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((5189, 5214), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (5201, 5214), False, 'from sqlalchemy.orm import selectinload\n'), ((5216, 5253), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (5228, 5253), False, 'from sqlalchemy.orm import selectinload\n'), ((5392, 5571), 'api.endpoints.models.v1.errors.NotFoundError', 'NotFoundError', ([], {'code': '"""issuer_credential.id_not_found"""', 'title': '"""Issuer Credential does not exist"""', 'detail': 'f"""Issuer Credential does not exist for id<{issuer_credential_id}>"""'}), "(code='issuer_credential.id_not_found', title=\n    'Issuer Credential does not exist', detail=\n    f'Issuer Credential does not exist for id<{issuer_credential_id}>')\n", (5405, 5571), False, 'from api.endpoints.models.v1.errors import NotFoundError\n'), ((6543, 6568), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (6555, 6568), False, 'from sqlalchemy.orm import selectinload\n'), ((6570, 6607), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (6582, 6607), False, 'from sqlalchemy.orm import selectinload\n'), ((6746, 6971), 'api.endpoints.models.v1.errors.NotFoundError', 'NotFoundError', ([], {'code': '"""issuer_credential.credential_exchange_id_not_found"""', 'title': '"""Issuer Credential does not exist"""', 'detail': 'f"""Issuer Credential does not exist for credential exchange id<{credential_exchange_id}>"""'}), "(code='issuer_credential.credential_exchange_id_not_found',\n    title='Issuer Credential does not exist', detail=\n    f'Issuer Credential does not exist for credential exchange id<{credential_exchange_id}>'\n    )\n", (6759, 6971), False, 'from api.endpoints.models.v1.errors import NotFoundError\n'), ((7909, 7929), 'sqlalchemy.desc', 'desc', (['cls.updated_at'], {}), '(cls.updated_at)\n', (7913, 7929), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((8812, 8832), 'sqlalchemy.desc', 'desc', (['cls.updated_at'], {}), '(cls.updated_at)\n', (8816, 8832), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((9699, 9719), 'sqlalchemy.desc', 'desc', (['cls.updated_at'], {}), '(cls.updated_at)\n', (9703, 9719), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((10459, 10479), 'sqlalchemy.desc', 'desc', (['cls.updated_at'], {}), '(cls.updated_at)\n', (10463, 10479), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((11350, 11370), 'sqlalchemy.desc', 'desc', (['cls.updated_at'], {}), '(cls.updated_at)\n', (11354, 11370), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((13338, 13358), 'sqlalchemy.desc', 'desc', (['cls.created_at'], {}), '(cls.created_at)\n', (13342, 13358), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((2507, 2525), 'sqlalchemy.dialects.postgresql.UUID', 'UUID', ([], {'as_uuid': '(True)'}), '(as_uuid=True)\n', (2511, 2525), False, 'from sqlalchemy.dialects.postgresql import UUID, TIMESTAMP, ARRAY\n'), ((3160, 3173), 'sqlalchemy.dialects.postgresql.ARRAY', 'ARRAY', (['String'], {}), '(String)\n', (3165, 3173), False, 'from sqlalchemy.dialects.postgresql import UUID, TIMESTAMP, ARRAY\n'), ((12243, 12261), 'sqlalchemy.dialects.postgresql.UUID', 'UUID', ([], {'as_uuid': '(True)'}), '(as_uuid=True)\n', (12247, 12261), False, 'from sqlalchemy.dialects.postgresql import UUID, TIMESTAMP, ARRAY\n'), ((2584, 2609), 'sqlalchemy.text', 'text', (['"""gen_random_uuid()"""'], {}), "('gen_random_uuid()')\n", (2588, 2609), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((4089, 4099), 'sqlalchemy.func.now', 'func.now', ([], {}), '()\n', (4097, 4099), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((4221, 4231), 'sqlalchemy.func.now', 'func.now', ([], {}), '()\n', (4229, 4231), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((4242, 4252), 'sqlalchemy.func.now', 'func.now', ([], {}), '()\n', (4250, 4252), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((7821, 7846), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (7833, 7846), False, 'from sqlalchemy.orm import selectinload\n'), ((7848, 7885), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (7860, 7885), False, 'from sqlalchemy.orm import selectinload\n'), ((8724, 8749), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (8736, 8749), False, 'from sqlalchemy.orm import selectinload\n'), ((8751, 8788), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (8763, 8788), False, 'from sqlalchemy.orm import selectinload\n'), ((9611, 9636), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (9623, 9636), False, 'from sqlalchemy.orm import selectinload\n'), ((9638, 9675), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (9650, 9675), False, 'from sqlalchemy.orm import selectinload\n'), ((10371, 10396), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (10383, 10396), False, 'from sqlalchemy.orm import selectinload\n'), ((10398, 10435), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (10410, 10435), False, 'from sqlalchemy.orm import selectinload\n'), ((11262, 11287), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.contact'], {}), '(cls.contact)\n', (11274, 11287), False, 'from sqlalchemy.orm import selectinload\n'), ((11289, 11326), 'sqlalchemy.orm.selectinload', 'selectinload', (['cls.credential_template'], {}), '(cls.credential_template)\n', (11301, 11326), False, 'from sqlalchemy.orm import selectinload\n'), ((12320, 12345), 'sqlalchemy.text', 'text', (['"""gen_random_uuid()"""'], {}), "('gen_random_uuid()')\n", (12324, 12345), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((12668, 12678), 'sqlalchemy.func.now', 'func.now', ([], {}), '()\n', (12676, 12678), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((13235, 13246), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (13241, 13246), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((6390, 6401), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (6396, 6401), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((10291, 10302), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (10297, 10302), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((4997, 5008), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (5003, 5008), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((7668, 7679), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (7674, 7679), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((8593, 8604), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (8599, 8604), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((9482, 9493), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (9488, 9493), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n'), ((11135, 11146), 'sqlalchemy.select', 'select', (['cls'], {}), '(cls)\n', (11141, 11146), False, 'from sqlalchemy import Column, func, String, select, desc, JSON, text\n')]