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