Skip to main content

EsRepo

Trait EsRepo 

Source
pub trait EsRepo: Send {
    type Entity: EsEntity;
    type ConstraintViolation: Rejection;
    type WriteError: Classify;
    type EsQueryFlavor;

    // Required methods
    fn nested_tree_spec() -> TreeSpec;
    fn hydrate_nested_from_rows(
        rows_by_tag: &mut HashMap<i32, Vec<Row>>,
        tag_cursor: &mut i32,
        entities: &mut [Self::Entity],
    ) -> Result<(), RepoReadError>;
}
Expand description

Required trait for all repositories to be compatible with es-entity and generate functions.

All repositories implement this trait to satisfy the basic requirements for type-safe database operations with the associated entity. The trait ensures validation that required fields (like entity) are present with compile-time errors. Implemented by the EsRepo derive macro with #[es_repo] attributes.

§Example

ⓘ

// Would show error for missing entity field if not provided in the `es_repo` attribute
#[derive(EsRepo, Debug)]
#[es_repo(entity = "User", columns(name(ty = "String")))]
pub struct Users {
    pool: PgPool,  // Required field for database operations
}

impl Users {
    pub fn new(pool: PgPool) -> Self {
        Self { pool }
   }
}

§in_op_only: making the operation mandatory

#[es_repo(in_op_only)] generates only the _in_op variants of every repo fn. The standalone fns are exactly the ones that open (or borrow) the pool on the caller’s behalf, so removing them makes passing an operation — an AtomicOperation for writes, an IntoOneTimeExecutor for reads — the only way to reach the database.

With no standalone fn left to open one, the pool field becomes optional. A repo that holds no pool cannot begin its own operation, which is the point: the discipline is enforced by construction rather than by convention.

Calling a non-_in_op fn on such a repo does not compile — the method does not exist (note the two tests below compile a real repo, so they need the test database, like the book’s examples):

ⓘ
use es_entity::*;
use serde::{Deserialize, Serialize};
// This repo deliberately KEEPS its pool, so that `create`, were it ever
// generated again, would compile: that makes the E0599 below prove the fn
// is absent, rather than merely that its body could not build an operation.
#[derive(EsRepo)]
#[es_repo(entity = "User", in_op_only, columns(name(ty = "String")))]
pub struct Users {
    pool: es_entity::db::Pool,
}

async fn reaches_the_db_without_an_op(repo: &Users, new_user: NewUser) {
    // error[E0599]: no method named `create` found — `in_op_only` leaves
    // only `create_in_op`, which demands an operation from the caller.
    repo.create(new_user).await.unwrap();
}

The _in_op twin of the very same call compiles:

use es_entity::*;
use serde::{Deserialize, Serialize};
#[derive(EsRepo)]
#[es_repo(entity = "User", in_op_only, columns(name(ty = "String")))]
pub struct Users {}

async fn takes_the_op_from_its_caller(
    repo: &Users,
    op: &mut impl AtomicOperation,
    new_user: NewUser,
) {
    repo.create_in_op(op, new_user).await.unwrap();
}

Required Associated Types§

Source

type Entity: EsEntity

Source

type ConstraintViolation: Rejection

The one repo Rejection: a violated database constraint the domain did not otherwise account for. Every generated write op returns Result<T, crate::RepoWriteError<Self::ConstraintViolation>>; find/list ops return Result<T, crate::RepoReadError> — reads never reject, so there is no NotFound rejection, only Fatal.

Source

type WriteError: Classify

The repo’s write classification made public and reusable: a consumer hand-writing a query against the repo’s own tables classifies its sqlx::Error the same way a generated write op would, with .classify::<Self::WriteError>()?.

Source

type EsQueryFlavor

Required Methods§

Source

fn nested_tree_spec() -> TreeSpec

Source

fn hydrate_nested_from_rows( rows_by_tag: &mut HashMap<i32, Vec<Row>>, tag_cursor: &mut i32, entities: &mut [Self::Entity], ) -> Result<(), RepoReadError>

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§