sqlorm_core/
traits.rs

1use crate::Driver;
2use crate::Row;
3use crate::TableInfo;
4use async_trait::async_trait;
5use sqlx::Acquire;
6
7/// Describes a database table and its metadata used by the query builder.
8///
9/// Implement this trait for your entity types to enable type-safe query building.
10/// It provides static metadata such as table name, primary key, and available columns.
11pub trait Table {
12    /// The table name in the database.
13    const TABLE_NAME: &'static str;
14    /// The primary key column name.
15    const PK: &'static str;
16    /// The list of selectable columns for this table.
17    const COLUMNS: &'static [&'static str];
18    const SQL_NAME: &'static str;
19    const ALIASED_SQL_NAME: &'static str;
20
21    /// Returns a TableInfo instance used by the query builder.
22    fn table_info() -> TableInfo;
23}
24
25/// Constructs a value from a database row where columns were projected with aliases.
26///
27/// Implementations should read values from row using the composed alias+column format
28/// produced by the query builder's projections.
29pub trait FromAliasedRow {
30    /// Builds `Self` from an aliased row.
31    fn from_aliased_row(row: &Row) -> sqlx::Result<Self>
32    where
33        Self: Sized + Default;
34}
35
36/// Executes a built query and returns typed results.
37///
38/// This trait is implemented for the query builder type, allowing you to fetch typed
39/// rows directly into your domain structs that implement `sqlx::FromRow`.
40///
41/// # Examples
42///
43/// PostgreSQL
44///
45/// ```ignore
46/// use sqlorm_core::{qb::{QB, Column}, TableInfo, GenericExecutor, Pool};
47/// use std::marker::PhantomData;
48///
49/// # async fn run(pool: &Pool) -> sqlx::Result<()> {
50/// let base = TableInfo {
51///     name: "users",
52///     alias: "u".to_string(),
53///     columns: vec!["id", "name"],
54/// };
55///
56/// let qb1 = QB::<()>::new(base)
57///     .select::<(i32, String)>(vec!["id", "name"])
58///     .filter(Column::<i32> {
59///         name: "id",
60///         table_alias: "u",
61///         aliased_name: "u__id",
62///         _marker: PhantomData,
63///     }.eq(1));
64///
65/// let one: (i32, String) = qb1.fetch_one_as(pool).await?;
66///
67/// let qb2 = QB::<()>::new(TableInfo {
68///     name: "users",
69///     alias: "u".to_string(),
70///     columns: vec!["id", "name"],
71/// })
72/// .select::<(i32, String)>(vec!["id", "name"])
73/// .filter(Column::<i32> {
74///     name: "id",
75///     table_alias: "u",
76///     aliased_name: "u__id",
77///     _marker: PhantomData,
78/// }.gt(0));
79///
80/// let many: Vec<(i32, String)> = qb2.fetch_all_as(pool).await?;
81/// # Ok(())
82/// # }
83#[async_trait]
84pub trait GenericExecutor<T> {
85    /// Executes the query and returns a single row mapped as `T`.
86    async fn fetch_one_as<'a, A: Send + Acquire<'a, Database = Driver>>(
87        self,
88        pool: A,
89    ) -> sqlx::Result<T>;
90    /// Executes the query and returns all rows mapped as `T`.
91    async fn fetch_all_as<'a, A: Send + Acquire<'a, Database = Driver>>(
92        self,
93        pool: A,
94    ) -> sqlx::Result<Vec<T>>;
95}
96
97#[async_trait]
98pub trait StatementExecutor<T: Table> {
99    async fn execute<'a, E>(self, acquirer: E) -> sqlx::Result<T>
100    where
101        E: Send + crate::sqlx::Acquire<'a, Database = Driver>;
102}