use chrono::{DateTime, Utc}; use diesel::prelude::*; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::core::shared::schema::dashboards::{ conversational_queries, dashboard_data_sources, dashboard_filters, dashboard_widgets, dashboards, }; use super::types::{ Dashboard, DashboardFilter, DashboardFilterType, DashboardLayout, DataSource, DataSourceConnection, DataSourceSchema, DataSourceStatus, DataSourceType, DataQuery, FilterOption, Widget, WidgetConfig, WidgetPosition, WidgetStyle, WidgetType, }; #[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)] #[diesel(table_name = dashboards)] pub struct DbDashboard { pub id: Uuid, pub org_id: Uuid, pub bot_id: Uuid, pub owner_id: Uuid, pub name: String, pub description: Option, pub layout: serde_json::Value, pub refresh_interval: Option, pub is_public: bool, pub is_template: bool, pub tags: Vec, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)] #[diesel(table_name = dashboard_widgets)] pub struct DbWidget { pub id: Uuid, pub dashboard_id: Uuid, pub widget_type: String, pub title: String, pub position_x: i32, pub position_y: i32, pub width: i32, pub height: i32, pub config: serde_json::Value, pub data_query: Option, pub style: serde_json::Value, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Debug, Clone, Queryable, Insertable, AsChangeset, Serialize, Deserialize)] #[diesel(table_name = dashboard_data_sources)] pub struct DbDataSource { pub id: Uuid, pub org_id: Uuid, pub bot_id: Uuid, pub name: String, pub description: Option, pub source_type: String, pub connection: serde_json::Value, pub schema_definition: serde_json::Value, pub refresh_schedule: Option, pub last_sync: Option>, pub status: String, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Debug, Clone, Queryable, Insertable, Serialize, Deserialize)] #[diesel(table_name = dashboard_filters)] pub struct DbFilter { pub id: Uuid, pub dashboard_id: Uuid, pub name: String, pub field: String, pub filter_type: String, pub default_value: Option, pub options: serde_json::Value, pub linked_widgets: serde_json::Value, pub created_at: DateTime, } #[derive(Debug, Clone, Queryable, Insertable, Serialize, Deserialize)] #[diesel(table_name = conversational_queries)] pub struct DbConversationalQuery { pub id: Uuid, pub org_id: Uuid, pub bot_id: Uuid, pub dashboard_id: Option, pub user_id: Uuid, pub natural_language: String, pub generated_query: Option, pub result_widget_config: Option, pub created_at: DateTime, } pub fn db_dashboard_to_dashboard( db: DbDashboard, widgets: Vec, filters: Vec, ) -> Dashboard { let layout: DashboardLayout = serde_json::from_value(db.layout).unwrap_or_default(); Dashboard { id: db.id, organization_id: db.org_id, owner_id: db.owner_id, name: db.name, description: db.description, layout, widgets, data_sources: vec![], filters, refresh_interval: db.refresh_interval, is_public: db.is_public, is_template: db.is_template, tags: db.tags, created_at: db.created_at, updated_at: db.updated_at, } } pub fn db_widget_to_widget(db: DbWidget) -> Widget { let widget_type: WidgetType = db.widget_type.parse().unwrap_or(WidgetType::Text); let config: WidgetConfig = serde_json::from_value(db.config).unwrap_or_default(); let data_query: Option = db.data_query.and_then(|v| serde_json::from_value(v).ok()); let style: Option = serde_json::from_value(db.style).ok(); Widget { id: db.id, widget_type, title: db.title, position: WidgetPosition { x: db.position_x, y: db.position_y, width: db.width, height: db.height, }, config, data_query, style, } } pub fn db_filter_to_filter(db: DbFilter) -> DashboardFilter { let filter_type: DashboardFilterType = db .filter_type .parse() .unwrap_or(DashboardFilterType::Text); let options: Vec = serde_json::from_value(db.options).unwrap_or_default(); let linked_widgets: Vec = serde_json::from_value(db.linked_widgets).unwrap_or_default(); DashboardFilter { id: db.id, name: db.name, field: db.field, filter_type, default_value: db.default_value, options, linked_widgets, } } pub fn db_data_source_to_data_source(db: DbDataSource) -> DataSource { let source_type: DataSourceType = db .source_type .parse() .unwrap_or(DataSourceType::InternalTables); let connection: DataSourceConnection = serde_json::from_value(db.connection).unwrap_or_default(); let schema: Option = serde_json::from_value(db.schema_definition).ok(); let status: DataSourceStatus = db.status.parse().unwrap_or(DataSourceStatus::Inactive); DataSource { id: db.id, organization_id: db.org_id, name: db.name, description: db.description, source_type, connection, schema, refresh_schedule: db.refresh_schedule, last_sync: db.last_sync, status, created_at: db.created_at, updated_at: db.updated_at, } }