Skip to main content

CrudRepository

Trait CrudRepository 

Source
pub trait CrudRepository<E>: Send + Sync{
Show 29 methods // Required methods fn create<'life0, 'async_trait>( &'life0 self, entity: E, ) -> Pin<Box<dyn Future<Output = Result<E, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn find_by_id<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn find_by_id_including_deleted<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn update<'life0, 'async_trait>( &'life0 self, entity: E, ) -> Pin<Box<dyn Future<Output = Result<E, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn soft_delete<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn restore<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn hard_delete<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait; fn list<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn list_deleted<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn count<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn count_deleted<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn bulk_create<'life0, 'async_trait>( &'life0 self, entities: Vec<E>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; fn empty_trash<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait; // Provided methods fn update_changed<'life0, 'life1, 'async_trait>( &'life0 self, before: &'life1 E, after: E, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn list_deleted_filtered<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn list_filtered<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn list_filtered_with_info<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, PaginationInfo), RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn table_name(&self) -> Option<&str> { ... } fn write_pool(&self) -> Option<&PgPool> { ... } fn aggregate_filtered<'life0, 'life1, 'async_trait>( &'life0 self, spec: &'life1 AggregateSpec, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<AggregateResult, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn fetch_related_json<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _table: &'life1 str, _ids: &'life2 [String], ) -> Pin<Box<dyn Future<Output = Vec<Value>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn reference_visible<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, table: &'life1 str, column: &'life2 str, value: &'life3 Value, ) -> Pin<Box<dyn Future<Output = Result<Option<bool>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait { ... } fn exists<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn bulk_soft_delete<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn bulk_restore<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn bulk_hard_delete<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn restore_all<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn bulk_update<'life0, 'async_trait>( &'life0 self, entities: Vec<E>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... } fn bulk_update_changed<'life0, 'async_trait>( &'life0 self, pairs: Vec<(E, E)>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>> where Self: 'async_trait, 'life0: 'async_trait { ... }
}
Expand description

Core CRUD repository trait

This trait defines the basic CRUD operations that all repositories must implement. It’s designed to work with the CrudService trait from the HTTP layer.

Required Methods§

Source

fn create<'life0, 'async_trait>( &'life0 self, entity: E, ) -> Pin<Box<dyn Future<Output = Result<E, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Create a new entity

Source

fn find_by_id<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Find entity by ID (excluding soft-deleted)

Source

fn find_by_id_including_deleted<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Find entity by ID (including soft-deleted, for trash operations)

Source

fn update<'life0, 'async_trait>( &'life0 self, entity: E, ) -> Pin<Box<dyn Future<Output = Result<E, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Update an existing entity

Source

fn soft_delete<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Soft delete an entity

Source

fn restore<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Restore a soft-deleted entity

Source

fn hard_delete<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Permanently delete an entity

Source

fn list<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List entities with pagination (excluding soft-deleted)

Source

fn list_deleted<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List soft-deleted entities with pagination

Source

fn count<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Count all entities (excluding soft-deleted)

Source

fn count_deleted<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Count soft-deleted entities

Source

fn bulk_create<'life0, 'async_trait>( &'life0 self, entities: Vec<E>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Bulk create entities

Source

fn empty_trash<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Permanently delete all soft-deleted entities

Provided Methods§

Source

fn update_changed<'life0, 'life1, 'async_trait>( &'life0 self, before: &'life1 E, after: E, ) -> Pin<Box<dyn Future<Output = Result<Option<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Update an entity from before (the row as read) to after, writing only the fields whose value differs between the two. Ok(None) when the row no longer exists or was soft-deleted since it was read — the write must never revive it.

The path every generic read-modify-write (PUT, PATCH) takes: a field the caller did not change keeps whatever value the database holds now, so a concurrent write to it (a verb moving a status) is not overwritten with the stale value read before it. The generated Postgres repositories override this with a changed-columns UPDATE guarded by the not-deleted predicate. The default falls back to the full Self::update, which a repository with no partial write path has to accept.

Source

fn list_deleted_filtered<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List soft-deleted entities with pagination, filters and search — the trash twin of list_filtered.

Default implementation ignores filters and delegates to list_deleted(). The generated repositories override it with the same filter pushdown the active list uses.

Source

fn list_filtered<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, u64), RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

List entities with pagination and filters (excluding soft-deleted)

Default implementation ignores filters and delegates to list(). Override in repository implementations that support filter pushdown.

Source

fn list_filtered_with_info<'life0, 'async_trait>( &'life0 self, page: u32, limit: u32, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<(Vec<E>, PaginationInfo), RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

list_filtered, carrying the pagination info (cursor positions included) so the HTTP layer can surface keyset paging. Default: the tuple form with the cursor fields absent; the generated Postgres repositories override this with the real keyset walk.

Source

fn table_name(&self) -> Option<&str>

Group and reduce entities under the same filters as list_filtered.

There is deliberately no useful default. A repository that cannot group must SAY so: an honest error tells the caller its chart is unavailable, whereas a default returning zeros would render an empty chart that looks like a real answer about a real, empty table. The Postgres-backed generated repositories override this via impl_crud_repository!. The schema-qualified table this repository reads, when it knows it.

The Postgres-backed generated repositories override this; anything that cannot name a table returns None and simply has no history.

Source

fn write_pool(&self) -> Option<&PgPool>

The pool this repository writes through, when it has one.

The generic service opens one write transaction on it around each write (backbone_orm::in_write_tx), so the write, its hooks and the events they stage commit or roll back together. None (the default: an in-memory repository, a mock) leaves the write without a transaction of its own. The Postgres-backed generated repositories override this via impl_crud_repository!.

Source

fn aggregate_filtered<'life0, 'life1, 'async_trait>( &'life0 self, spec: &'life1 AggregateSpec, filters: HashMap<String, String>, ) -> Pin<Box<dyn Future<Output = Result<AggregateResult, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Hydrate ?include= relations: fetch rows from table by id list, as JSON (raw row_to_json). table comes from EntityRepoMeta::relations() (generator-emitted), never client input. Default: no expansion. The Postgres-backed generated repos override this via impl_crud_repository!.

Source

fn reference_visible<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, table: &'life1 str, column: &'life2 str, value: &'life3 Value, ) -> Pin<Box<dyn Future<Output = Result<Option<bool>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Whether the row of table whose column holds value is visible to the caller: read on the request’s own connection and scope, so a row row-level security hides counts as absent. table comes from PersistentEntity::references (generator-emitted), never from client input.

Ok(None) means this repository cannot tell; the write is then left to the database’s own key. That is the default. The Postgres-backed generated repositories override it via impl_crud_repository!.

Source

fn exists<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Check if an entity exists by ID

Source

fn bulk_soft_delete<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Soft-delete many entities by id. Returns the number affected.

Source

fn bulk_restore<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Restore many soft-deleted entities by id. Returns the restored entities.

Source

fn bulk_hard_delete<'life0, 'life1, 'async_trait>( &'life0 self, ids: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<u64, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Permanently delete many entities by id. Returns the number affected.

Source

fn restore_all<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Restore every soft-deleted entity. Returns the restored entities.

Source

fn bulk_update<'life0, 'async_trait>( &'life0 self, entities: Vec<E>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Update many entities atomically. Returns the updated entities.

Source

fn bulk_update_changed<'life0, 'async_trait>( &'life0 self, pairs: Vec<(E, E)>, ) -> Pin<Box<dyn Future<Output = Result<Vec<E>, RepositoryError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Update many entities from (before, after) pairs, writing for each only the fields that changed — the batch twin of update_changed, and the path the generic bulk PUT and bulk PATCH take. A row missing or deleted since it was read fails the batch, with the error placed on that item.

The generated Postgres repositories override this with one transaction. The default loops over update_changed and is not transactional.

Dyn Compatibility§

This trait is dyn compatible.

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

Implementors§