async_concurrency/
async_concurrency.rs1use std::collections::HashMap;
11use std::sync::Arc;
12use torm::{
13 AsyncStorageEngine, Database, Model, Query, TableSchema,
14 StorageColumnDefinition as ColumnDefinition, StorageColumnType as ColumnType, WhereClause,
15};
16
17#[derive(Debug, Clone, Model)]
19#[model(table_name = "products")]
20pub struct Product {
21 pub id: i64,
22 pub name: String,
23 pub price: i64,
24}
25
26#[tokio::main]
27async fn main() -> Result<(), Box<dyn std::error::Error>> {
28 println!("🚀 TORM - Async Concurrency Demo\n");
29
30 println!("1) Database (SQLite) concurrent queries");
32 println!("========================================");
33 database_concurrency().await?;
34 println!();
35
36 println!("2) AsyncStorageEngine concurrent read/write");
38 println!("=============================================");
39 async_storage_concurrency().await?;
40 println!();
41
42 println!("🎉 All concurrent demos completed successfully!");
43 Ok(())
44}
45
46async fn database_concurrency() -> Result<(), Box<dyn std::error::Error>> {
48 let db = Arc::new(Database::sqlite(":memory:").await?);
49
50 db.auto_migrate::<Product>().await?;
52
53 for i in 0..100 {
55 let mut p = Product {
56 id: 0,
57 name: format!("product_{}", i),
58 price: i,
59 };
60 db.create(&mut p).await?;
61 }
62
63 let mut handles = Vec::new();
65 for offset in (0..100).step_by(25) {
66 let db = Arc::clone(&db);
67 handles.push(tokio::spawn(async move {
68 let products: Vec<Product> = Query::new("products")
69 .order_by_asc("id")
70 .limit(25)
71 .offset(offset)
72 .query(&db)
73 .models::<Product>()
74 .await?;
75 Ok::<usize, torm::db::database::DbError>(products.len())
76 }));
77 }
78
79 let mut total = 0usize;
80 for h in handles {
81 total += h.await??;
82 }
83 println!(" 4 concurrent queries fetched {} rows in total.", total);
84
85 let mut handles = Vec::new();
87 for min_price in [10i64, 20, 30, 40] {
88 let db = Arc::clone(&db);
89 handles.push(tokio::spawn(async move {
90 Query::new("products")
91 .where_gt("price", min_price)
92 .query(&db)
93 .count()
94 .await
95 }));
96 }
97 for (i, h) in handles.into_iter().enumerate() {
98 let count = h.await??;
99 let n = count
100 .rows
101 .first()
102 .and_then(|r| r.get("COUNT(*)").or_else(|| r.get("count")))
103 .and_then(|v| v.as_i64())
104 .unwrap_or(0);
105 println!(" price > {} -> {} products", [10, 20, 30, 40][i], n);
106 }
107
108 Ok(())
109}
110
111async fn async_storage_concurrency() -> Result<(), Box<dyn std::error::Error>> {
113 let engine = Arc::new(AsyncStorageEngine::new());
114
115 let schema = TableSchema {
116 name: "scores".to_string(),
117 columns: vec![
118 ColumnDefinition {
119 name: "id".to_string(),
120 column_type: ColumnType::Integer,
121 nullable: false,
122 default: None,
123 unique: true,
124 },
125 ColumnDefinition {
126 name: "player".to_string(),
127 column_type: ColumnType::Text,
128 nullable: false,
129 default: None,
130 unique: false,
131 },
132 ColumnDefinition {
133 name: "score".to_string(),
134 column_type: ColumnType::Integer,
135 nullable: true,
136 default: None,
137 unique: false,
138 },
139 ],
140 primary_key: Some("id".to_string()),
141 };
142 engine.create_table(schema).await?;
143
144 let mut handles = Vec::new();
146 for i in 0..50u32 {
147 let engine = Arc::clone(&engine);
148 handles.push(tokio::spawn(async move {
149 engine
150 .insert(
151 "scores",
152 vec![
153 (i as i32).into(),
154 format!("player_{}", i).into(),
155 ((i * 3 % 100) as i32).into(),
156 ],
157 )
158 .await
159 }));
160 }
161 for h in handles {
162 h.await??;
163 }
164
165 let mut handles = Vec::new();
167 for i in 0..50u32 {
168 let engine = Arc::clone(&engine);
169 handles.push(tokio::spawn(async move {
170 let result = engine.select("scores", None, None, None, None).await?;
172 let mut updates = HashMap::new();
173 updates.insert("score".to_string(), (100 + i as i32).into());
174 let affected = engine
175 .update(
176 "scores",
177 updates,
178 Some(WhereClause::Eq("id".to_string(), (i as i32).into())),
179 )
180 .await?;
181 Ok::<(usize, u64), torm::db::storage::StorageError>((result.rows.len(), affected))
182 }));
183 }
184
185 let mut total_reads = 0usize;
186 let mut total_affected = 0u64;
187 for h in handles {
188 let (read, affected) = h.await??;
189 total_reads += read;
190 total_affected += affected;
191 }
192 println!(
193 " 50 concurrent tasks: {} total reads, {} rows updated.",
194 total_reads, total_affected
195 );
196
197 let result = engine.select("scores", None, None, None, None).await?;
199 let total_score: i32 = result
200 .rows
201 .iter()
202 .filter_map(|r| r.get("score").and_then(|v| v.as_i32()))
203 .sum();
204 println!(
205 " Final: {} players, total score = {}",
206 result.rows.len(),
207 total_score
208 );
209
210 Ok(())
211}