gremlin_orm/
lib.rs

1//! # `gremlin-orm`
2//!
3//! This crate provides a lightweight, type-safe ORM for PostgreSQL in Rust, focusing on minimal boilerplate and compile-time query safety.
4//!
5//! ## Example
6//!
7//! ```rust
8//! use gremlin_orm::Entity;
9//!
10//! #[derive(Entity, sqlx::FromRow)]
11//! #[orm(table = "public.artist")]
12//! struct Artist {
13//!     #[orm(pk, generated)]
14//!     id: i32,
15//!     name: String,
16//!     #[orm(generated)]
17//!     slug: String,
18//! }
19//!
20//! // Example with soft delete support
21//! #[derive(Entity, sqlx::FromRow)]
22//! #[orm(table = "public.soft_delete", soft_delete = "deleted_at")]
23//! struct SoftDelete {
24//!     #[orm(pk, generated)]
25//!     id: i32,
26//!     value: i32,
27//!     #[orm(default)]
28//!     deleted_at: Option<chrono::NaiveDateTime>,
29//! }
30//! ```
31//!
32//! ## Annotations
33//!
34//! The `#[orm(...)]` attribute supports both struct-level and field-level annotations to
35//! control code generation and database mapping.
36//!
37//! ### Struct-level Annotations
38//!
39//! - `#[orm(table = "schema.table")]`: Specifies the database table for the entity.
40//! - `#[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.
41//!
42//! ### Field-level Annotations
43//!
44//! - `#[orm(pk)]`: Marks the field as a primary key. Multiple fields can be marked as primary keys for composite keys.
45//! - `#[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.
46//! - `#[orm(deref)]`: Used for optional/reference types (e.g., `Option<T>`, `&str`, etc.), allowing the macro to handle dereferencing when generating queries.
47//! - `#[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.
48//! - `#[orm(default)]`: Allows the field to use a default value when inserting, by wrapping it in `Defaultable<T>`.
49//! - `#[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).
50//!
51//! ## Traits Overview
52//!
53//! ### [`InsertableEntity`]
54//! For types that can be inserted into the database. An "Insertable" struct is generated for
55//! each entity, containing only the fields that should be provided on insert.
56//!
57//! Fields annotated with the default annotation are wrapped in [`Defaultable`], indicating if the
58//! default value should be used, or the provided one.
59//!
60//! ### [`FetchableEntity`]
61//!
62//! For types that can be fetched by primary key(s) from the database. A "Pk" struct is generated
63//! for each entity, containing only the primary key fields.
64//!
65//! > If the entity uses soft delete, fetch operations will return `None` for rows where the soft delete column is set (i.e., not NULL).
66//!
67//! ### [`StreamableEntity`]
68//!
69//! For types that can be streamed (selected) from the database. This trait is implemented for
70//! the entity struct, allowing you to stream all rows from the table.
71//!
72//! > If the entity uses soft delete, only rows where the soft delete column is NULL will be streamed.
73//!
74//! ### [`UpdatableEntity`]
75//!
76//! For types that can be updated in the database. An "Updatable" struct is generated for each
77//! entity, containing the primary key(s) and updatable fields.
78//!
79//! > Updates will only affect rows that are not soft deleted (i.e., where the soft delete column is NULL).
80//!
81//! ### [`DeletableEntity`]
82//!
83//! For types that can be deleted from the database. This trait is implemented for the entity
84//! struct, allowing you to delete a row by its primary key(s).
85//!
86//! > 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.
87//!
88
89pub use futures::Stream;
90pub use gremlin_orm_macro::Entity;
91use sqlx::PgExecutor;
92
93/// Used for inserting values, use either the default or the provided value
94pub enum Defaultable<T> {
95    /// Use the default value
96    Default,
97    /// Use the provided value
98    Value(T),
99}
100
101/// Trait for types that can be inserted into the database.
102/// An "Insertable" struct is generated for each entity, containing only the fields that should be provided on insert.
103pub trait InsertableEntity {
104    /// The entity type returned after insertion (typically the main entity struct).
105    type SourceEntity;
106
107    /// Insert the entity into the database.
108    ///
109    /// # Arguments
110    ///
111    /// * `pool` - A reference to a PostgreSQL connection pool.
112    ///
113    /// # Returns
114    ///
115    /// A future resolving to either the inserted entity or a SQLx error.
116    fn insert<'a>(
117        &self,
118        executor: impl PgExecutor<'a>,
119    ) -> impl Future<Output = Result<Self::SourceEntity, sqlx::Error>>;
120}
121
122/// Trait for types that can be fetched by primary key(s) from the database.
123/// A "Pk" struct is generated for each entity, containing only the primary key fields.
124pub trait FetchableEntity {
125    /// The entity type returned after fetching (typically the main entity struct).
126    type SourceEntity;
127
128    /// Fetch the entity from the database by its primary key(s).
129    ///
130    /// # Arguments
131    ///
132    /// * `pool` - A reference to a PostgreSQL connection pool.
133    ///
134    /// # Returns
135    ///
136    /// A future resolving to either `Some(entity)` if found, `None` if not found, or a SQLx error.
137    fn fetch<'a>(
138        &self,
139        executor: impl PgExecutor<'a>,
140    ) -> impl Future<Output = Result<Option<Self::SourceEntity>, sqlx::Error>>;
141}
142
143/// Trait for types that can be streamed (selected) from the database.
144/// This trait is implemented for the entity struct, allowing you to stream all rows from the table.
145pub trait StreamableEntity: Sized {
146    /// Stream all entities from the database table.
147    ///
148    /// # Arguments
149    ///
150    /// * `pool` - A reference to a PostgreSQL connection pool.
151    ///
152    /// # Returns
153    ///
154    /// An async stream of results, each being either the entity or a SQLx error.
155    fn stream<'a>(
156        executor: impl PgExecutor<'a> + 'a,
157    ) -> impl Stream<Item = Result<Self, sqlx::Error>>;
158}
159
160/// Trait for types that can be updated in the database.
161/// An "Updatable" struct is generated for each entity, containing the primary key(s) and updatable fields.
162pub trait UpdatableEntity {
163    /// The entity type returned after updating (typically the main entity struct).
164    type SourceEntity;
165
166    /// Update the entity in the database.
167    ///
168    /// # Arguments
169    ///
170    /// * `pool` - A reference to a PostgreSQL connection pool.
171    ///
172    /// # Returns
173    ///
174    /// A future resolving to either the updated entity or a SQLx error.
175    fn update<'a>(
176        &self,
177        executor: impl PgExecutor<'a>,
178    ) -> impl Future<Output = Result<Self::SourceEntity, sqlx::Error>>;
179}
180
181/// Trait for types that can be deleted from the database.
182/// This trait is implemented for the entity struct, allowing you to delete a row by its primary key(s).
183pub trait DeletableEntity {
184    /// Delete the entity from the database by its primary key(s).
185    ///
186    /// # Arguments
187    ///
188    /// * `pool` - A reference to a PostgreSQL connection pool.
189    ///
190    /// # Returns
191    ///
192    /// A future resolving to `()` if successful, or a SQLx error.
193    fn delete<'a>(
194        &self,
195        executor: impl PgExecutor<'a>,
196    ) -> impl Future<Output = Result<(), sqlx::Error>>;
197}