luplo.core.items ================ .. py:module:: luplo.core.items .. autoapi-nested-parse:: CRUD operations for the items table. Items are the central entity in luplo — decisions, knowledge, policies, and documents all live here. Edits create new rows via ``supersedes_id`` (the old row is never mutated). Deletes are soft (``deleted_at`` is set, row stays). Attributes ---------- .. autoapisummary:: luplo.core.items.ITEM_COLUMNS Functions --------- .. autoapisummary:: luplo.core.items.row_to_item luplo.core.items.create_item luplo.core.items.get_item luplo.core.items.get_item_including_deleted luplo.core.items.list_items luplo.core.items.delete_item luplo.core.items.get_supersedes_chain Module Contents --------------- .. py:data:: ITEM_COLUMNS :value: ('id', 'project_id', 'item_type', 'title', 'body', 'source_url', 'parent_item_id',... .. py:function:: row_to_item(row: dict[str, Any]) -> luplo.core.models.Item Convert a dict-row into an Item, dropping unknown columns and NULL-safe defaults. .. py:function:: create_item(conn: psycopg.AsyncConnection[Any], data: luplo.core.models.ItemCreate) -> luplo.core.models.Item :async: Insert a new item and return it. * Generates a UUID4 ``id`` automatically. * Populates ``search_tsv`` from title + body + rationale. * If ``data.supersedes_id`` is set the new row is treated as an edit of the referenced item (the old row is untouched). :param conn: An async psycopg connection (inside an open transaction). :param data: Fields for the new item. :returns: The fully-populated ``Item`` as stored in the database. .. py:function:: get_item(conn: psycopg.AsyncConnection[Any], item_id: str, *, project_id: str | None = None) -> luplo.core.models.Item | None :async: Fetch a single item by ID or hex prefix. :param conn: Open async connection. :param item_id: Either a full UUID or a hex prefix of at least :data:`luplo.core.id_resolve.MIN_PREFIX_LENGTH` characters. :param project_id: Optional project scope for prefix lookups. Strongly recommended whenever the caller knows it; without it, prefix collisions are evaluated across every project in the database. :returns: The matching item, or ``None`` when no row exists / the row is soft-deleted. :raises AmbiguousIdError: If the prefix matches multiple rows. :raises IdTooShortError: If a hex prefix shorter than the minimum is supplied. :raises InvalidIdFormatError: If the input is not a UUID or hex prefix. .. py:function:: get_item_including_deleted(conn: psycopg.AsyncConnection[Any], item_id: str, *, project_id: str | None = None) -> luplo.core.models.Item | None :async: Fetch a single item by ID or prefix, even if soft-deleted. See :func:`get_item` for argument and exception semantics. The only difference is that soft-deleted rows are still returned. .. py:function:: list_items(conn: psycopg.AsyncConnection[Any], project_id: str, *, item_type: str | None = None, system_id: str | None = None, work_unit_id: str | None = None, include_deleted: bool = False, limit: int = 100, offset: int = 0) -> list[luplo.core.models.Item] :async: List items for a project with optional filters. :param conn: Async psycopg connection. :param project_id: Required project scope. :param item_type: Filter by ``item_type`` (e.g. ``"decision"``). :param system_id: Filter items whose ``system_ids`` array contains this value. :param work_unit_id: Filter by ``work_unit_id``. :param include_deleted: If ``True``, include soft-deleted items. :param limit: Maximum rows returned (default 100). :param offset: Pagination offset. :returns: List of ``Item`` ordered by ``created_at DESC``. .. py:function:: delete_item(conn: psycopg.AsyncConnection[Any], item_id: str, *, actor_id: str) -> bool :async: Soft-delete an item by setting ``deleted_at``. The row is never removed. ``get_item`` will return ``None`` for it, but ``list_items(include_deleted=True)`` will still find it. :param conn: Async psycopg connection. :param item_id: ID of the item to delete. :param actor_id: Who performed the deletion (for audit trail). :returns: ``True`` if the item existed and was deleted, ``False`` if it was already deleted or not found. .. py:function:: get_supersedes_chain(conn: psycopg.AsyncConnection[Any], item_id: str) -> list[luplo.core.models.Item] :async: Walk the ``supersedes_id`` chain from *item_id* back to the original. Returns the full chain ordered **oldest-first** (the original item is at index 0, the most recent version — *item_id* itself — is last). If *item_id* does not exist, returns an empty list.