nxtgauge-backend-rust/crates/db/src/models/config.rs

358 lines
9.7 KiB
Rust
Raw Normal View History

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::{FromRow, PgPool};
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct OnboardingConfigListItem {
pub id: Uuid,
pub role_id: Uuid,
pub role_key: String,
pub version: i32,
pub is_active: bool,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct OnboardingConfig {
pub id: Uuid,
pub role_id: Uuid,
pub schema_json: serde_json::Value,
pub version: i32,
pub is_active: bool,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateOnboardingConfigPayload {
pub role_id: Uuid,
pub schema_json: serde_json::Value,
}
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct DashboardConfigListItem {
pub id: Uuid,
pub role_id: Uuid,
pub role_key: String,
pub audience: String,
pub version: i32,
pub is_active: bool,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct DashboardConfig {
pub id: Uuid,
pub role_id: Uuid,
pub audience: String,
pub config_json: serde_json::Value,
pub version: i32,
pub is_active: bool,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateDashboardConfigPayload {
pub role_id: Uuid,
pub audience: String,
pub config_json: serde_json::Value,
}
#[derive(Debug, Serialize, Deserialize, FromRow)]
pub struct RuntimeConfig {
pub id: Uuid,
pub role_id: Uuid,
pub config_json: serde_json::Value,
pub version: i32,
pub is_active: bool,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct CreateRuntimeConfigPayload {
pub role_id: Uuid,
pub config_json: serde_json::Value,
}
pub struct ConfigRepository;
impl ConfigRepository {
pub async fn create_onboarding_config(
pool: &PgPool,
payload: CreateOnboardingConfigPayload,
) -> Result<OnboardingConfig, sqlx::Error> {
// Soft-disable previous active configs for this role
sqlx::query!(
r#"
UPDATE onboarding_configs
SET is_active = false
WHERE role_id = $1 AND is_active = true
"#,
payload.role_id
)
.execute(pool)
.await?;
// Insert new config
let config = sqlx::query_as!(
OnboardingConfig,
r#"
INSERT INTO onboarding_configs (role_id, schema_json, version, is_active)
VALUES (
$1,
$2,
COALESCE((SELECT MAX(version) FROM onboarding_configs WHERE role_id = $1), 0) + 1,
true
)
RETURNING id, role_id, schema_json, version, is_active, updated_at
"#,
payload.role_id,
payload.schema_json
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_active_onboarding_config(
pool: &PgPool,
role_id: Uuid,
) -> Result<OnboardingConfig, sqlx::Error> {
let config = sqlx::query_as!(
OnboardingConfig,
r#"
SELECT id, role_id, schema_json, version, is_active, updated_at
FROM onboarding_configs
WHERE role_id = $1 AND is_active = true
"#,
role_id
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_all_onboarding_configs(
pool: &PgPool,
) -> Result<Vec<OnboardingConfigListItem>, sqlx::Error> {
let configs = sqlx::query_as!(
OnboardingConfigListItem,
r#"
SELECT
c.id, c.role_id, r.key as role_key,
c.version, c.is_active, c.updated_at
FROM onboarding_configs c
JOIN roles r ON c.role_id = r.id
ORDER BY c.updated_at DESC
"#
)
.fetch_all(pool)
.await?;
Ok(configs)
}
pub async fn get_active_onboarding_by_role_key(
pool: &PgPool,
role_key: &str,
) -> Result<OnboardingConfig, sqlx::Error> {
let config = sqlx::query_as!(
OnboardingConfig,
r#"
SELECT c.id, c.role_id, c.schema_json, c.version, c.is_active, c.updated_at
FROM onboarding_configs c
JOIN roles r ON c.role_id = r.id
WHERE r.key = $1 AND c.is_active = true
"#,
role_key.to_uppercase()
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn create_dashboard_config(
pool: &PgPool,
payload: CreateDashboardConfigPayload,
) -> Result<DashboardConfig, sqlx::Error> {
// Soft-disable previous active configs for this role
sqlx::query!(
r#"
UPDATE dashboard_configs
SET is_active = false
WHERE role_id = $1 AND audience = $2::text AND is_active = true
"#,
payload.role_id,
payload.audience
)
.execute(pool)
.await?;
// Insert new config
let config = sqlx::query_as!(
DashboardConfig,
r#"
INSERT INTO dashboard_configs (role_id, audience, config_json, version, is_active)
VALUES (
$1,
$2::text,
$3,
COALESCE((SELECT MAX(version) FROM dashboard_configs WHERE role_id = $1 AND audience = $2::text), 0) + 1,
true
)
RETURNING id, role_id, audience, config_json, version, is_active, updated_at
"#,
payload.role_id,
payload.audience,
payload.config_json
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_active_dashboard_config(
pool: &PgPool,
role_id: Uuid,
audience: &str,
) -> Result<DashboardConfig, sqlx::Error> {
let config = sqlx::query_as!(
DashboardConfig,
r#"
SELECT id, role_id, audience, config_json, version, is_active, updated_at
FROM dashboard_configs
WHERE role_id = $1 AND audience = $2 AND is_active = true
"#,
role_id,
audience
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_all_dashboard_configs(
pool: &PgPool,
) -> Result<Vec<DashboardConfigListItem>, sqlx::Error> {
let configs = sqlx::query_as!(
DashboardConfigListItem,
r#"
SELECT
c.id, c.role_id, r.key as role_key, c.audience,
c.version, c.is_active, c.updated_at
FROM dashboard_configs c
JOIN roles r ON c.role_id = r.id
ORDER BY c.updated_at DESC
"#
)
.fetch_all(pool)
.await?;
Ok(configs)
}
pub async fn get_active_dashboard_by_role_key(
pool: &PgPool,
role_key: &str,
audience: &str,
) -> Result<DashboardConfig, sqlx::Error> {
let config = sqlx::query_as!(
DashboardConfig,
r#"
SELECT c.id, c.role_id, c.audience, c.config_json, c.version, c.is_active, c.updated_at
FROM dashboard_configs c
JOIN roles r ON c.role_id = r.id
WHERE r.key = $1 AND c.audience = $2 AND c.is_active = true
"#,
role_key.to_uppercase(),
audience
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn create_runtime_config(
pool: &PgPool,
payload: CreateRuntimeConfigPayload,
) -> Result<RuntimeConfig, sqlx::Error> {
// Soft-disable previous active configs for this role
sqlx::query!(
r#"
UPDATE runtime_configs
SET is_active = false
WHERE role_id = $1 AND is_active = true
"#,
payload.role_id
)
.execute(pool)
.await?;
// Insert new config
let config = sqlx::query_as!(
RuntimeConfig,
r#"
INSERT INTO runtime_configs (role_id, config_json, version, is_active)
VALUES (
$1,
$2,
COALESCE((SELECT MAX(version) FROM runtime_configs WHERE role_id = $1), 0) + 1,
true
)
RETURNING id, role_id, config_json, version, is_active, updated_at
"#,
payload.role_id,
payload.config_json
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_active_runtime_config(
pool: &PgPool,
role_id: Uuid,
) -> Result<RuntimeConfig, sqlx::Error> {
let config = sqlx::query_as!(
RuntimeConfig,
r#"
SELECT id, role_id, config_json, version, is_active, updated_at
FROM runtime_configs
WHERE role_id = $1 AND is_active = true
"#,
role_id
)
.fetch_one(pool)
.await?;
Ok(config)
}
pub async fn get_active_runtime_by_role_key(
pool: &PgPool,
role_key: &str,
) -> Result<RuntimeConfig, sqlx::Error> {
let config = sqlx::query_as!(
RuntimeConfig,
r#"
SELECT rc.id, rc.role_id, rc.config_json, rc.version, rc.is_active, rc.updated_at
FROM runtime_configs rc
JOIN roles r ON rc.role_id = r.id
WHERE r.key = $1 AND rc.is_active = true
"#,
role_key.to_uppercase()
)
.fetch_one(pool)
.await?;
Ok(config)
}
}