What is a Resource? =================================== .. contents:: Table of Contents :depth: 2 :local: Introduction ------------ Resources in Malevich Nova are Python classes that describe a subgraph in the database. You declare a resource by subclassing ``Resource`` and adding fields that describe the main node (pivot) and its relationships (mounts). Resource enables you to create a portion of the graph atomically and retrieve larger chunks of data in a single query. Also, Resources may dictate the rules to access the data and provide custom business logic. Concepts ----------------- - **Pivot**: The main node of your resource. Think of it as the root or entry point. - **Mount**: Use when the edge (relationship) is declared on the pivot node. - **ForeignMount**: Use when the edge is declared on another node, but you want to access related nodes from the perspective of your pivot. - **ResourceEdge**: A small container that glues a node or resource with an edge (relationship). Strong Typing ------------------------------- Both ``Mount`` and ``ForeignMount`` have the same type signature: .. code-block:: python edge_definition[, resource=ResourceType, array=True|False] The declared field automatically converted to a proper ``ResourceEdge`` type. When setting ``array=True``, the type becomes a list of ``ResourceEdge`` objects. Setting ``resource=...`` makes the type a resource instead of a node (e.g., ``ResourceEdge[CommentResource, Link]``). If the provided edge definition uses the model (``edge = Relation(model=...)``), the type of ResourceEdge will use it instead of the default ``Link``. .. note:: The direction of the edge does not matter in the perspective of the resource. The type of the following mounts will be the same: .. code-block:: python class User(Node): wrote = Relation(Post) written_by = Relation(Post, incoming=True) class PostResource(Resource): post = Pivot(Post) author = Mount(Post.wrote) # type: ResourceEdge[User, Link] written_by = Mount(Post.written_by) # type: ResourceEdge[User, Link] What is ResourceEdge? --------------------- A ``ResourceEdge`` is a small object that holds both the related node (or resource) and the edge (relationship) data. Its type signature is: .. code-block:: python class ResourceEdge(Generic[NodeType, EdgeType]): resource: NodeType # The related node or resource edge: EdgeType | None # The edge data (can be None) For example, ``ResourceEdge[User, Link]`` means you get a User node and the Link (relationship) between your pivot and that user. - If you use ``resource=...`` in your mount, ``NodeType`` becomes your resource class instead of a node. - If you use ``array=True``, you get a list of ``ResourceEdge`` objects. Mount vs ForeignMount: What Declares the Edge? ---------------------------------------------- The **key difference** between ``Mount`` and ``ForeignMount`` is **where the edge is declared in your data model**, not the direction of the relationship. - **Mount**: Use when the edge is declared on the pivot node (the main node of your resource). - **ForeignMount**: Use when the edge is declared on another node, but you want to access related nodes from the perspective of your pivot. **Direction does not matter**—the direction is set by the ``incoming=True`` flag in your model's ``Relation`` or ``FutureRelation``. Always check where the edge is actually declared in your node classes to decide which mount type to use. **Example:** .. code-block:: python class User(Node): ... class Post(Node): author = Relation(to=User) class PostResource(Resource): post = Pivot(Post) author = Mount(Post.author) # Post declares the edge 'author' class UserResource(Resource): user = Pivot(User) # Declared not by User, but by Post, so we use ForeignMount posts = ForeignMount(Post.author, array=True) - In ``PostResource``, use ``Mount`` because ``Post`` declares the ``author`` edge. - In ``UserResource``, use ``ForeignMount`` because you want to collect all posts that reference the user, but the edge is declared on ``Post``. Best Practices -------------- - Always declare exactly one ``Pivot`` per resource. - Use ``Mount`` when the edge is declared on the pivot node. - Use ``ForeignMount`` when the edge is declared on another node. - Use ``array=True`` to collect multiple edges. - Use ``resource=...`` to nest resources for deep subgraphs. See the API docs for :class:`nova.resource.base.Resource`, :class:`nova.resource.base.Mount`, :class:`nova.resource.base.ForeignMount`, and :class:`nova.resource.base.ResourceEdge` for more details.