use anyhow::Result; use sqlx::SqlitePool; use crate::models::{Activity, Plan, Relay, Tenant}; #[derive(Clone)] pub struct Query { pool: SqlitePool, } impl Query { pub fn new(pool: SqlitePool) -> Self { Self { pool } } pub async fn list_tenants(&self) -> Result> { let rows = sqlx::query_as::<_, Tenant>( "SELECT pubkey, nwc_url, nwc_error, created_at, stripe_customer_id, stripe_subscription_id, past_due_at FROM tenant ORDER BY pubkey", ) .fetch_all(&self.pool) .await?; Ok(rows) } pub async fn get_tenant(&self, pubkey: &str) -> Result> { let row = sqlx::query_as::<_, Tenant>( "SELECT pubkey, nwc_url, nwc_error, created_at, stripe_customer_id, stripe_subscription_id, past_due_at FROM tenant WHERE pubkey = ?", ) .bind(pubkey) .fetch_optional(&self.pool) .await?; Ok(row) } pub fn list_plans() -> Vec { vec![ Plan { id: "free".to_string(), name: "Free".to_string(), amount: 0, members: Some(10), blossom: false, livekit: false, stripe_price_id: None, }, Plan { id: "basic".to_string(), name: "Basic".to_string(), amount: 500, members: Some(100), blossom: true, livekit: true, stripe_price_id: Some(std::env::var("STRIPE_PRICE_BASIC").unwrap_or_default()), }, Plan { id: "growth".to_string(), name: "Growth".to_string(), amount: 2500, members: None, blossom: true, livekit: true, stripe_price_id: Some(std::env::var("STRIPE_PRICE_GROWTH").unwrap_or_default()), }, ] } pub async fn list_relays(&self) -> Result> { let rows = sqlx::query_as::<_, Relay>( "SELECT id, tenant, schema, subdomain, plan, stripe_subscription_item_id, status, sync_error, info_name, info_icon, info_description, policy_public_join, policy_strip_signatures, groups_enabled, management_enabled, blossom_enabled, livekit_enabled, push_enabled, synced FROM relay ORDER BY id", ) .fetch_all(&self.pool) .await?; Ok(rows) } pub async fn list_relays_for_tenant(&self, tenant_id: &str) -> Result> { let rows = sqlx::query_as::<_, Relay>( "SELECT id, tenant, schema, subdomain, plan, stripe_subscription_item_id, status, sync_error, info_name, info_icon, info_description, policy_public_join, policy_strip_signatures, groups_enabled, management_enabled, blossom_enabled, livekit_enabled, push_enabled, synced FROM relay WHERE tenant = ? ORDER BY id", ) .bind(tenant_id) .fetch_all(&self.pool) .await?; Ok(rows) } pub async fn get_relay(&self, id: &str) -> Result> { let row = sqlx::query_as::<_, Relay>( "SELECT id, tenant, schema, subdomain, plan, stripe_subscription_item_id, status, sync_error, info_name, info_icon, info_description, policy_public_join, policy_strip_signatures, groups_enabled, management_enabled, blossom_enabled, livekit_enabled, push_enabled, synced FROM relay WHERE id = ?", ) .bind(id) .fetch_optional(&self.pool) .await?; Ok(row) } pub async fn get_tenant_by_stripe_customer_id(&self, stripe_customer_id: &str) -> Result> { let row = sqlx::query_as::<_, Tenant>( "SELECT pubkey, nwc_url, nwc_error, created_at, stripe_customer_id, stripe_subscription_id, past_due_at FROM tenant WHERE stripe_customer_id = ?", ) .bind(stripe_customer_id) .fetch_optional(&self.pool) .await?; Ok(row) } pub async fn has_active_paid_relays(&self, tenant_id: &str) -> Result { let count = sqlx::query_scalar::<_, i64>( "SELECT COUNT(*) FROM relay WHERE tenant = ? AND status = 'active' AND plan != 'free'", ) .bind(tenant_id) .fetch_one(&self.pool) .await?; Ok(count > 0) } pub async fn list_activity_for_relay(&self, relay_id: &str) -> Result> { let rows = sqlx::query_as::<_, Activity>( "SELECT id, tenant, created_at, activity_type, resource_type, resource_id FROM activity WHERE resource_type = 'relay' AND resource_id = ? ORDER BY created_at DESC, id DESC", ) .bind(relay_id) .fetch_all(&self.pool) .await?; Ok(rows) } }