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}