Skip to main content

Module generic_repository

Module generic_repository 

Source
Expand description

GenericCrudRepository<T, DeleteMode> — one implementation for all entities.

The generated repository file previously duplicated ~20 identical method bodies for every entity. This module provides those implementations once so that the generator can emit a thin newtype wrapper instead of hundreds of lines of copy-paste.

§Delete mode markers

MarkerBehaviour
SoftDeletedeleted_at stored in metadata JSONB; active rows filter IS NULL
HardDeleteRows are permanently deleted; no trash concept

§Generated output (after this change)

ⓘ
// ~20 lines total instead of ~460-560
pub struct UserRepository(
    backbone_orm::GenericCrudRepository<User, backbone_orm::SoftDelete>
);
impl std::ops::Deref for UserRepository {
    type Target = backbone_orm::GenericCrudRepository<User, backbone_orm::SoftDelete>;
    fn deref(&self) -> &Self::Target { &self.0 }
}
impl UserRepository {
    pub fn new(pool: sqlx::PgPool) -> Self {
        Self(backbone_orm::GenericCrudRepository::new(pool, "users"))
    }
    // entity-specific methods only:
    pub async fn find_by_email(&self, email: &str) -> anyhow::Result<Option<User>> { … }
    pub async fn partial_update(…) { … }
    pub async fn list_paginated_filtered(…) { … }
}
backbone_core::impl_crud_repository!(UserRepository, User, soft_delete);

Structs§

GenericCrudRepository
Generic PostgreSQL CRUD repository parameterised by entity type T and delete strategy D (SoftDelete or HardDelete).
HardDelete
Marker: entity uses hard deletes only — no soft delete / trash concept.
MissingCompanyScope
The caller could not be scoped to a company for an entity that requires one.
SoftDelete
Marker: entity uses JSONB-based soft delete (metadata->>'deleted_at').

Traits§

EntityRepoMeta
Metadata trait that entities implement so GenericCrudRepository can provide list_paginated_filtered and list_deleted_filtered without per-entity boilerplate.

Functions§

and_conditions
AND two optional SQL conditions into the single __base_condition slot.
company_fence
Build the SQL fence for T, or fail closed.
fetch_by_ids_as_json
Fetch rows from an arbitrary table by id list, as JSON — hydrates ?include= relations in the generic CRUD handler without a typed repository for the target entity. table is a generator-emitted collection name (from EntityRepoMeta::relations()), NEVER client input, so the interpolation is not an injection vector. caller_table is the hydrated entity’s own (schema-qualified) table name, used to qualify a bare table — see qualify_relation_table. One batched WHERE id = ANY(...) per relation. Returns row_to_json objects keyed by raw (snake_case) column names.
qualify_relation_table
Qualify a relation target table with the calling entity’s schema.
strip_client_company_filters
Remove any caller-supplied filter on the company column.