1#![allow(unused_variables)]
2use anyhow::anyhow;
3use std::{collections::HashMap, str::FromStr, sync::LazyLock};
4use tank::{AsValue, Entity, Result, Value, expr};
5use tokio::sync::Mutex;
6use uuid::Uuid;
7
8static MUTEX: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
9
10#[derive(Default, PartialEq, Clone, Debug)]
11pub struct Notes(pub String); pub struct NotesWrap(pub Notes); impl AsValue for NotesWrap {
15 fn as_empty_value() -> Value {
16 Value::Varchar(None)
17 }
18 fn as_value(self) -> Value {
19 Value::Varchar(Some(self.0.0.into()))
20 }
21 fn try_from_value(value: Value) -> Result<Self> {
22 match value.try_as(&Value::Varchar(None)) {
23 Ok(Value::Varchar(Some(s))) => Ok(NotesWrap(Notes(s.to_string()))),
24 _ => Err(anyhow!("Expected Varchar for Notes")),
25 }
26 }
27}
28impl From<Notes> for NotesWrap {
29 fn from(v: Notes) -> Self {
30 NotesWrap(v)
31 }
32}
33impl From<NotesWrap> for Notes {
34 fn from(v: NotesWrap) -> Self {
35 v.0
36 }
37}
38
39#[derive(Default, Entity, PartialEq, Debug)]
40#[tank(
41 schema = "army",
42 name = "deployments",
43 primary_key = (Self::unit_id, Self::region),
44)]
45struct EntityExample {
46 unit_id: Uuid,
47 #[tank(clustering_key)]
48 region: String,
49 #[tank(name = "callsign")]
50 callsign: String,
51 casualties: i32,
52 #[tank(conversion_type = NotesWrap)]
53 metadata: Notes,
54 #[tank(ignore)]
55 transient_cache: HashMap<String, String>,
56}
57
58pub async fn cheat_sheet(mut connection: &mut impl tank::Connection) -> Result<()> {
59 let _lock = MUTEX.lock().await;
60
61 {
62 EntityExample::drop_table(&mut connection, true, false).await?;
63 EntityExample::create_table(&mut connection, true, true).await?;
64 }
65
66 let entity = EntityExample {
67 unit_id: Uuid::new_v4(),
68 region: "North".into(),
69 callsign: "Alpha".into(),
70 casualties: 0,
71 metadata: Notes("mission".into()),
72 transient_cache: HashMap::new(),
73 };
74
75 {
76 use tank::{Entity, Transaction};
77
78 let mut tx = connection.begin().await?;
79 EntityExample::insert_one(&mut tx, &entity).await?;
80 entity.delete(&mut tx).await?;
81 tx.commit().await?;
82 }
83
84 let entity2 = EntityExample {
85 unit_id: Uuid::new_v4(),
86 region: "South".into(),
87 callsign: "Bravo-2".into(),
88 casualties: 3,
89 metadata: Notes("mission-2".into()),
90 transient_cache: HashMap::new(),
91 };
92 let entity3 = EntityExample {
93 unit_id: Uuid::new_v4(),
94 region: "East".into(),
95 callsign: "Charlie-3".into(),
96 casualties: 5,
97 metadata: Notes("mission-3".into()),
98 transient_cache: HashMap::new(),
99 };
100
101 {
102 EntityExample::insert_one(&mut connection, &entity).await?;
103 EntityExample::insert_many(&mut connection, [&entity2]).await?;
104 connection.append([&entity3]).await?;
105 }
106
107 {
108 entity.save(&mut connection).await?;
109 entity.delete(&mut connection).await?;
110 }
111
112 {
113 use std::pin::pin;
114 use tank::{Entity, expr, stream::TryStreamExt};
115
116 let entity = EntityExample::find_one(&mut connection, entity.primary_key_expr()).await?;
117 {
118 let uid = entity2.unit_id;
119 let mut stream = pin!(EntityExample::find_many(
120 &mut connection,
121 expr!(EntityExample::unit_id == #uid),
122 Some(100),
123 ));
124 while let Some(entity) = stream.try_next().await? {
125 println!("{}", entity.callsign);
126 }
127 }
128 let uid = Uuid::from_str("94f0cbcc-1fce-454e-a6e4-4e3587741808")?;
129 let entities: Vec<EntityExample> =
130 EntityExample::find_many(&mut connection, expr!(EntityExample::unit_id == #uid), None)
131 .try_collect()
132 .await?;
133 }
134
135 {
136 use tank::{Entity, expr};
137
138 let uid = entity2.unit_id;
139 EntityExample::delete_many(&mut connection, expr!(EntityExample::unit_id == #uid)).await?;
140
141 let uid = entity3.unit_id;
142 EntityExample::delete_many(&mut connection, expr!(EntityExample::unit_id == #uid)).await?;
143 }
144
145 {
146 expr!(EntityExample::casualties == 0);
147 expr!(EntityExample::casualties >= 10);
148 expr!(EntityExample::region == "North" || EntityExample::region == "South");
149 expr!(EntityExample::callsign == "Alpha%" as LIKE);
150 expr!(EntityExample::callsign != "Alpha%" as LIKE);
151 expr!(EntityExample::casualties > ?);
152 let uid = Uuid::new_v4();
153 expr!(EntityExample::unit_id == #uid);
154 }
155
156 {
157 use tank::{Entity, expr, stream::TryStreamExt};
158
159 let mut query = EntityExample::prepare_find(
160 &mut connection,
161 expr!(EntityExample::unit_id == ?),
162 Some(50),
163 )
164 .await?;
165 query.bind(Uuid::from_str("2f4f97da-0278-4c99-bc22-2b3986aeee85")?)?;
166 let entities = connection
167 .fetch(&mut query)
168 .map_ok(|row| EntityExample::from_row(row).unwrap())
169 .try_collect::<Vec<EntityExample>>()
170 .await?;
171 query.clear_bindings()?;
172 query.bind(Uuid::from_str("962f2c1c-7caa-468d-a387-53ed9860c4bf")?)?;
173 }
174
175 {
176 use tank::{QueryBuilder, cols, expr, stream::TryStreamExt};
177
178 let uid = entity.unit_id;
179 let results = connection
180 .fetch(
181 QueryBuilder::new()
182 .select(cols!(EntityExample::callsign, EntityExample::casualties))
184 .from(EntityExample::table())
185 .where_expr(expr!(EntityExample::unit_id == #uid))
186 .order_by(cols!(EntityExample::region ASC))
187 .limit(Some(50))
188 .build(&connection.driver()),
189 )
190 .map_ok(|row| EntityExample::from_row(row).unwrap())
191 .try_collect::<Vec<_>>()
192 .await?;
193 }
194
195 #[cfg(not(feature = "disable-joins"))]
196 {
197 use crate::{Author, AuthorColumnTrait, Book, BookColumnTrait};
198 use tank::{
199 Entity, QueryBuilder, cols, expr, join, stream::StreamExt, stream::TryStreamExt,
200 };
201
202 #[derive(Entity, Debug)]
203 struct BookWithAuthor {
204 title: String,
205 author: String,
206 }
207
208 let rows: Vec<BookWithAuthor> = connection
209 .fetch(
210 QueryBuilder::new()
211 .select(cols!(Book::title, Author::name as author))
212 .from(join!(Book JOIN Author ON Book::author == Author::id))
213 .where_expr(expr!(Book::year > 2000))
214 .order_by(cols!(Book::title ASC))
215 .build(&connection.driver()),
216 )
217 .map_ok(BookWithAuthor::from_row)
218 .map(Result::flatten)
219 .try_collect()
220 .await?;
221
222 let rows: Vec<BookWithAuthor> = connection
223 .fetch(
224 QueryBuilder::new()
225 .select(cols!(B.title, A.name as author))
226 .from(join!(Book B LEFT JOIN Author A ON B.author == A.author_id))
227 .where_expr(true)
228 .build(&connection.driver()),
229 )
230 .map_ok(BookWithAuthor::from_row)
231 .map(Result::flatten)
232 .try_collect()
233 .await?;
234
235 let dataset = join!(
236 Book B
237 LEFT JOIN Author A1 ON B.author == A1.author_id
238 LEFT JOIN Author A2 ON B.co_author == A2.author_id
239 );
240 let rows = connection
241 .fetch(
242 QueryBuilder::new()
243 .select(cols!(B.title, A1.name as author, A2.name as co_author))
244 .from(dataset)
245 .where_expr(true)
246 .build(&connection.driver()),
247 )
248 .try_collect::<Vec<_>>()
249 .await?;
250 }
251
252 Ok(())
253}