sqlorm_core/
traits.rs

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