gremlin-orm 0.5.0

A lightweight, ORM for PostgreSQL, built on top of SQLx.
Documentation
//! # `gremlin-orm`
//!
//! This crate provides a lightweight, type-safe ORM for PostgreSQL in Rust, focusing on minimal boilerplate and compile-time query safety.
//!
//! ## Example
//!
//! ```rust
//! use gremlin_orm::Entity;
//!
//! #[derive(Entity, sqlx::FromRow)]
//! #[orm(table = "public.artist")]
//! struct Artist {
//!     #[orm(pk, generated)]
//!     id: i32,
//!     name: String,
//!     #[orm(generated)]
//!     slug: String,
//! }
//!
//! // Example with soft delete support
//! #[derive(Entity, sqlx::FromRow)]
//! #[orm(table = "public.soft_delete", soft_delete = "deleted_at")]
//! struct SoftDelete {
//!     #[orm(pk, generated)]
//!     id: i32,
//!     value: i32,
//!     #[orm(default)]
//!     deleted_at: Option<chrono::NaiveDateTime>,
//! }
//! ```
//!
//! ## Annotations
//!
//! The `#[orm(...)]` attribute supports both struct-level and field-level annotations to
//! control code generation and database mapping.
//!
//! ### Struct-level Annotations
//!
//! - `#[orm(table = "schema.table")]`: Specifies the database table for the entity.
//! - `#[orm(soft_delete = "column_name")]`: Enables soft delete support for the entity. The given column (typically an `Option<chrono::NaiveDateTime>`) will be set to the current timestamp instead of deleting the row. Entities with a non-NULL value in this column are considered deleted and will be excluded from fetch, stream, and update operations.
//!
//! ### Field-level Annotations
//!
//! - `#[orm(pk)]`: Marks the field as a primary key. Multiple fields can be marked as primary keys for composite keys.
//! - `#[orm(generated)]`: Indicates the field is auto-generated by the database (e.g., auto-increment or computed columns). Such fields are excluded from inserts and updates.
//! - `#[orm(deref)]`: Used for optional/reference types (e.g., `Option<T>`, `&str`, etc.), allowing the macro to handle dereferencing when generating queries.
//! - `#[orm(as_ref)]`: Used for optional primitive types (e.g., `Option<i32>`, `Option<bool>`), calling `.as_ref()` instead of `.as_deref()` when generating update queries. This is useful for optional primitive values that don't need dereferencing.
//! - `#[orm(default)]`: Allows the field to use a default value when inserting, by wrapping it in `Defaultable<T>`.
//! - `#[orm(cast = "Type")]`: Casts the field to the specified SQL type in generated queries. This is useful when you want to explicitly cast a column in SQL (e.g., for custom types or to resolve type mismatches).
//!
//! ## Traits Overview
//!
//! ### [`InsertableEntity`]
//! For types that can be inserted into the database. An "Insertable" struct is generated for
//! each entity, containing only the fields that should be provided on insert.
//!
//! Fields annotated with the default annotation are wrapped in [`Defaultable`], indicating if the
//! default value should be used, or the provided one.
//!
//! ### [`FetchableEntity`]
//!
//! For types that can be fetched by primary key(s) from the database. A "Pk" struct is generated
//! for each entity, containing only the primary key fields.
//!
//! > If the entity uses soft delete, fetch operations will return `None` for rows where the soft delete column is set (i.e., not NULL).
//!
//! ### [`StreamableEntity`]
//!
//! For types that can be streamed (selected) from the database. This trait is implemented for
//! the entity struct, allowing you to stream all rows from the table.
//!
//! > If the entity uses soft delete, only rows where the soft delete column is NULL will be streamed.
//!
//! ### [`UpdatableEntity`]
//!
//! For types that can be updated in the database. An "Updatable" struct is generated for each
//! entity, containing the primary key(s) and updatable fields.
//!
//! > Updates will only affect rows that are not soft deleted (i.e., where the soft delete column is NULL).
//!
//! ### [`DeletableEntity`]
//!
//! For types that can be deleted from the database. This trait is implemented for the entity
//! struct, allowing you to delete a row by its primary key(s).
//!
//! > If the entity uses soft delete, calling `delete` will set the soft delete column to the current timestamp instead of removing the row from the database.
//!

pub use futures::Stream;
pub use gremlin_orm_macro::Entity;
use sqlx::PgExecutor;

/// Used for inserting values, use either the default or the provided value
pub enum Defaultable<T> {
    /// Use the default value
    Default,
    /// Use the provided value
    Value(T),
}

/// Trait for types that can be inserted into the database.
/// An "Insertable" struct is generated for each entity, containing only the fields that should be provided on insert.
pub trait InsertableEntity {
    /// The entity type returned after insertion (typically the main entity struct).
    type SourceEntity;

    /// Insert the entity into the database.
    ///
    /// # Arguments
    ///
    /// * `pool` - A reference to a PostgreSQL connection pool.
    ///
    /// # Returns
    ///
    /// A future resolving to either the inserted entity or a SQLx error.
    fn insert<'a>(
        &self,
        executor: impl PgExecutor<'a>,
    ) -> impl Future<Output = Result<Self::SourceEntity, sqlx::Error>>;
}

/// Trait for types that can be fetched by primary key(s) from the database.
/// A "Pk" struct is generated for each entity, containing only the primary key fields.
pub trait FetchableEntity {
    /// The entity type returned after fetching (typically the main entity struct).
    type SourceEntity;

    /// Fetch the entity from the database by its primary key(s).
    ///
    /// # Arguments
    ///
    /// * `pool` - A reference to a PostgreSQL connection pool.
    ///
    /// # Returns
    ///
    /// A future resolving to either `Some(entity)` if found, `None` if not found, or a SQLx error.
    fn fetch<'a>(
        &self,
        executor: impl PgExecutor<'a>,
    ) -> impl Future<Output = Result<Option<Self::SourceEntity>, sqlx::Error>>;
}

/// Trait for types that can be streamed (selected) from the database.
/// This trait is implemented for the entity struct, allowing you to stream all rows from the table.
pub trait StreamableEntity: Sized {
    /// Stream all entities from the database table.
    ///
    /// # Arguments
    ///
    /// * `pool` - A reference to a PostgreSQL connection pool.
    ///
    /// # Returns
    ///
    /// An async stream of results, each being either the entity or a SQLx error.
    fn stream<'a>(
        executor: impl PgExecutor<'a> + 'a,
    ) -> impl Stream<Item = Result<Self, sqlx::Error>>;
}

/// Trait for types that can be updated in the database.
/// An "Updatable" struct is generated for each entity, containing the primary key(s) and updatable fields.
pub trait UpdatableEntity {
    /// The entity type returned after updating (typically the main entity struct).
    type SourceEntity;

    /// Update the entity in the database.
    ///
    /// # Arguments
    ///
    /// * `pool` - A reference to a PostgreSQL connection pool.
    ///
    /// # Returns
    ///
    /// A future resolving to either the updated entity or a SQLx error.
    fn update<'a>(
        &self,
        executor: impl PgExecutor<'a>,
    ) -> impl Future<Output = Result<Self::SourceEntity, sqlx::Error>>;
}

/// Trait for types that can be deleted from the database.
/// This trait is implemented for the entity struct, allowing you to delete a row by its primary key(s).
pub trait DeletableEntity {
    /// Delete the entity from the database by its primary key(s).
    ///
    /// # Arguments
    ///
    /// * `pool` - A reference to a PostgreSQL connection pool.
    ///
    /// # Returns
    ///
    /// A future resolving to `()` if successful, or a SQLx error.
    fn delete<'a>(
        &self,
        executor: impl PgExecutor<'a>,
    ) -> impl Future<Output = Result<(), sqlx::Error>>;
}