Skip to main content

tank_tests/
cheat_sheet.rs

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); // Third party type
12pub struct NotesWrap(pub Notes); // Local wrapper
13
14impl 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                    // Selecting fewer columns requires the entity to have the Default trait
183                    .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}