use prax_postgres::{PgEngine, PgPool};
use prax_query::filter::{Filter, FilterValue};
use prax_query::raw::sql_with_params;
use prax_query::traits::QueryEngine;
const DATABASE_URL: &str = "postgresql://prax:prax_test_password@localhost:5432/prax_test";
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter("prax_postgres=debug,postgres_demo=info")
.init();
println!("🚀 Prax PostgreSQL Demo\n");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
println!("📦 Creating connection pool...");
let config = prax_postgres::PgConfig::from_url(DATABASE_URL)?;
let pool = PgPool::new(config).await?;
println!(" ✓ Connection pool created\n");
println!("⚙️ Creating Prax PostgreSQL engine...");
let engine = PgEngine::new(pool.clone());
println!(" ✓ Engine created and ready\n");
println!("🔌 Verifying database connection...");
let conn = pool.get().await?;
let row = conn.query_one("SELECT version()", &[]).await?;
let version: &str = row.get(0);
println!(
" ✓ Connected to: {}\n",
version.split(" on ").next().unwrap_or(version)
);
println!("📊 Checking database schema...");
let tables_row = conn.query_one(
"SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE'",
&[],
).await?;
let table_count: i64 = tables_row.get(0);
println!(" ✓ Found {} tables in public schema\n", table_count);
let tables = conn.query(
"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE' ORDER BY table_name",
&[],
).await?;
println!(" Tables:");
for table in &tables {
let name: &str = table.get(0);
println!(" • {}", name);
}
println!();
println!("📝 Executing raw SQL via Prax engine...\n");
let count = engine.count("SELECT COUNT(*) FROM users", vec![]).await?;
println!(" Current user count: {}", count);
println!("\n Inserting test user...");
let insert_result = engine
.execute_raw(
"INSERT INTO users (email, name, active, created_at, updated_at) \
VALUES ($1, $2, $3, NOW(), NOW()) \
ON CONFLICT (email) DO NOTHING",
vec![
prax_query::filter::FilterValue::String("demo@prax.dev".to_string()),
prax_query::filter::FilterValue::String("Prax Demo User".to_string()),
prax_query::filter::FilterValue::Bool(true),
],
)
.await?;
println!(" ✓ Insert affected {} row(s)", insert_result);
let new_count = engine.count("SELECT COUNT(*) FROM users", vec![]).await?;
println!(" New user count: {}\n", new_count);
println!("🔍 Using the Prax raw SQL builder...\n");
let query = sql_with_params(
"SELECT id, email, name, active FROM users WHERE active = $1",
vec![FilterValue::Bool(true)],
);
let (sql_str, params) = query.build();
println!(" Generated SQL: {}", sql_str);
println!(" Parameters: {:?}\n", params);
let rows = conn
.query(
"SELECT id, email, name, active FROM users WHERE active = true LIMIT 5",
&[],
)
.await?;
println!(" Active users (first 5):");
for row in rows {
let id: i64 = row.get(0);
let email: &str = row.get(1);
let name: Option<&str> = row.get(2);
let active: bool = row.get(3);
println!(
" • [{}] {} - {} (active: {})",
id,
email,
name.unwrap_or("(no name)"),
active
);
}
println!();
println!("📚 Working with Posts table...\n");
let user_row = conn
.query_opt("SELECT id FROM users WHERE email = $1", &[&"demo@prax.dev"])
.await?;
if let Some(user_row) = user_row {
let user_id: i64 = user_row.get(0);
println!(" Found demo user with id: {}", user_id);
let post_result = conn
.execute(
"INSERT INTO posts (title, content, published, view_count, created_at, updated_at, user_id) \
VALUES ($1, $2, $3, $4, NOW(), NOW(), $5) \
ON CONFLICT DO NOTHING",
&[
&"Hello from Prax!",
&"This is a demo post created by the Prax PostgreSQL demo.",
&true,
&0i32,
&user_id,
],
)
.await?;
println!(" ✓ Created {} post(s)", post_result);
let post_count = engine.count("SELECT COUNT(*) FROM posts", vec![]).await?;
println!(" Total posts in database: {}\n", post_count);
}
println!("🎯 Testing filter operations...\n");
let filter = Filter::And(
vec![
Filter::Equals("active".into(), FilterValue::Bool(true)),
Filter::Contains("email".into(), FilterValue::String("@".to_string())),
]
.into_boxed_slice(),
);
println!(" Filter structure: {:?}", filter);
let (where_clause, filter_params) = filter.to_sql(1); println!(" Generated WHERE: {}", where_clause);
println!(" Filter params: {:?}\n", filter_params);
println!("🏊 Connection pool statistics...\n");
let status = pool.status();
println!(" Pool size: {}", status.size);
println!(" Available connections: {}", status.available);
println!(" Waiting clients: {}\n", status.waiting);
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
println!("✅ Demo completed successfully!\n");
println!("📋 Summary:");
println!(" • Connected to PostgreSQL with connection pooling");
println!(" • Verified schema tables created by migrations");
println!(" • Executed raw SQL queries via Prax engine");
println!(" • Demonstrated filter building and SQL generation");
println!(" • Created test data (user and post)");
println!();
println!("🔗 Next steps:");
println!(" • Run 'prax generate' to create typed model code");
println!(" • Use generated code for type-safe queries");
println!(" • Check prax-query for advanced query building");
println!();
Ok(())
}