1#![allow(unused_imports)]
2use std::{
3 collections::{BTreeMap, HashSet},
4 sync::LazyLock,
5};
6use tank::{
7 Entity, Executor, Passive, expr,
8 stream::{StreamExt, TryStreamExt},
9};
10use time::macros::datetime;
11use tokio::sync::Mutex;
12use uuid::Uuid;
13
14#[derive(Entity, Debug, Clone)]
15#[tank(schema = "testing", name = "user_profiles", primary_key = (id, follower_count))]
17pub struct UserProfile {
18 #[tank(name = "user_id")]
19 pub id: Passive<Uuid>,
20 #[tank(unique, column_type = (mysql = "VARCHAR(128)"))]
21 pub username: String,
22 #[tank(unique, column_type = (mysql = "VARCHAR(128)"))]
23 pub email: String,
24 pub full_name: Option<String>,
25 #[tank(default = "0")]
26 pub follower_count: u32,
27 pub is_active: bool,
28 pub last_login: Option<time::PrimitiveDateTime>,
29 #[cfg(not(feature = "disable-maps"))]
30 pub preferences: Option<BTreeMap<String, String>>,
31}
32static MUTEX: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
33
34pub async fn users<E: Executor>(executor: &mut E) {
35 let _lock = MUTEX.lock().await;
36
37 let result = UserProfile::drop_table(executor, true, false).await;
39 assert!(
40 result.is_ok(),
41 "Failed to UserProfile::drop_table: {:?}",
42 result.unwrap_err()
43 );
44
45 let result = UserProfile::create_table(executor, false, true).await;
47 assert!(
48 result.is_ok(),
49 "Failed to UserProfile::create_table: {:?}",
50 result.unwrap_err()
51 );
52
53 let users_to_create = vec![
55 UserProfile {
56 id: Uuid::parse_str("a1a1a1a1-a1a1-a1a1-a1a1-a1a1a1a1a1a1")
57 .unwrap()
58 .into(),
59 username: "alice".into(),
60 email: "alice@example.com".into(),
61 full_name: Some("Alice Wonderland".into()),
62 follower_count: 56,
63 is_active: true,
64 last_login: Some(datetime!(2025-07-15 10:00:00)),
65 #[cfg(not(feature = "disable-maps"))]
66 preferences: Some(BTreeMap::from_iter([("theme".into(), "dark".into())])),
67 },
68 UserProfile {
69 id: Uuid::parse_str("b2b2b2b2-b2b2-b2b2-b2b2-b2b2b2b2b2b2")
70 .unwrap()
71 .into(),
72 username: "bob".into(),
73 email: "bob@example.com".into(),
74 full_name: Some("Bob Builder".into()),
75 follower_count: 99,
76 is_active: false,
77 last_login: None,
78 #[cfg(not(feature = "disable-maps"))]
79 preferences: Some(BTreeMap::from_iter([("theme".into(), "light".into())])),
80 },
81 UserProfile {
82 id: Uuid::parse_str("c3c3c3c3-c3c3-c3c3-c3c3-c3c3c3c3c3c3")
83 .unwrap()
84 .into(),
85 username: "charlie".into(),
86 email: "charlie@example.com".into(),
87 full_name: None,
88 follower_count: 5000,
89 is_active: true,
90 last_login: Some(datetime!(2025-07-16 11:30:00)),
91 #[cfg(not(feature = "disable-maps"))]
92 preferences: None,
93 },
94 UserProfile {
95 id: Uuid::parse_str("d4d4d4d4-d4d4-d4d4-d4d4-d4d4d4d4d4d4")
96 .unwrap()
97 .into(),
98 username: "dean".into(),
99 email: "dean@example.com".into(),
100 full_name: Some("Dean Martin".into()),
101 follower_count: 15000,
102 is_active: true,
103 last_login: None,
104 #[cfg(not(feature = "disable-maps"))]
105 preferences: Some(BTreeMap::from_iter([(
106 "notifications".into(),
107 "off".into(),
108 )])),
109 },
110 UserProfile {
111 id: Uuid::parse_str("e5e5e5e5-e5e5-e5e5-e5e5-e5e5e5e5e5e5")
112 .unwrap()
113 .into(),
114 username: "eve".into(),
115 email: "eve@example.com".into(),
116 full_name: Some("Eve".into()),
117 follower_count: 1,
118 is_active: false,
119 last_login: Some(datetime!(2024-01-01 00:00:00)),
120 #[cfg(not(feature = "disable-maps"))]
121 preferences: None,
122 },
123 ];
124
125 let result = UserProfile::insert_many(executor, users_to_create.iter()).await;
126 assert!(
127 result.is_ok(),
128 "Failed to insert users: {:?}",
129 result.unwrap_err()
130 );
131 if let Some(affected) = result.unwrap().rows_affected {
132 assert_eq!(affected, 5);
133 }
134
135 let popular_users = UserProfile::find_many(executor, &expr!(follower_count > 1000), None)
137 .try_collect::<Vec<_>>()
138 .await
139 .unwrap();
140 assert_eq!(popular_users.len(), 2);
141
142 let active_users = UserProfile::find_many(executor, &expr!(is_active == true), None)
144 .try_collect::<Vec<_>>()
145 .await
146 .unwrap();
147 assert_eq!(active_users.len(), 3);
148 let active_users = active_users
149 .into_iter()
150 .map(|u| u.username)
151 .collect::<HashSet<_>>();
152 assert_eq!(
153 active_users,
154 HashSet::from_iter(["alice".into(), "charlie".into(), "dean".into()])
155 );
156
157 let mut bob = UserProfile::find_one(executor, &expr!(username == "bob"))
159 .await
160 .expect("Expected query to succeed")
161 .expect("Could not find bob ");
162 bob.is_active = true;
163 bob.full_name = Some("Robert Builder".into());
164 bob.last_login = Some(datetime!(2025-07-17 20:00:00));
165 let result = bob.save(executor).await;
166 assert!(
167 result.is_ok(),
168 "Failed to save Bob: {:?}",
169 result.unwrap_err()
170 );
171 let updated_bob = UserProfile::find_pk(executor, &bob.primary_key())
172 .await
173 .expect("Expected query to succeed")
174 .expect("Could not find bob ");
175 assert_eq!(updated_bob.is_active, true);
176 assert_eq!(updated_bob.full_name, Some("Robert Builder".into()));
177 assert!(updated_bob.last_login.is_some());
178
179 let active_users_after_update =
181 UserProfile::find_many(executor, &expr!(is_active == true), None)
182 .try_collect::<Vec<_>>()
183 .await
184 .unwrap();
185 assert_eq!(active_users_after_update.len(), 4);
186
187 let eve = UserProfile::find_one(executor, &expr!(username == "eve"))
189 .await
190 .expect("Expected query to succeed")
191 .expect("Could not find eve ");
192 let result = eve.delete(executor).await;
193 assert!(
194 result.is_ok(),
195 "Failed to delete Eve: {:?}",
196 result.unwrap_err()
197 );
198 let maybe_eve = UserProfile::find_pk(executor, &eve.primary_key())
199 .await
200 .expect("Expected query to succeed");
201 assert!(maybe_eve.is_none(), "Eve should have been deleted");
202
203 let total_users = UserProfile::find_many(executor, &true, None).count().await;
205 assert_eq!(total_users, 4, "There should be 4 users remaining");
206
207 let result = UserProfile::delete_many(executor, &expr!(last_login == NULL))
209 .await
210 .expect("Expected query to succeed");
211 if let Some(affected) = result.rows_affected {
212 assert_eq!(affected, 1, "Should have removed 1 rows");
213 }
214
215 let final_users = UserProfile::find_many(executor, &true, None)
217 .try_collect::<Vec<_>>()
218 .await
219 .expect("Expected query to succeed");
220 assert_eq!(final_users.len(), 3);
221 let final_usernames = final_users
222 .into_iter()
223 .map(|u| u.username)
224 .collect::<HashSet<_>>();
225 assert_eq!(
226 final_usernames,
227 HashSet::from_iter(["alice".into(), "bob".into(), "charlie".into()])
228 );
229}