1use torm::*;
12
13const PG_HOST: &str = "localhost";
14const PG_PORT: u16 = 5432;
15const PG_DB: &str = "tormdb";
16const PG_USER: &str = "odoo";
17const PG_PASS: &str = "odoo";
18
19#[tokio::main]
20async fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
21 println!("🐘 TORM - Tokio ORM PostgreSQL Demo\n");
22
23 println!("📡 PostgreSQL connection example");
25 println!("================================");
26 demonstrate_database_connection().await?;
27 println!();
28
29 println!("🗄️ GORM-style model CRUD");
31 println!("================================");
32 demonstrate_crud().await?;
33 println!();
34
35 println!("🔒 PostgreSQL transactions");
37 println!("================================");
38 demonstrate_transactions().await?;
39 println!();
40
41 println!("🔑 Simplified UUID generation");
43 println!("================================");
44 demonstrate_simplified_uuid()?;
45 println!();
46
47 println!("⚠️ Simplified error handling");
49 println!("================================");
50 demonstrate_simplified_error()?;
51 println!();
52
53 println!("💾 Simplified LRU cache");
55 println!("================================");
56 demonstrate_simplified_cache()?;
57 println!();
58
59 println!("🏊 Simple connection pool");
61 println!("================================");
62 demonstrate_connection_pool().await?;
63 println!();
64
65 println!("🔨 Query builder example");
67 println!("================================");
68 demonstrate_query_builder();
69 println!();
70
71 println!("🎉 All demos completed successfully!");
72 println!();
73
74 Ok(())
75}
76
77async fn demonstrate_database_connection() -> std::result::Result<(), Box<dyn std::error::Error>> {
78 println!("PostgreSQL connection (native wire protocol):");
79 let dsn = Dsn::new(DBDriver::PostgreSQL, PG_DB)
80 .with_host(PG_HOST)
81 .with_port(PG_PORT)
82 .with_username(PG_USER)
83 .with_password(PG_PASS);
84 println!(" DSN: {}", dsn.build());
85
86 let db = Database::postgresql(PG_HOST, PG_PORT, PG_DB, PG_USER, PG_PASS).await?;
88 println!(" ✅ Connected to PostgreSQL (native wire protocol)");
89 println!(" DB type: {:?}", db.db_type());
90 println!(" Connected: {}", db.is_connected());
91 db.ping().await?;
92 println!(" ✅ Ping successful");
93 db.close().await?;
94
95 println!();
96 println!("Connection via ConnectionFactory:");
97 let config = ConnectionConfig::postgresql(PG_HOST, PG_PORT, PG_DB, PG_USER, PG_PASS)
98 .with_timeout(std::time::Duration::from_secs(30))
99 .with_max_connections(10);
100 let conn = ConnectionFactory::create_connection(config.clone()).await?;
101 println!(" ✅ Connection created (factory)");
102 println!(" DB type: {:?}", conn.db_type());
103 conn.close().await?;
104
105 println!();
106 println!("Direct PostgresConnection:");
107 let pg = PostgresConnection::new(&config).await?;
108 println!(" ✅ PostgresConnection created");
109 println!(" Connected: {}", pg.is_connected());
110 pg.close().await?;
111
112 Ok(())
113}
114
115async fn demonstrate_crud() -> std::result::Result<(), Box<dyn std::error::Error>> {
116 println!("GORM-style model CRUD (create / first / find / update / delete):");
117 let db = Database::postgresql(PG_HOST, PG_PORT, PG_DB, PG_USER, PG_PASS).await?;
118
119 db.execute("DROP TABLE IF EXISTS users", &[]).await?;
121 db.execute(
122 "CREATE TABLE users (
123 id TEXT PRIMARY KEY,
124 name TEXT NOT NULL,
125 email TEXT,
126 age INTEGER,
127 status TEXT,
128 created_at TIMESTAMPTZ,
129 updated_at TIMESTAMPTZ
130 )",
131 &[],
132 )
133 .await?;
134 println!(" ✅ Schema ready (users table recreated)");
135
136 let mut alice = User::new("Alice", "alice@example.com").with_age(25);
138 db.create(&mut alice).await?;
139 println!(
140 " ✅ Created: id={} name={} (created_at: {:?})",
141 alice.id,
142 alice.name,
143 alice.created_at()
144 );
145
146 let mut bob = User::new("Bob", "bob@example.com").with_age(30);
147 db.create(&mut bob).await?;
148 println!(" ✅ Created: id={} name={}", bob.id, bob.name);
149
150 let found: Option<User> = db.first(&alice.id).await?;
152 match &found {
153 Some(u) => println!(
154 " ✅ First: id={} name={} age={:?} status={}",
155 u.id, u.name, u.age, u.status
156 ),
157 None => println!(" ❌ First: not found"),
158 }
159
160 let users: Vec<User> = db.all().await?;
162 println!(" ✅ Find: {} user(s)", users.len());
163 for u in &users {
164 println!(
165 " - {} <{}> age={:?} status={}",
166 u.name, u.email, u.age, u.status
167 );
168 }
169
170 db.update(&mut alice, &[("age", 29)]).await?;
172 let updated: User = db.first(&alice.id).await?.expect("alice exists");
173 println!(" ✅ Updated: {} age now {:?}", updated.name, updated.age);
174
175 db.delete(&mut alice).await?;
177 let gone: Option<User> = db.first(&alice.id).await?;
178 println!(
179 " ✅ Deleted: {} exists after delete = {}",
180 alice.name,
181 gone.is_some()
182 );
183
184 db.close().await?;
185 println!(" ✅ Database closed");
186
187 Ok(())
188}
189
190async fn demonstrate_transactions() -> std::result::Result<(), Box<dyn std::error::Error>> {
191 println!("PostgreSQL transactions (BEGIN / COMMIT / ROLLBACK):");
192 let db = Database::postgresql(PG_HOST, PG_PORT, PG_DB, PG_USER, PG_PASS).await?;
193
194 let mut tx = db.begin_transaction().await?;
196 tx.execute(
197 "INSERT INTO users (id, name, age) VALUES ($1, $2, $3)",
198 &[
199 SimpleUuid::new_v4().to_string().into(),
200 "Dave".into(),
201 40.into(),
202 ],
203 )
204 .await?;
205 tx.execute(
206 "INSERT INTO users (id, name, age) VALUES ($1, $2, $3)",
207 &[
208 SimpleUuid::new_v4().to_string().into(),
209 "Frank".into(),
210 35.into(),
211 ],
212 )
213 .await?;
214 tx.commit().await?;
215 println!(" ✅ Transaction committed (2 users)");
216
217 let mut tx = db.begin_transaction().await?;
219 tx.execute(
220 "INSERT INTO users (id, name, age) VALUES ($1, $2, $3)",
221 &[
222 SimpleUuid::new_v4().to_string().into(),
223 "Eve".into(),
224 45.into(),
225 ],
226 )
227 .await?;
228 tx.rollback().await?;
229 println!(" ✅ Transaction rolled back (Eve not saved)");
230
231 let result = db.query("SELECT COUNT(*) AS count FROM users", &[]).await?;
232 println!(" ✅ Final user count: {:?}", result.rows[0].get("count"));
233
234 db.close().await?;
235 Ok(())
236}
237
238fn demonstrate_simplified_uuid() -> std::result::Result<(), Box<dyn std::error::Error>> {
239 println!("Generating UUIDs:");
240
241 let uuid1 = SimpleUuid::new_v4();
243 let uuid2 = SimpleUuid::new_v4();
244 let uuid3 = SimpleUuid::new_v4();
245
246 println!(" UUID 1: {}", uuid1);
247 println!(" UUID 2: {}", uuid2);
248 println!(" UUID 3: {}", uuid3);
249 println!(
250 " All unique: {}",
251 uuid1 != uuid2 && uuid2 != uuid3 && uuid1 != uuid3
252 );
253
254 println!();
255 println!("ID Generator:");
256 let generator = IdGenerator::new();
257 let id1 = generator.generate();
258 let id2 = generator.generate();
259
260 println!(" ID 1: {}", id1);
261 println!(" ID 2: {}", id2);
262 println!(
263 " ID 3: {}",
264 generator.with_prefix("user_").generate()
265 );
266
267 println!();
268 println!("Simple IDs:");
269 let simple_gen = IdGenerator::new().with_simple_id();
270 println!(" Simple ID: {}", simple_gen.generate());
271 println!(
272 " Prefixed: {}",
273 simple_gen.with_prefix("order_").generate()
274 );
275
276 Ok(())
277}
278
279fn demonstrate_simplified_error() -> std::result::Result<(), Box<dyn std::error::Error>> {
280 println!("Error handling without thiserror:");
281
282 let not_found = SimpleError::NotFound;
284 println!(" NotFound: {}", not_found);
285
286 let custom = SimpleError::custom("Something went wrong");
287 println!(" Custom: {}", custom);
288
289 let invalid_query = SimpleError::invalid_query("Invalid WHERE clause");
290 println!(" InvalidQuery: {}", invalid_query);
291
292 let connection_error = SimpleError::connection_error("Could not connect to database");
293 println!(" ConnectionError: {}", connection_error);
294
295 println!();
296 println!("Using SimpleResult:");
297 let success: SimpleResult<i32> = Ok(42);
298 println!(" Success: {:?}", success);
299
300 let failure: SimpleResult<i32> = Err(SimpleError::NotFound);
301 println!(" Failure: {:?}", failure);
302
303 Ok(())
304}
305
306fn demonstrate_simplified_cache() -> std::result::Result<(), Box<dyn std::error::Error>> {
307 println!("LRU cache:");
308
309 let mut cache: SimpleLruCache<&str, &str> = SimpleLruCache::new(3);
310
311 cache.put("key1", "value1");
313 cache.put("key2", "value2");
314 cache.put("key3", "value3");
315
316 println!(" Initial size: {}", cache.len());
317 println!(" key1: {:?}", cache.get(&"key1"));
318 println!(" key2: {:?}", cache.get(&"key2"));
319 println!(" key3: {:?}", cache.get(&"key3"));
320
321 println!();
323 println!(" Adding key4 (should evict oldest):");
324 cache.put("key4", "value4");
325 println!(" key1: {:?}", cache.get(&"key1")); println!(" key4: {:?}", cache.get(&"key4")); println!();
330 println!(" Current capacity: {}", cache.capacity());
331 println!(" Current size: {}", cache.len());
332
333 cache.resize(2);
335 println!(" After resize to 2:");
336 println!(" New size: {}", cache.len());
337
338 cache.clear();
340 println!(" After clear: {}", cache.is_empty());
341
342 Ok(())
343}
344
345async fn demonstrate_connection_pool() -> std::result::Result<(), Box<dyn std::error::Error>> {
346 println!("Simple connection pool implementation:");
347
348 let connections = vec![1, 2, 3, 4, 5];
350 let pool = SimplePool::new(connections);
351 let status = pool.status();
352
353 println!(" Total connections: {}", status.total_connections);
354 println!(" Idle connections: {}", status.idle_connections);
355 println!(" Active connections: {}", status.active_connections);
356 println!(
357 " Utilization: {:.1}%",
358 status.utilization_rate() * 100.0
359 );
360
361 println!();
363 println!(" Getting a connection from pool:");
364 match pool.get().await {
365 Ok(conn) => {
366 println!(" Got: {}", conn);
367 let status = pool.status();
368 println!(
369 " After get - idle: {}, active: {}",
370 status.idle_connections, status.active_connections
371 );
372 pool.put(conn);
373 let status = pool.status();
374 println!(
375 " After put - idle: {}, active: {}",
376 status.idle_connections, status.active_connections
377 );
378 }
379 Err(e) => println!(" Error: {}", e),
380 }
381
382 println!();
383 println!("Pool features:");
384 println!(" • Connection reuse");
385 println!(" • Timeout handling");
386 println!(" • No external deadpool dependency");
387
388 Ok(())
389}
390
391fn demonstrate_query_builder() {
392 println!("Query builder examples:");
393 println!(" (generates SQL text; note PostgreSQL executes with $1/$2-style parameters, see CRUD above)");
394
395 let (sql, bindings) = QueryBuilder::new(User::table_name())
397 .where_eq("email", "john@example.com")
398 .limit(1)
399 .build();
400 println!(" Basic query:");
401 println!(" SQL: {}", sql);
402 println!(" Bindings: {:?}", bindings);
403
404 let (sql, bindings) = QueryBuilder::new(User::table_name())
406 .where_eq("status", "active")
407 .where_gt("age", 18)
408 .where_like("name", "John%")
409 .order_by("created_at", "DESC")
410 .limit(10)
411 .build();
412 println!();
413 println!(" Complex query:");
414 println!(" SQL: {}", sql);
415 println!(" Bindings: {:?}", bindings);
416
417 let (sql, bindings) = QueryBuilder::new(User::table_name())
419 .where_in("id", vec![1, 2, 3])
420 .build();
421 println!();
422 println!(" IN query:");
423 println!(" SQL: {}", sql);
424 println!(" Bindings: {:?}", bindings);
425
426 let (sql, bindings) = QueryBuilder::new(User::table_name())
428 .where_between("age", 18, 65)
429 .build();
430 println!();
431 println!(" BETWEEN query:");
432 println!(" SQL: {}", sql);
433 println!(" Bindings: {:?}", bindings);
434}
435
436#[derive(Debug, Clone, Model)]
438#[model(table_name = "users")]
439pub struct User {
440 pub id: String,
441 pub name: String,
442 pub email: String,
443 pub age: Option<i32>,
444 pub status: String,
445 pub timestamps: torm::orm::model::Timestamps,
446}
447
448impl User {
449 pub fn new(name: &str, email: &str) -> Self {
450 let generator = IdGenerator::new().with_prefix("user_");
451 Self {
452 id: generator.generate(),
453 name: name.to_string(),
454 email: email.to_string(),
455 age: None,
456 status: "active".to_string(),
457 timestamps: torm::orm::model::Timestamps::new(),
458 }
459 }
460
461 pub fn with_age(mut self, age: i32) -> Self {
462 self.age = Some(age);
463 self
464 }
465
466 pub fn with_status(mut self, status: &str) -> Self {
467 self.status = status.to_string();
468 self
469 }
470}
471