1use crate::error::OrmResult;
2use crate::query::QueryBuilder;
3use async_trait::async_trait;
4use sqlx::{PgPool, Row};
5
6#[async_trait]
9pub trait Model: Sized + Send + Sync + Unpin + 'static {
10 fn table_name() -> &'static str;
12
13 fn primary_key() -> &'static str {
15 "id"
16 }
17
18 fn columns() -> &'static [&'static str];
20
21 fn query() -> QueryBuilder<Self> {
23 QueryBuilder::new(Self::table_name(), Self::primary_key())
24 }
25
26 async fn find(id: i64, pool: &PgPool) -> OrmResult<Option<Self>>
28 where
29 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
30 {
31 let sql = format!(
32 "SELECT * FROM \"{}\" WHERE \"{}\" = $1",
33 Self::table_name(),
34 Self::primary_key(),
35 );
36 let row = sqlx::query_as::<_, Self>(&sql)
37 .bind(id)
38 .fetch_optional(pool)
39 .await
40 .map_err(crate::error::OrmError::from_sqlx)?;
41 Ok(row)
42 }
43
44 async fn find_or_fail(id: i64, pool: &PgPool) -> OrmResult<Self>
46 where
47 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
48 {
49 Self::find(id, pool)
50 .await?
51 .ok_or(crate::error::OrmError::NotFound)
52 }
53
54 async fn find_many(ids: &[i64], pool: &PgPool) -> OrmResult<Vec<Self>>
56 where
57 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
58 {
59 if ids.is_empty() {
60 return Ok(vec![]);
61 }
62 let placeholders: Vec<String> = (1..=ids.len()).map(|i| format!("${}", i)).collect();
63 let sql = format!(
64 "SELECT * FROM \"{}\" WHERE \"{}\" IN ({})",
65 Self::table_name(),
66 Self::primary_key(),
67 placeholders.join(", "),
68 );
69 let mut q = sqlx::query_as::<_, Self>(&sql);
70 for id in ids {
71 q = q.bind(id);
72 }
73 let rows = q
74 .fetch_all(pool)
75 .await
76 .map_err(crate::error::OrmError::from_sqlx)?;
77 Ok(rows)
78 }
79
80 async fn all(pool: &PgPool) -> OrmResult<Vec<Self>>
82 where
83 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
84 {
85 let sql = format!("SELECT * FROM \"{}\"", Self::table_name());
86 let rows = sqlx::query_as::<_, Self>(&sql)
87 .fetch_all(pool)
88 .await
89 .map_err(crate::error::OrmError::from_sqlx)?;
90 Ok(rows)
91 }
92
93 async fn first(pool: &PgPool) -> OrmResult<Option<Self>>
95 where
96 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
97 {
98 let sql = format!(
99 "SELECT * FROM \"{}\" ORDER BY \"{}\" ASC LIMIT 1",
100 Self::table_name(),
101 Self::primary_key(),
102 );
103 let row = sqlx::query_as::<_, Self>(&sql)
104 .fetch_optional(pool)
105 .await
106 .map_err(crate::error::OrmError::from_sqlx)?;
107 Ok(row)
108 }
109
110 async fn last(pool: &PgPool) -> OrmResult<Option<Self>>
112 where
113 Self: for<'r> sqlx::FromRow<'r, sqlx::postgres::PgRow>,
114 {
115 let sql = format!(
116 "SELECT * FROM \"{}\" ORDER BY \"{}\" DESC LIMIT 1",
117 Self::table_name(),
118 Self::primary_key(),
119 );
120 let row = sqlx::query_as::<_, Self>(&sql)
121 .fetch_optional(pool)
122 .await
123 .map_err(crate::error::OrmError::from_sqlx)?;
124 Ok(row)
125 }
126
127 async fn count(pool: &PgPool) -> OrmResult<i64> {
129 let sql = format!("SELECT COUNT(*) FROM \"{}\"", Self::table_name());
130 let row: (i64,) = sqlx::query_as(&sql)
131 .fetch_one(pool)
132 .await
133 .map_err(crate::error::OrmError::from_sqlx)?;
134 Ok(row.0)
135 }
136
137 async fn any(pool: &PgPool) -> OrmResult<bool> {
139 Ok(Self::count(pool).await? > 0)
140 }
141
142 async fn exists(id: i64, pool: &PgPool) -> OrmResult<bool> {
144 let sql = format!(
145 "SELECT EXISTS(SELECT 1 FROM \"{}\" WHERE \"{}\" = $1)",
146 Self::table_name(),
147 Self::primary_key(),
148 );
149 let row: (bool,) = sqlx::query_as(&sql)
150 .bind(id)
151 .fetch_one(pool)
152 .await
153 .map_err(crate::error::OrmError::from_sqlx)?;
154 Ok(row.0)
155 }
156}