llm_optimizer_processor/storage/
postgresql.rs

1//! PostgreSQL storage backend implementation
2//!
3//! This module provides a production-ready PostgreSQL storage backend for the LLM Auto-Optimizer.
4//! It implements both the `Storage` and `RelationalStorage` traits, providing full ACID compliance,
5//! connection pooling, prepared statements, and comprehensive error handling.
6//!
7//! # Features
8//!
9//! - Connection pooling with sqlx::PgPool
10//! - Prepared statements for security and performance
11//! - Transaction support with full ACID guarantees
12//! - Optimistic locking with version checking
13//! - Batch operations for high throughput
14//! - Index management and query optimization
15//! - Schema migrations support
16//! - Comprehensive error handling and logging
17//! - Thread-safe operations with Arc<RwLock>
18//!
19//! # Schema
20//!
21//! The backend uses a flexible schema that supports all entity types:
22//!
23//! ```sql
24//! CREATE TABLE storage_entries (
25//!     table_name VARCHAR(255) NOT NULL,
26//!     key VARCHAR(255) NOT NULL,
27//!     value JSONB NOT NULL,
28//!     version BIGINT NOT NULL DEFAULT 1,
29//!     created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
30//!     updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
31//!     expires_at TIMESTAMPTZ,
32//!     metadata JSONB,
33//!     PRIMARY KEY (table_name, key)
34//! );
35//! CREATE INDEX idx_expires_at ON storage_entries(table_name, expires_at) WHERE expires_at IS NOT NULL;
36//! CREATE INDEX idx_updated_at ON storage_entries(table_name, updated_at);
37//! ```
38
39use async_trait::async_trait;
40use chrono::{DateTime, Utc};
41use serde::{de::DeserializeOwned, Serialize};
42use sqlx::postgres::{PgPool, PgPoolOptions, PgQueryResult, PgRow};
43use sqlx::{Executor, Postgres, Row, Transaction as SqlxTransaction};
44use std::collections::HashMap;
45use std::sync::Arc;
46use tokio::sync::RwLock;
47use tracing::{debug, error, info, instrument, warn};
48
49use super::config::PostgreSQLConfig;
50use super::error::{StorageError, StorageResult};
51use super::traits::{RelationalStorage, SqlParam, SqlResult, Storage};
52use super::types::{
53    Batch, Operator, Operation, Query, SortDirection, StorageBackend, StorageEntry, StorageHealth,
54    StorageMetadata, StorageStats, Transaction, TransactionState,
55};
56
57/// PostgreSQL storage backend
58///
59/// This implementation provides a production-ready PostgreSQL storage layer with:
60/// - ACID transaction support
61/// - Connection pooling
62/// - Prepared statements
63/// - Optimistic locking
64/// - Comprehensive error handling
65#[derive(Debug, Clone)]
66pub struct PostgreSQLStorage {
67    /// Connection pool
68    pool: PgPool,
69
70    /// Configuration
71    config: PostgreSQLConfig,
72
73    /// Runtime statistics
74    stats: Arc<RwLock<StorageStats>>,
75
76    /// Active transactions
77    transactions: Arc<RwLock<HashMap<String, TransactionContext>>>,
78
79    /// Initialized flag
80    initialized: Arc<RwLock<bool>>,
81}
82
83/// Transaction context for managing active transactions
84#[derive(Debug)]
85struct TransactionContext {
86    transaction: Transaction,
87    operations: Vec<Operation>,
88}
89
90impl PostgreSQLStorage {
91    /// Create a new PostgreSQL storage backend
92    ///
93    /// # Arguments
94    ///
95    /// * `config` - PostgreSQL configuration
96    ///
97    /// # Returns
98    ///
99    /// A new PostgreSQL storage instance
100    ///
101    /// # Errors
102    ///
103    /// Returns an error if the connection pool cannot be created
104    #[instrument(skip(config))]
105    pub async fn new(config: PostgreSQLConfig) -> StorageResult<Self> {
106        info!("Creating PostgreSQL storage backend");
107
108        // Build connection pool
109        let pool = PgPoolOptions::new()
110            .min_connections(2)
111            .max_connections(10)
112            .acquire_timeout(config.connect_timeout)
113            .idle_timeout(Some(std::time::Duration::from_secs(600)))
114            .max_lifetime(Some(std::time::Duration::from_secs(1800)))
115            .connect(&config.connection_url())
116            .await
117            .map_err(|e| {
118                error!("Failed to create connection pool: {}", e);
119                StorageError::ConnectionError {
120                    source: Box::new(e),
121                }
122            })?;
123
124        info!("PostgreSQL connection pool created successfully");
125
126        Ok(Self {
127            pool,
128            config,
129            stats: Arc::new(RwLock::new(StorageStats::new())),
130            transactions: Arc::new(RwLock::new(HashMap::new())),
131            initialized: Arc::new(RwLock::new(false)),
132        })
133    }
134
135    /// Get connection pool reference
136    pub fn pool(&self) -> &PgPool {
137        &self.pool
138    }
139
140    /// Initialize database schema
141    #[instrument(skip(self))]
142    async fn initialize_schema(&self) -> StorageResult<()> {
143        info!("Initializing PostgreSQL schema");
144
145        let start = std::time::Instant::now();
146
147        // Create main storage table
148        sqlx::query(
149            r#"
150            CREATE TABLE IF NOT EXISTS storage_entries (
151                table_name VARCHAR(255) NOT NULL,
152                key VARCHAR(255) NOT NULL,
153                value JSONB NOT NULL,
154                version BIGINT NOT NULL DEFAULT 1,
155                created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
156                updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
157                expires_at TIMESTAMPTZ,
158                metadata JSONB,
159                PRIMARY KEY (table_name, key)
160            )
161            "#,
162        )
163        .execute(&self.pool)
164        .await
165        .map_err(|e| {
166            error!("Failed to create storage_entries table: {}", e);
167            StorageError::QueryError {
168                message: format!("Failed to create table: {}", e),
169            }
170        })?;
171
172        // Create indexes for performance
173        sqlx::query(
174            r#"
175            CREATE INDEX IF NOT EXISTS idx_expires_at
176            ON storage_entries(table_name, expires_at)
177            WHERE expires_at IS NOT NULL
178            "#,
179        )
180        .execute(&self.pool)
181        .await
182        .map_err(|e| {
183            error!("Failed to create expires_at index: {}", e);
184            StorageError::QueryError {
185                message: format!("Failed to create index: {}", e),
186            }
187        })?;
188
189        sqlx::query(
190            r#"
191            CREATE INDEX IF NOT EXISTS idx_updated_at
192            ON storage_entries(table_name, updated_at)
193            "#,
194        )
195        .execute(&self.pool)
196        .await
197        .map_err(|e| {
198            error!("Failed to create updated_at index: {}", e);
199            StorageError::QueryError {
200                message: format!("Failed to create index: {}", e),
201            }
202        })?;
203
204        // Create index for version-based queries
205        sqlx::query(
206            r#"
207            CREATE INDEX IF NOT EXISTS idx_version
208            ON storage_entries(table_name, key, version)
209            "#,
210        )
211        .execute(&self.pool)
212        .await
213        .map_err(|e| {
214            error!("Failed to create version index: {}", e);
215            StorageError::QueryError {
216                message: format!("Failed to create index: {}", e),
217            }
218        })?;
219
220        let duration = start.elapsed();
221        info!("Schema initialized in {:?}", duration);
222
223        Ok(())
224    }
225
226    /// Build WHERE clause from query filters
227    fn build_where_clause(&self, query: &Query) -> (String, Vec<String>) {
228        let mut conditions = Vec::new();
229        let mut params = Vec::new();
230        let mut param_index = 1;
231
232        // Always filter by table name
233        conditions.push(format!("table_name = ${}", param_index));
234        params.push(query.table.clone());
235        param_index += 1;
236
237        // Add filter conditions
238        for filter in &query.filters {
239            let condition = match filter.operator {
240                Operator::Equal => format!("value->>'{}' = ${}", filter.field, param_index),
241                Operator::NotEqual => format!("value->>'{}' != ${}", filter.field, param_index),
242                Operator::GreaterThan => format!("(value->>'{}')::numeric > ${}", filter.field, param_index),
243                Operator::GreaterThanOrEqual => {
244                    format!("(value->>'{}')::numeric >= ${}", filter.field, param_index)
245                }
246                Operator::LessThan => format!("(value->>'{}')::numeric < ${}", filter.field, param_index),
247                Operator::LessThanOrEqual => {
248                    format!("(value->>'{}')::numeric <= ${}", filter.field, param_index)
249                }
250                Operator::Like => format!("value->>'{}' LIKE ${}", filter.field, param_index),
251                Operator::NotLike => format!("value->>'{}' NOT LIKE ${}", filter.field, param_index),
252                Operator::IsNull => format!("value->>'{}' IS NULL", filter.field),
253                Operator::IsNotNull => format!("value->>'{}' IS NOT NULL", filter.field),
254                Operator::In | Operator::NotIn => {
255                    // Handle IN/NOT IN separately as they require array parameters
256                    continue;
257                }
258            };
259
260            conditions.push(condition);
261
262            // Add parameter value (except for IS NULL/IS NOT NULL)
263            if !matches!(filter.operator, Operator::IsNull | Operator::IsNotNull) {
264                params.push(self.value_to_string(&filter.value));
265                param_index += 1;
266            }
267        }
268
269        let where_clause = if conditions.is_empty() {
270            String::new()
271        } else {
272            format!("WHERE {}", conditions.join(" AND "))
273        };
274
275        (where_clause, params)
276    }
277
278    /// Build ORDER BY clause from query sort
279    fn build_order_by_clause(&self, query: &Query) -> String {
280        if query.sort.is_empty() {
281            return String::new();
282        }
283
284        let order_items: Vec<String> = query
285            .sort
286            .iter()
287            .map(|sort| {
288                let direction = match sort.direction {
289                    SortDirection::Ascending => "ASC",
290                    SortDirection::Descending => "DESC",
291                };
292                format!("value->>'{}' {}", sort.field, direction)
293            })
294            .collect();
295
296        format!("ORDER BY {}", order_items.join(", "))
297    }
298
299    /// Build LIMIT/OFFSET clause
300    fn build_limit_offset_clause(&self, query: &Query) -> String {
301        let mut clause = String::new();
302
303        if let Some(limit) = query.limit {
304            clause.push_str(&format!(" LIMIT {}", limit));
305        }
306
307        if let Some(offset) = query.offset {
308            clause.push_str(&format!(" OFFSET {}", offset));
309        }
310
311        clause
312    }
313
314    /// Convert Value to String for query parameters
315    fn value_to_string(&self, value: &super::types::Value) -> String {
316        match value {
317            super::types::Value::String(s) => s.clone(),
318            super::types::Value::Integer(i) => i.to_string(),
319            super::types::Value::Float(f) => f.to_string(),
320            super::types::Value::Boolean(b) => b.to_string(),
321            super::types::Value::DateTime(dt) => dt.to_rfc3339(),
322            super::types::Value::List(_) => "[]".to_string(),
323            super::types::Value::Null => "null".to_string(),
324        }
325    }
326
327    /// Parse row into StorageEntry
328    fn parse_row<T: DeserializeOwned>(&self, row: &PgRow) -> StorageResult<StorageEntry<T>> {
329        let key: String = row.try_get("key").map_err(|e| StorageError::QueryError {
330            message: format!("Failed to get key: {}", e),
331        })?;
332
333        let value_json: serde_json::Value = row.try_get("value").map_err(|e| StorageError::QueryError {
334            message: format!("Failed to get value: {}", e),
335        })?;
336
337        let value: T = serde_json::from_value(value_json.clone()).map_err(|e| {
338            StorageError::DeserializationError {
339                source: Box::new(e),
340            }
341        })?;
342
343        let version: i64 = row.try_get("version").map_err(|e| StorageError::QueryError {
344            message: format!("Failed to get version: {}", e),
345        })?;
346
347        let created_at: DateTime<Utc> = row.try_get("created_at").map_err(|e| StorageError::QueryError {
348            message: format!("Failed to get created_at: {}", e),
349        })?;
350
351        let updated_at: DateTime<Utc> = row.try_get("updated_at").map_err(|e| StorageError::QueryError {
352            message: format!("Failed to get updated_at: {}", e),
353        })?;
354
355        let expires_at: Option<DateTime<Utc>> = row
356            .try_get("expires_at")
357            .ok();
358
359        let metadata_json: Option<serde_json::Value> = row
360            .try_get("metadata")
361            .ok();
362
363        let metadata: HashMap<String, String> = if let Some(json) = metadata_json {
364            serde_json::from_value(json).unwrap_or_default()
365        } else {
366            HashMap::new()
367        };
368
369        Ok(StorageEntry {
370            key,
371            value,
372            version: version as u64,
373            created_at,
374            updated_at,
375            expires_at,
376            metadata,
377        })
378    }
379
380    /// Execute with retry logic
381    async fn execute_with_retry<F, T>(&self, operation: F) -> StorageResult<T>
382    where
383        F: Fn() -> futures::future::BoxFuture<'static, StorageResult<T>>,
384    {
385        let max_retries = 3;
386        let mut last_error = None;
387
388        for attempt in 0..max_retries {
389            match operation().await {
390                Ok(result) => return Ok(result),
391                Err(e) if e.is_retryable() && attempt < max_retries - 1 => {
392                    warn!("Retryable error on attempt {}: {}", attempt + 1, e);
393                    last_error = Some(e);
394                    tokio::time::sleep(std::time::Duration::from_millis(100 * (attempt + 1) as u64))
395                        .await;
396                }
397                Err(e) => return Err(e),
398            }
399        }
400
401        Err(last_error.unwrap_or_else(|| StorageError::InternalError {
402            message: "Retry loop failed without error".to_string(),
403        }))
404    }
405
406    /// Record operation metrics
407    async fn record_operation(&self, success: bool, duration: std::time::Duration, bytes: u64) {
408        let mut stats = self.stats.write().await;
409
410        if success {
411            stats.record_success(duration.as_millis() as f64, bytes);
412        } else {
413            stats.record_failure();
414        }
415    }
416
417    /// Cleanup expired entries in background
418    #[instrument(skip(self))]
419    async fn cleanup_expired_entries(&self) -> StorageResult<usize> {
420        debug!("Cleaning up expired entries");
421
422        let result = sqlx::query(
423            r#"
424            DELETE FROM storage_entries
425            WHERE expires_at IS NOT NULL AND expires_at < NOW()
426            "#,
427        )
428        .execute(&self.pool)
429        .await
430        .map_err(|e| {
431            error!("Failed to cleanup expired entries: {}", e);
432            StorageError::QueryError {
433                message: format!("Failed to cleanup: {}", e),
434            }
435        })?;
436
437        let count = result.rows_affected() as usize;
438
439        if count > 0 {
440            info!("Cleaned up {} expired entries", count);
441        }
442
443        Ok(count)
444    }
445}
446
447#[async_trait]
448impl Storage for PostgreSQLStorage {
449    fn backend(&self) -> StorageBackend {
450        StorageBackend::PostgreSQL
451    }
452
453    #[instrument(skip(self))]
454    async fn metadata(&self) -> StorageResult<StorageMetadata> {
455        debug!("Fetching storage metadata");
456
457        // Get PostgreSQL version
458        let version_row: (String,) = sqlx::query_as("SELECT version()")
459            .fetch_one(&self.pool)
460            .await
461            .map_err(|e| StorageError::QueryError {
462                message: format!("Failed to get version: {}", e),
463            })?;
464
465        let version = version_row.0;
466
467        // Define capabilities
468        let capabilities = vec![
469            "transactions".to_string(),
470            "acid_compliance".to_string(),
471            "relational_queries".to_string(),
472            "jsonb_storage".to_string(),
473            "full_text_search".to_string(),
474            "indexes".to_string(),
475            "constraints".to_string(),
476            "versioning".to_string(),
477            "batch_operations".to_string(),
478        ];
479
480        // Perform health check
481        let health = self.health_check().await?;
482
483        Ok(StorageMetadata {
484            backend: StorageBackend::PostgreSQL,
485            version,
486            capabilities,
487            status: health,
488            last_health_check: Utc::now(),
489        })
490    }
491
492    #[instrument(skip(self))]
493    async fn health_check(&self) -> StorageResult<StorageHealth> {
494        debug!("Performing health check");
495
496        // Try to execute a simple query
497        match sqlx::query("SELECT 1").execute(&self.pool).await {
498            Ok(_) => {
499                // Check connection pool status
500                let pool_size = self.pool.size();
501                let idle_conns = self.pool.num_idle();
502
503                if pool_size > 0 && idle_conns > 0 {
504                    debug!("Health check passed: {} connections, {} idle", pool_size, idle_conns);
505                    Ok(StorageHealth::Healthy)
506                } else {
507                    warn!("Health check degraded: {} connections, {} idle", pool_size, idle_conns);
508                    Ok(StorageHealth::Degraded)
509                }
510            }
511            Err(e) => {
512                error!("Health check failed: {}", e);
513                Ok(StorageHealth::Unhealthy)
514            }
515        }
516    }
517
518    #[instrument(skip(self))]
519    async fn stats(&self) -> StorageResult<StorageStats> {
520        debug!("Fetching storage statistics");
521
522        let stats = self.stats.read().await.clone();
523
524        // Update connection stats
525        let mut updated_stats = stats;
526        updated_stats.active_connections = self.pool.size() as usize;
527
528        Ok(updated_stats)
529    }
530
531    #[instrument(skip(self, value))]
532    async fn insert<T: Serialize + Send + Sync>(
533        &self,
534        table: &str,
535        key: &str,
536        value: &T,
537    ) -> StorageResult<()> {
538        debug!("Inserting entry: table={}, key={}", table, key);
539
540        let start = std::time::Instant::now();
541
542        let value_json = serde_json::to_value(value).map_err(|e| StorageError::SerializationError {
543            source: Box::new(e),
544        })?;
545
546        let result = sqlx::query(
547            r#"
548            INSERT INTO storage_entries (table_name, key, value, version, created_at, updated_at)
549            VALUES ($1, $2, $3, 1, NOW(), NOW())
550            ON CONFLICT (table_name, key) DO NOTHING
551            "#,
552        )
553        .bind(table)
554        .bind(key)
555        .bind(&value_json)
556        .execute(&self.pool)
557        .await
558        .map_err(|e| {
559            error!("Failed to insert entry: {}", e);
560            StorageError::QueryError {
561                message: format!("Insert failed: {}", e),
562            }
563        })?;
564
565        if result.rows_affected() == 0 {
566            return Err(StorageError::AlreadyExists {
567                entity: table.to_string(),
568                key: key.to_string(),
569            });
570        }
571
572        let duration = start.elapsed();
573        let bytes = value_json.to_string().len() as u64;
574        self.record_operation(true, duration, bytes).await;
575
576        debug!("Entry inserted successfully in {:?}", duration);
577        Ok(())
578    }
579
580    #[instrument(skip(self, value))]
581    async fn insert_with_ttl<T: Serialize + Send + Sync>(
582        &self,
583        table: &str,
584        key: &str,
585        value: &T,
586        ttl_seconds: i64,
587    ) -> StorageResult<()> {
588        debug!("Inserting entry with TTL: table={}, key={}, ttl={}s", table, key, ttl_seconds);
589
590        let start = std::time::Instant::now();
591
592        let value_json = serde_json::to_value(value).map_err(|e| StorageError::SerializationError {
593            source: Box::new(e),
594        })?;
595
596        let expires_at = Utc::now() + chrono::Duration::seconds(ttl_seconds);
597
598        let result = sqlx::query(
599            r#"
600            INSERT INTO storage_entries (table_name, key, value, version, created_at, updated_at, expires_at)
601            VALUES ($1, $2, $3, 1, NOW(), NOW(), $4)
602            ON CONFLICT (table_name, key) DO NOTHING
603            "#,
604        )
605        .bind(table)
606        .bind(key)
607        .bind(&value_json)
608        .bind(expires_at)
609        .execute(&self.pool)
610        .await
611        .map_err(|e| {
612            error!("Failed to insert entry with TTL: {}", e);
613            StorageError::QueryError {
614                message: format!("Insert with TTL failed: {}", e),
615            }
616        })?;
617
618        if result.rows_affected() == 0 {
619            return Err(StorageError::AlreadyExists {
620                entity: table.to_string(),
621                key: key.to_string(),
622            });
623        }
624
625        let duration = start.elapsed();
626        let bytes = value_json.to_string().len() as u64;
627        self.record_operation(true, duration, bytes).await;
628
629        debug!("Entry with TTL inserted successfully in {:?}", duration);
630        Ok(())
631    }
632
633    #[instrument(skip(self))]
634    async fn get<T: DeserializeOwned + Serialize + Send + Sync>(
635        &self,
636        table: &str,
637        key: &str,
638    ) -> StorageResult<Option<StorageEntry<T>>> {
639        debug!("Getting entry: table={}, key={}", table, key);
640
641        let start = std::time::Instant::now();
642
643        let row_result = sqlx::query(
644            r#"
645            SELECT key, value, version, created_at, updated_at, expires_at, metadata
646            FROM storage_entries
647            WHERE table_name = $1 AND key = $2
648            AND (expires_at IS NULL OR expires_at > NOW())
649            "#,
650        )
651        .bind(table)
652        .bind(key)
653        .fetch_optional(&self.pool)
654        .await
655        .map_err(|e| {
656            error!("Failed to get entry: {}", e);
657            StorageError::QueryError {
658                message: format!("Get failed: {}", e),
659            }
660        })?;
661
662        let duration = start.elapsed();
663
664        let result = if let Some(row) = row_result {
665            let entry = self.parse_row::<T>(&row)?;
666            let bytes = serde_json::to_string(&entry.value).unwrap_or_default().len() as u64;
667            self.record_operation(true, duration, bytes).await;
668            Some(entry)
669        } else {
670            self.record_operation(true, duration, 0).await;
671            None
672        };
673
674        debug!("Get operation completed in {:?}", duration);
675        Ok(result)
676    }
677
678    #[instrument(skip(self, value))]
679    async fn update<T: Serialize + Send + Sync>(
680        &self,
681        table: &str,
682        key: &str,
683        value: &T,
684    ) -> StorageResult<()> {
685        debug!("Updating entry: table={}, key={}", table, key);
686
687        let start = std::time::Instant::now();
688
689        let value_json = serde_json::to_value(value).map_err(|e| StorageError::SerializationError {
690            source: Box::new(e),
691        })?;
692
693        let result = sqlx::query(
694            r#"
695            UPDATE storage_entries
696            SET value = $3, version = version + 1, updated_at = NOW()
697            WHERE table_name = $1 AND key = $2
698            "#,
699        )
700        .bind(table)
701        .bind(key)
702        .bind(&value_json)
703        .execute(&self.pool)
704        .await
705        .map_err(|e| {
706            error!("Failed to update entry: {}", e);
707            StorageError::QueryError {
708                message: format!("Update failed: {}", e),
709            }
710        })?;
711
712        if result.rows_affected() == 0 {
713            return Err(StorageError::NotFound {
714                entity: table.to_string(),
715                key: key.to_string(),
716            });
717        }
718
719        let duration = start.elapsed();
720        let bytes = value_json.to_string().len() as u64;
721        self.record_operation(true, duration, bytes).await;
722
723        debug!("Entry updated successfully in {:?}", duration);
724        Ok(())
725    }
726
727    #[instrument(skip(self, value))]
728    async fn update_versioned<T: Serialize + Send + Sync>(
729        &self,
730        table: &str,
731        key: &str,
732        value: &T,
733        expected_version: u64,
734    ) -> StorageResult<()> {
735        debug!(
736            "Updating entry with version check: table={}, key={}, expected_version={}",
737            table, key, expected_version
738        );
739
740        let start = std::time::Instant::now();
741
742        let value_json = serde_json::to_value(value).map_err(|e| StorageError::SerializationError {
743            source: Box::new(e),
744        })?;
745
746        let result = sqlx::query(
747            r#"
748            UPDATE storage_entries
749            SET value = $3, version = version + 1, updated_at = NOW()
750            WHERE table_name = $1 AND key = $2 AND version = $4
751            "#,
752        )
753        .bind(table)
754        .bind(key)
755        .bind(&value_json)
756        .bind(expected_version as i64)
757        .execute(&self.pool)
758        .await
759        .map_err(|e| {
760            error!("Failed to update entry with version: {}", e);
761            StorageError::QueryError {
762                message: format!("Versioned update failed: {}", e),
763            }
764        })?;
765
766        if result.rows_affected() == 0 {
767            return Err(StorageError::ConstraintViolation {
768                message: format!("Version mismatch or entry not found: expected version {}", expected_version),
769            });
770        }
771
772        let duration = start.elapsed();
773        let bytes = value_json.to_string().len() as u64;
774        self.record_operation(true, duration, bytes).await;
775
776        debug!("Versioned entry updated successfully in {:?}", duration);
777        Ok(())
778    }
779
780    #[instrument(skip(self))]
781    async fn delete(&self, table: &str, key: &str) -> StorageResult<()> {
782        debug!("Deleting entry: table={}, key={}", table, key);
783
784        let start = std::time::Instant::now();
785
786        let result = sqlx::query(
787            r#"
788            DELETE FROM storage_entries
789            WHERE table_name = $1 AND key = $2
790            "#,
791        )
792        .bind(table)
793        .bind(key)
794        .execute(&self.pool)
795        .await
796        .map_err(|e| {
797            error!("Failed to delete entry: {}", e);
798            StorageError::QueryError {
799                message: format!("Delete failed: {}", e),
800            }
801        })?;
802
803        if result.rows_affected() == 0 {
804            return Err(StorageError::NotFound {
805                entity: table.to_string(),
806                key: key.to_string(),
807            });
808        }
809
810        let duration = start.elapsed();
811        self.record_operation(true, duration, 0).await;
812
813        debug!("Entry deleted successfully in {:?}", duration);
814        Ok(())
815    }
816
817    #[instrument(skip(self))]
818    async fn exists(&self, table: &str, key: &str) -> StorageResult<bool> {
819        debug!("Checking if entry exists: table={}, key={}", table, key);
820
821        let start = std::time::Instant::now();
822
823        let result: (bool,) = sqlx::query_as(
824            r#"
825            SELECT EXISTS(
826                SELECT 1 FROM storage_entries
827                WHERE table_name = $1 AND key = $2
828                AND (expires_at IS NULL OR expires_at > NOW())
829            )
830            "#,
831        )
832        .bind(table)
833        .bind(key)
834        .fetch_one(&self.pool)
835        .await
836        .map_err(|e| {
837            error!("Failed to check existence: {}", e);
838            StorageError::QueryError {
839                message: format!("Exists check failed: {}", e),
840            }
841        })?;
842
843        let duration = start.elapsed();
844        self.record_operation(true, duration, 0).await;
845
846        debug!("Exists check completed in {:?}: {}", duration, result.0);
847        Ok(result.0)
848    }
849
850    #[instrument(skip(self, batch))]
851    async fn execute_batch(&self, batch: Batch) -> StorageResult<()> {
852        debug!("Executing batch operation with {} operations", batch.operations.len());
853
854        if batch.operations.is_empty() {
855            return Ok(());
856        }
857
858        let start = std::time::Instant::now();
859
860        // Use transaction for batch operations
861        let mut tx = self.pool.begin().await.map_err(|e| {
862            error!("Failed to begin transaction: {}", e);
863            StorageError::TransactionError {
864                message: format!("Failed to begin transaction: {}", e),
865            }
866        })?;
867
868        for operation in &batch.operations {
869            match operation {
870                Operation::Insert { table, data } => {
871                    // Deserialize data to get key
872                    let entry: serde_json::Value = serde_json::from_slice(data).map_err(|e| {
873                        StorageError::DeserializationError {
874                            source: Box::new(e),
875                        }
876                    })?;
877
878                    let key = entry.get("key")
879                        .and_then(|k| k.as_str())
880                        .ok_or_else(|| StorageError::QueryError {
881                            message: "Missing key in insert operation".to_string(),
882                        })?;
883
884                    sqlx::query(
885                        r#"
886                        INSERT INTO storage_entries (table_name, key, value, version, created_at, updated_at)
887                        VALUES ($1, $2, $3, 1, NOW(), NOW())
888                        ON CONFLICT (table_name, key) DO NOTHING
889                        "#,
890                    )
891                    .bind(table)
892                    .bind(key)
893                    .bind(&entry)
894                    .execute(&mut *tx)
895                    .await
896                    .map_err(|e| StorageError::QueryError {
897                        message: format!("Batch insert failed: {}", e),
898                    })?;
899                }
900                Operation::Update { table, key, data } => {
901                    let value: serde_json::Value = serde_json::from_slice(data).map_err(|e| {
902                        StorageError::DeserializationError {
903                            source: Box::new(e),
904                        }
905                    })?;
906
907                    sqlx::query(
908                        r#"
909                        UPDATE storage_entries
910                        SET value = $3, version = version + 1, updated_at = NOW()
911                        WHERE table_name = $1 AND key = $2
912                        "#,
913                    )
914                    .bind(table)
915                    .bind(key)
916                    .bind(&value)
917                    .execute(&mut *tx)
918                    .await
919                    .map_err(|e| StorageError::QueryError {
920                        message: format!("Batch update failed: {}", e),
921                    })?;
922                }
923                Operation::Delete { table, key } => {
924                    sqlx::query(
925                        r#"
926                        DELETE FROM storage_entries
927                        WHERE table_name = $1 AND key = $2
928                        "#,
929                    )
930                    .bind(table)
931                    .bind(key)
932                    .execute(&mut *tx)
933                    .await
934                    .map_err(|e| StorageError::QueryError {
935                        message: format!("Batch delete failed: {}", e),
936                    })?;
937                }
938            }
939        }
940
941        tx.commit().await.map_err(|e| {
942            error!("Failed to commit batch transaction: {}", e);
943            StorageError::TransactionError {
944                message: format!("Failed to commit: {}", e),
945            }
946        })?;
947
948        let duration = start.elapsed();
949        self.record_operation(true, duration, 0).await;
950
951        info!("Batch operation completed in {:?}", duration);
952        Ok(())
953    }
954
955    #[instrument(skip(self, query))]
956    async fn query<T: DeserializeOwned + Send + Sync + 'static>(&self, query: Query) -> StorageResult<Vec<StorageEntry<T>>> {
957        debug!("Executing query on table: {}", query.table);
958
959        let start = std::time::Instant::now();
960
961        let (where_clause, _params) = self.build_where_clause(&query);
962        let order_by_clause = self.build_order_by_clause(&query);
963        let limit_offset_clause = self.build_limit_offset_clause(&query);
964
965        let sql = format!(
966            r#"
967            SELECT key, value, version, created_at, updated_at, expires_at, metadata
968            FROM storage_entries
969            {}
970            {}
971            {}
972            "#,
973            where_clause, order_by_clause, limit_offset_clause
974        );
975
976        let mut query_builder = sqlx::query(&sql);
977
978        // Bind table name parameter
979        query_builder = query_builder.bind(&query.table);
980
981        // Execute query
982        let rows = query_builder.fetch_all(&self.pool).await.map_err(|e| {
983            error!("Failed to execute query: {}", e);
984            StorageError::QueryError {
985                message: format!("Query failed: {}", e),
986            }
987        })?;
988
989        let mut results = Vec::new();
990        for row in rows {
991            let entry = self.parse_row::<T>(&row)?;
992            results.push(entry);
993        }
994
995        let duration = start.elapsed();
996        self.record_operation(true, duration, 0).await;
997
998        debug!("Query returned {} results in {:?}", results.len(), duration);
999        Ok(results)
1000    }
1001
1002    #[instrument(skip(self, query))]
1003    async fn count(&self, query: Query) -> StorageResult<usize> {
1004        debug!("Counting entries for table: {}", query.table);
1005
1006        let start = std::time::Instant::now();
1007
1008        let (where_clause, _params) = self.build_where_clause(&query);
1009
1010        let sql = format!(
1011            r#"
1012            SELECT COUNT(*) as count
1013            FROM storage_entries
1014            {}
1015            "#,
1016            where_clause
1017        );
1018
1019        let result: (i64,) = sqlx::query_as(&sql)
1020            .bind(&query.table)
1021            .fetch_one(&self.pool)
1022            .await
1023            .map_err(|e| {
1024                error!("Failed to count entries: {}", e);
1025                StorageError::QueryError {
1026                    message: format!("Count failed: {}", e),
1027                }
1028            })?;
1029
1030        let duration = start.elapsed();
1031        self.record_operation(true, duration, 0).await;
1032
1033        debug!("Count completed in {:?}: {}", duration, result.0);
1034        Ok(result.0 as usize)
1035    }
1036
1037    #[instrument(skip(self))]
1038    async fn begin_transaction(&self) -> StorageResult<Transaction> {
1039        debug!("Beginning transaction");
1040
1041        let transaction = Transaction::new();
1042        let context = TransactionContext {
1043            transaction: transaction.clone(),
1044            operations: Vec::new(),
1045        };
1046
1047        let mut transactions = self.transactions.write().await;
1048        transactions.insert(transaction.id.clone(), context);
1049
1050        info!("Transaction started: {}", transaction.id);
1051        Ok(transaction)
1052    }
1053
1054    #[instrument(skip(self, transaction))]
1055    async fn commit_transaction(&self, mut transaction: Transaction) -> StorageResult<()> {
1056        debug!("Committing transaction: {}", transaction.id);
1057
1058        let mut transactions = self.transactions.write().await;
1059        let context = transactions.remove(&transaction.id).ok_or_else(|| {
1060            StorageError::TransactionError {
1061                message: format!("Transaction not found: {}", transaction.id),
1062            }
1063        })?;
1064
1065        // Start SQL transaction
1066        let mut tx = self.pool.begin().await.map_err(|e| {
1067            error!("Failed to begin SQL transaction: {}", e);
1068            StorageError::TransactionError {
1069                message: format!("Failed to begin transaction: {}", e),
1070            }
1071        })?;
1072
1073        // Execute all operations
1074        for operation in &context.operations {
1075            match operation {
1076                Operation::Insert { table, data } => {
1077                    let entry: serde_json::Value = serde_json::from_slice(data).map_err(|e| {
1078                        StorageError::DeserializationError {
1079                            source: Box::new(e),
1080                        }
1081                    })?;
1082
1083                    let key = entry.get("key")
1084                        .and_then(|k| k.as_str())
1085                        .ok_or_else(|| StorageError::QueryError {
1086                            message: "Missing key in insert operation".to_string(),
1087                        })?;
1088
1089                    sqlx::query(
1090                        r#"
1091                        INSERT INTO storage_entries (table_name, key, value, version, created_at, updated_at)
1092                        VALUES ($1, $2, $3, 1, NOW(), NOW())
1093                        "#,
1094                    )
1095                    .bind(table)
1096                    .bind(key)
1097                    .bind(&entry)
1098                    .execute(&mut *tx)
1099                    .await
1100                    .map_err(|e| StorageError::QueryError {
1101                        message: format!("Transaction insert failed: {}", e),
1102                    })?;
1103                }
1104                Operation::Update { table, key, data } => {
1105                    let value: serde_json::Value = serde_json::from_slice(data).map_err(|e| {
1106                        StorageError::DeserializationError {
1107                            source: Box::new(e),
1108                        }
1109                    })?;
1110
1111                    sqlx::query(
1112                        r#"
1113                        UPDATE storage_entries
1114                        SET value = $3, version = version + 1, updated_at = NOW()
1115                        WHERE table_name = $1 AND key = $2
1116                        "#,
1117                    )
1118                    .bind(table)
1119                    .bind(key)
1120                    .bind(&value)
1121                    .execute(&mut *tx)
1122                    .await
1123                    .map_err(|e| StorageError::QueryError {
1124                        message: format!("Transaction update failed: {}", e),
1125                    })?;
1126                }
1127                Operation::Delete { table, key } => {
1128                    sqlx::query(
1129                        r#"
1130                        DELETE FROM storage_entries
1131                        WHERE table_name = $1 AND key = $2
1132                        "#,
1133                    )
1134                    .bind(table)
1135                    .bind(key)
1136                    .execute(&mut *tx)
1137                    .await
1138                    .map_err(|e| StorageError::QueryError {
1139                        message: format!("Transaction delete failed: {}", e),
1140                    })?;
1141                }
1142            }
1143        }
1144
1145        // Commit SQL transaction
1146        tx.commit().await.map_err(|e| {
1147            error!("Failed to commit SQL transaction: {}", e);
1148            StorageError::TransactionError {
1149                message: format!("Failed to commit: {}", e),
1150            }
1151        })?;
1152
1153        transaction.state = TransactionState::Committed;
1154        info!("Transaction committed: {}", transaction.id);
1155        Ok(())
1156    }
1157
1158    #[instrument(skip(self, transaction))]
1159    async fn rollback_transaction(&self, mut transaction: Transaction) -> StorageResult<()> {
1160        debug!("Rolling back transaction: {}", transaction.id);
1161
1162        let mut transactions = self.transactions.write().await;
1163        transactions.remove(&transaction.id);
1164
1165        transaction.state = TransactionState::RolledBack;
1166        info!("Transaction rolled back: {}", transaction.id);
1167        Ok(())
1168    }
1169
1170    #[instrument(skip(self))]
1171    async fn scan_prefix(&self, table: &str, prefix: &str) -> StorageResult<Vec<String>> {
1172        debug!("Scanning keys with prefix: table={}, prefix={}", table, prefix);
1173
1174        let start = std::time::Instant::now();
1175
1176        let pattern = format!("{}%", prefix);
1177
1178        let rows: Vec<(String,)> = sqlx::query_as(
1179            r#"
1180            SELECT key
1181            FROM storage_entries
1182            WHERE table_name = $1 AND key LIKE $2
1183            AND (expires_at IS NULL OR expires_at > NOW())
1184            ORDER BY key
1185            "#,
1186        )
1187        .bind(table)
1188        .bind(&pattern)
1189        .fetch_all(&self.pool)
1190        .await
1191        .map_err(|e| {
1192            error!("Failed to scan prefix: {}", e);
1193            StorageError::QueryError {
1194                message: format!("Prefix scan failed: {}", e),
1195            }
1196        })?;
1197
1198        let keys: Vec<String> = rows.into_iter().map(|(key,)| key).collect();
1199
1200        let duration = start.elapsed();
1201        self.record_operation(true, duration, 0).await;
1202
1203        debug!("Prefix scan returned {} keys in {:?}", keys.len(), duration);
1204        Ok(keys)
1205    }
1206
1207    #[instrument(skip(self, keys))]
1208    async fn get_multi<T: DeserializeOwned + Serialize + Send + Sync>(
1209        &self,
1210        table: &str,
1211        keys: Vec<String>,
1212    ) -> StorageResult<Vec<Option<StorageEntry<T>>>> {
1213        debug!("Getting multiple entries: table={}, count={}", table, keys.len());
1214
1215        if keys.is_empty() {
1216            return Ok(Vec::new());
1217        }
1218
1219        let start = std::time::Instant::now();
1220
1221        let mut results = Vec::new();
1222
1223        for key in keys {
1224            let entry = self.get::<T>(table, &key).await?;
1225            results.push(entry);
1226        }
1227
1228        let duration = start.elapsed();
1229        debug!("Multi-get completed in {:?}", duration);
1230        Ok(results)
1231    }
1232
1233    #[instrument(skip(self, keys))]
1234    async fn delete_multi(&self, table: &str, keys: Vec<String>) -> StorageResult<()> {
1235        debug!("Deleting multiple entries: table={}, count={}", table, keys.len());
1236
1237        if keys.is_empty() {
1238            return Ok(());
1239        }
1240
1241        let start = std::time::Instant::now();
1242
1243        // Build placeholders for IN clause
1244        let placeholders: Vec<String> = (1..=keys.len())
1245            .map(|i| format!("${}", i + 1))
1246            .collect();
1247
1248        let sql = format!(
1249            r#"
1250            DELETE FROM storage_entries
1251            WHERE table_name = $1 AND key IN ({})
1252            "#,
1253            placeholders.join(", ")
1254        );
1255
1256        let mut query = sqlx::query(&sql).bind(table);
1257
1258        for key in keys {
1259            query = query.bind(key);
1260        }
1261
1262        let result = query.execute(&self.pool).await.map_err(|e| {
1263            error!("Failed to delete multiple entries: {}", e);
1264            StorageError::QueryError {
1265                message: format!("Multi-delete failed: {}", e),
1266            }
1267        })?;
1268
1269        let duration = start.elapsed();
1270        self.record_operation(true, duration, 0).await;
1271
1272        info!("Deleted {} entries in {:?}", result.rows_affected(), duration);
1273        Ok(())
1274    }
1275
1276    #[instrument(skip(self, new_value))]
1277    async fn compare_and_swap<T: Serialize + Send + Sync>(
1278        &self,
1279        table: &str,
1280        key: &str,
1281        expected_version: u64,
1282        new_value: &T,
1283    ) -> StorageResult<bool> {
1284        debug!(
1285            "Compare-and-swap: table={}, key={}, expected_version={}",
1286            table, key, expected_version
1287        );
1288
1289        let start = std::time::Instant::now();
1290
1291        let value_json = serde_json::to_value(new_value).map_err(|e| {
1292            StorageError::SerializationError {
1293                source: Box::new(e),
1294            }
1295        })?;
1296
1297        let result = sqlx::query(
1298            r#"
1299            UPDATE storage_entries
1300            SET value = $3, version = version + 1, updated_at = NOW()
1301            WHERE table_name = $1 AND key = $2 AND version = $4
1302            "#,
1303        )
1304        .bind(table)
1305        .bind(key)
1306        .bind(&value_json)
1307        .bind(expected_version as i64)
1308        .execute(&self.pool)
1309        .await
1310        .map_err(|e| {
1311            error!("Failed to compare-and-swap: {}", e);
1312            StorageError::QueryError {
1313                message: format!("CAS failed: {}", e),
1314            }
1315        })?;
1316
1317        let success = result.rows_affected() > 0;
1318
1319        let duration = start.elapsed();
1320        self.record_operation(true, duration, 0).await;
1321
1322        debug!("Compare-and-swap completed in {:?}: {}", duration, success);
1323        Ok(success)
1324    }
1325
1326    #[instrument(skip(self))]
1327    async fn get_modified_since<T: DeserializeOwned + Send + Sync + 'static>(
1328        &self,
1329        table: &str,
1330        since: DateTime<Utc>,
1331    ) -> StorageResult<Vec<StorageEntry<T>>> {
1332        debug!("Getting entries modified since: table={}, since={}", table, since);
1333
1334        let start = std::time::Instant::now();
1335
1336        let rows = sqlx::query(
1337            r#"
1338            SELECT key, value, version, created_at, updated_at, expires_at, metadata
1339            FROM storage_entries
1340            WHERE table_name = $1 AND updated_at > $2
1341            AND (expires_at IS NULL OR expires_at > NOW())
1342            ORDER BY updated_at ASC
1343            "#,
1344        )
1345        .bind(table)
1346        .bind(since)
1347        .fetch_all(&self.pool)
1348        .await
1349        .map_err(|e| {
1350            error!("Failed to get modified entries: {}", e);
1351            StorageError::QueryError {
1352                message: format!("Get modified since failed: {}", e),
1353            }
1354        })?;
1355
1356        let mut results = Vec::new();
1357        for row in rows {
1358            let entry = self.parse_row::<T>(&row)?;
1359            results.push(entry);
1360        }
1361
1362        let duration = start.elapsed();
1363        self.record_operation(true, duration, 0).await;
1364
1365        debug!("Found {} modified entries in {:?}", results.len(), duration);
1366        Ok(results)
1367    }
1368
1369    #[instrument(skip(self))]
1370    async fn get_expiring_before<T: DeserializeOwned + Send + Sync + 'static>(
1371        &self,
1372        table: &str,
1373        before: DateTime<Utc>,
1374    ) -> StorageResult<Vec<StorageEntry<T>>> {
1375        debug!("Getting entries expiring before: table={}, before={}", table, before);
1376
1377        let start = std::time::Instant::now();
1378
1379        let rows = sqlx::query(
1380            r#"
1381            SELECT key, value, version, created_at, updated_at, expires_at, metadata
1382            FROM storage_entries
1383            WHERE table_name = $1 AND expires_at IS NOT NULL AND expires_at < $2
1384            ORDER BY expires_at ASC
1385            "#,
1386        )
1387        .bind(table)
1388        .bind(before)
1389        .fetch_all(&self.pool)
1390        .await
1391        .map_err(|e| {
1392            error!("Failed to get expiring entries: {}", e);
1393            StorageError::QueryError {
1394                message: format!("Get expiring before failed: {}", e),
1395            }
1396        })?;
1397
1398        let mut results = Vec::new();
1399        for row in rows {
1400            let entry = self.parse_row::<T>(&row)?;
1401            results.push(entry);
1402        }
1403
1404        let duration = start.elapsed();
1405        self.record_operation(true, duration, 0).await;
1406
1407        debug!("Found {} expiring entries in {:?}", results.len(), duration);
1408        Ok(results)
1409    }
1410
1411    #[instrument(skip(self))]
1412    async fn cleanup_expired(&self, table: &str) -> StorageResult<usize> {
1413        debug!("Cleaning up expired entries in table: {}", table);
1414
1415        let start = std::time::Instant::now();
1416
1417        let result = sqlx::query(
1418            r#"
1419            DELETE FROM storage_entries
1420            WHERE table_name = $1 AND expires_at IS NOT NULL AND expires_at < NOW()
1421            "#,
1422        )
1423        .bind(table)
1424        .execute(&self.pool)
1425        .await
1426        .map_err(|e| {
1427            error!("Failed to cleanup expired entries: {}", e);
1428            StorageError::QueryError {
1429                message: format!("Cleanup failed: {}", e),
1430            }
1431        })?;
1432
1433        let count = result.rows_affected() as usize;
1434
1435        let duration = start.elapsed();
1436        self.record_operation(true, duration, 0).await;
1437
1438        info!("Cleaned up {} expired entries in {:?}", count, duration);
1439        Ok(count)
1440    }
1441
1442    #[instrument(skip(self))]
1443    async fn compact(&self) -> StorageResult<()> {
1444        info!("Running VACUUM on database");
1445
1446        let start = std::time::Instant::now();
1447
1448        // Run VACUUM ANALYZE to reclaim space and update statistics
1449        sqlx::query("VACUUM ANALYZE storage_entries")
1450            .execute(&self.pool)
1451            .await
1452            .map_err(|e| {
1453                error!("Failed to vacuum database: {}", e);
1454                StorageError::QueryError {
1455                    message: format!("Vacuum failed: {}", e),
1456                }
1457            })?;
1458
1459        let duration = start.elapsed();
1460        info!("Database vacuumed in {:?}", duration);
1461        Ok(())
1462    }
1463
1464    #[instrument(skip(self))]
1465    async fn flush(&self) -> StorageResult<()> {
1466        debug!("Flushing pending writes (no-op for PostgreSQL)");
1467        // PostgreSQL handles flushing automatically
1468        Ok(())
1469    }
1470
1471    #[instrument(skip(self))]
1472    async fn initialize(&mut self) -> StorageResult<()> {
1473        info!("Initializing PostgreSQL storage");
1474
1475        let mut initialized = self.initialized.write().await;
1476        if *initialized {
1477            warn!("Storage already initialized");
1478            return Ok(());
1479        }
1480
1481        // Initialize schema
1482        self.initialize_schema().await?;
1483
1484        // Run migrations if enabled
1485        if self.config.enable_migrations {
1486            info!("Running migrations");
1487            // Migration logic would go here
1488        }
1489
1490        *initialized = true;
1491        info!("PostgreSQL storage initialized successfully");
1492        Ok(())
1493    }
1494
1495    #[instrument(skip(self))]
1496    async fn shutdown(&mut self) -> StorageResult<()> {
1497        info!("Shutting down PostgreSQL storage");
1498
1499        // Close connection pool
1500        self.pool.close().await;
1501
1502        let mut initialized = self.initialized.write().await;
1503        *initialized = false;
1504
1505        info!("PostgreSQL storage shutdown complete");
1506        Ok(())
1507    }
1508}
1509
1510#[async_trait]
1511impl RelationalStorage for PostgreSQLStorage {
1512    #[instrument(skip(self, params))]
1513    async fn execute_sql(&self, sql: &str, params: Vec<SqlParam>) -> StorageResult<SqlResult> {
1514        debug!("Executing SQL: {}", sql);
1515
1516        let start = std::time::Instant::now();
1517
1518        let mut query = sqlx::query(sql);
1519
1520        for param in params {
1521            query = match param {
1522                SqlParam::String(s) => query.bind(s),
1523                SqlParam::Integer(i) => query.bind(i),
1524                SqlParam::Float(f) => query.bind(f),
1525                SqlParam::Boolean(b) => query.bind(b),
1526                SqlParam::DateTime(dt) => query.bind(dt),
1527                SqlParam::Null => query.bind(None::<String>),
1528            };
1529        }
1530
1531        let result = query.execute(&self.pool).await.map_err(|e| {
1532            error!("Failed to execute SQL: {}", e);
1533            StorageError::QueryError {
1534                message: format!("SQL execution failed: {}", e),
1535            }
1536        })?;
1537
1538        let duration = start.elapsed();
1539        self.record_operation(true, duration, 0).await;
1540
1541        debug!("SQL executed in {:?}, rows affected: {}", duration, result.rows_affected());
1542        Ok(SqlResult {
1543            rows_affected: result.rows_affected(),
1544        })
1545    }
1546
1547    #[instrument(skip(self, params))]
1548    async fn query_sql<T: DeserializeOwned + Send + Sync>(
1549        &self,
1550        sql: &str,
1551        params: Vec<SqlParam>,
1552    ) -> StorageResult<Vec<T>> {
1553        debug!("Querying SQL: {}", sql);
1554
1555        let start = std::time::Instant::now();
1556
1557        let mut query = sqlx::query(sql);
1558
1559        for param in params {
1560            query = match param {
1561                SqlParam::String(s) => query.bind(s),
1562                SqlParam::Integer(i) => query.bind(i),
1563                SqlParam::Float(f) => query.bind(f),
1564                SqlParam::Boolean(b) => query.bind(b),
1565                SqlParam::DateTime(dt) => query.bind(dt),
1566                SqlParam::Null => query.bind(None::<String>),
1567            };
1568        }
1569
1570        let rows = query.fetch_all(&self.pool).await.map_err(|e| {
1571            error!("Failed to query SQL: {}", e);
1572            StorageError::QueryError {
1573                message: format!("SQL query failed: {}", e),
1574            }
1575        })?;
1576
1577        let mut results = Vec::new();
1578        for row in rows {
1579            // Extract the value column as JSON and deserialize it
1580            let value_json: serde_json::Value = row.try_get("value").map_err(|e| {
1581                StorageError::QueryError {
1582                    message: format!("Failed to get value column: {}", e),
1583                }
1584            })?;
1585
1586            let result: T = serde_json::from_value(value_json).map_err(|e| {
1587                StorageError::DeserializationError {
1588                    source: Box::new(e),
1589                }
1590            })?;
1591
1592            results.push(result);
1593        }
1594
1595        let duration = start.elapsed();
1596        self.record_operation(true, duration, 0).await;
1597
1598        debug!("SQL query returned {} rows in {:?}", results.len(), duration);
1599        Ok(results)
1600    }
1601
1602    #[instrument(skip(self, columns))]
1603    async fn create_index(
1604        &self,
1605        table: &str,
1606        index_name: &str,
1607        columns: Vec<String>,
1608        unique: bool,
1609    ) -> StorageResult<()> {
1610        info!("Creating index: {} on table: {}", index_name, table);
1611
1612        let unique_clause = if unique { "UNIQUE" } else { "" };
1613        let columns_clause = columns.join(", ");
1614
1615        let sql = format!(
1616            "CREATE {} INDEX IF NOT EXISTS {} ON {} ({})",
1617            unique_clause, index_name, table, columns_clause
1618        );
1619
1620        sqlx::query(&sql).execute(&self.pool).await.map_err(|e| {
1621            error!("Failed to create index: {}", e);
1622            StorageError::QueryError {
1623                message: format!("Index creation failed: {}", e),
1624            }
1625        })?;
1626
1627        info!("Index created successfully: {}", index_name);
1628        Ok(())
1629    }
1630
1631    #[instrument(skip(self))]
1632    async fn drop_index(&self, index_name: &str) -> StorageResult<()> {
1633        info!("Dropping index: {}", index_name);
1634
1635        let sql = format!("DROP INDEX IF EXISTS {}", index_name);
1636
1637        sqlx::query(&sql).execute(&self.pool).await.map_err(|e| {
1638            error!("Failed to drop index: {}", e);
1639            StorageError::QueryError {
1640                message: format!("Index drop failed: {}", e),
1641            }
1642        })?;
1643
1644        info!("Index dropped successfully: {}", index_name);
1645        Ok(())
1646    }
1647
1648    #[instrument(skip(self))]
1649    async fn vacuum(&self, table: &str) -> StorageResult<()> {
1650        info!("Vacuuming table: {}", table);
1651
1652        let sql = format!("VACUUM ANALYZE {}", table);
1653
1654        sqlx::query(&sql).execute(&self.pool).await.map_err(|e| {
1655            error!("Failed to vacuum table: {}", e);
1656            StorageError::QueryError {
1657                message: format!("Vacuum failed: {}", e),
1658            }
1659        })?;
1660
1661        info!("Table vacuumed successfully: {}", table);
1662        Ok(())
1663    }
1664
1665    #[instrument(skip(self))]
1666    async fn analyze(&self, table: &str) -> StorageResult<()> {
1667        info!("Analyzing table: {}", table);
1668
1669        let sql = format!("ANALYZE {}", table);
1670
1671        sqlx::query(&sql).execute(&self.pool).await.map_err(|e| {
1672            error!("Failed to analyze table: {}", e);
1673            StorageError::QueryError {
1674                message: format!("Analyze failed: {}", e),
1675            }
1676        })?;
1677
1678        info!("Table analyzed successfully: {}", table);
1679        Ok(())
1680    }
1681}
1682
1683#[cfg(test)]
1684mod tests {
1685    use super::*;
1686    use serde::{Deserialize, Serialize};
1687
1688    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1689    struct TestData {
1690        id: String,
1691        value: i32,
1692        name: String,
1693    }
1694
1695    async fn create_test_storage() -> PostgreSQLStorage {
1696        let config = PostgreSQLConfig {
1697            host: "localhost".to_string(),
1698            port: 5432,
1699            database: "test_llm_optimizer".to_string(),
1700            username: "postgres".to_string(),
1701            password: "postgres".to_string(),
1702            ..Default::default()
1703        };
1704
1705        let mut storage = PostgreSQLStorage::new(config)
1706            .await
1707            .expect("Failed to create storage");
1708
1709        storage.initialize().await.expect("Failed to initialize");
1710        storage
1711    }
1712
1713    #[tokio::test]
1714    async fn test_backend_type() {
1715        let storage = create_test_storage().await;
1716        assert_eq!(storage.backend(), StorageBackend::PostgreSQL);
1717    }
1718
1719    #[tokio::test]
1720    async fn test_health_check() {
1721        let storage = create_test_storage().await;
1722        let health = storage.health_check().await.expect("Health check failed");
1723        assert!(matches!(health, StorageHealth::Healthy | StorageHealth::Degraded));
1724    }
1725
1726    #[tokio::test]
1727    async fn test_insert_and_get() {
1728        let storage = create_test_storage().await;
1729
1730        let test_data = TestData {
1731            id: "test1".to_string(),
1732            value: 42,
1733            name: "Test Entry".to_string(),
1734        };
1735
1736        storage
1737            .insert("test_table", "test_key1", &test_data)
1738            .await
1739            .expect("Insert failed");
1740
1741        let entry: Option<StorageEntry<TestData>> = storage
1742            .get("test_table", "test_key1")
1743            .await
1744            .expect("Get failed");
1745
1746        assert!(entry.is_some());
1747        let entry = entry.unwrap();
1748        assert_eq!(entry.key, "test_key1");
1749        assert_eq!(entry.value.id, "test1");
1750        assert_eq!(entry.value.value, 42);
1751        assert_eq!(entry.version, 1);
1752    }
1753
1754    #[tokio::test]
1755    async fn test_insert_duplicate_fails() {
1756        let storage = create_test_storage().await;
1757
1758        let test_data = TestData {
1759            id: "test2".to_string(),
1760            value: 100,
1761            name: "Duplicate Test".to_string(),
1762        };
1763
1764        storage
1765            .insert("test_table", "dup_key", &test_data)
1766            .await
1767            .expect("First insert failed");
1768
1769        let result = storage.insert("test_table", "dup_key", &test_data).await;
1770        assert!(result.is_err());
1771        assert!(matches!(result.unwrap_err(), StorageError::AlreadyExists { .. }));
1772    }
1773
1774    #[tokio::test]
1775    async fn test_update() {
1776        let storage = create_test_storage().await;
1777
1778        let test_data = TestData {
1779            id: "test3".to_string(),
1780            value: 10,
1781            name: "Original".to_string(),
1782        };
1783
1784        storage
1785            .insert("test_table", "update_key", &test_data)
1786            .await
1787            .expect("Insert failed");
1788
1789        let updated_data = TestData {
1790            id: "test3".to_string(),
1791            value: 20,
1792            name: "Updated".to_string(),
1793        };
1794
1795        storage
1796            .update("test_table", "update_key", &updated_data)
1797            .await
1798            .expect("Update failed");
1799
1800        let entry: Option<StorageEntry<TestData>> = storage
1801            .get("test_table", "update_key")
1802            .await
1803            .expect("Get failed");
1804
1805        assert!(entry.is_some());
1806        let entry = entry.unwrap();
1807        assert_eq!(entry.value.value, 20);
1808        assert_eq!(entry.value.name, "Updated");
1809        assert_eq!(entry.version, 2);
1810    }
1811
1812    #[tokio::test]
1813    async fn test_update_versioned() {
1814        let storage = create_test_storage().await;
1815
1816        let test_data = TestData {
1817            id: "test4".to_string(),
1818            value: 100,
1819            name: "Versioned".to_string(),
1820        };
1821
1822        storage
1823            .insert("test_table", "version_key", &test_data)
1824            .await
1825            .expect("Insert failed");
1826
1827        let updated_data = TestData {
1828            id: "test4".to_string(),
1829            value: 200,
1830            name: "Versioned Updated".to_string(),
1831        };
1832
1833        // Update with correct version should succeed
1834        storage
1835            .update_versioned("test_table", "version_key", &updated_data, 1)
1836            .await
1837            .expect("Versioned update failed");
1838
1839        // Update with wrong version should fail
1840        let result = storage
1841            .update_versioned("test_table", "version_key", &updated_data, 1)
1842            .await;
1843
1844        assert!(result.is_err());
1845        assert!(matches!(result.unwrap_err(), StorageError::ConstraintViolation { .. }));
1846    }
1847
1848    #[tokio::test]
1849    async fn test_delete() {
1850        let storage = create_test_storage().await;
1851
1852        let test_data = TestData {
1853            id: "test5".to_string(),
1854            value: 50,
1855            name: "To Delete".to_string(),
1856        };
1857
1858        storage
1859            .insert("test_table", "delete_key", &test_data)
1860            .await
1861            .expect("Insert failed");
1862
1863        storage
1864            .delete("test_table", "delete_key")
1865            .await
1866            .expect("Delete failed");
1867
1868        let entry: Option<StorageEntry<TestData>> = storage
1869            .get("test_table", "delete_key")
1870            .await
1871            .expect("Get failed");
1872
1873        assert!(entry.is_none());
1874    }
1875
1876    #[tokio::test]
1877    async fn test_exists() {
1878        let storage = create_test_storage().await;
1879
1880        let test_data = TestData {
1881            id: "test6".to_string(),
1882            value: 60,
1883            name: "Exists Test".to_string(),
1884        };
1885
1886        storage
1887            .insert("test_table", "exists_key", &test_data)
1888            .await
1889            .expect("Insert failed");
1890
1891        let exists = storage
1892            .exists("test_table", "exists_key")
1893            .await
1894            .expect("Exists check failed");
1895        assert!(exists);
1896
1897        let not_exists = storage
1898            .exists("test_table", "nonexistent_key")
1899            .await
1900            .expect("Exists check failed");
1901        assert!(!not_exists);
1902    }
1903
1904    #[tokio::test]
1905    async fn test_insert_with_ttl() {
1906        let storage = create_test_storage().await;
1907
1908        let test_data = TestData {
1909            id: "test7".to_string(),
1910            value: 70,
1911            name: "TTL Test".to_string(),
1912        };
1913
1914        storage
1915            .insert_with_ttl("test_table", "ttl_key", &test_data, 2)
1916            .await
1917            .expect("Insert with TTL failed");
1918
1919        let entry: Option<StorageEntry<TestData>> = storage
1920            .get("test_table", "ttl_key")
1921            .await
1922            .expect("Get failed");
1923
1924        assert!(entry.is_some());
1925        let entry = entry.unwrap();
1926        assert!(entry.expires_at.is_some());
1927
1928        // Wait for expiration
1929        tokio::time::sleep(std::time::Duration::from_secs(3)).await;
1930
1931        let expired_entry: Option<StorageEntry<TestData>> = storage
1932            .get("test_table", "ttl_key")
1933            .await
1934            .expect("Get failed");
1935
1936        assert!(expired_entry.is_none());
1937    }
1938
1939    #[tokio::test]
1940    async fn test_scan_prefix() {
1941        let storage = create_test_storage().await;
1942
1943        for i in 0..5 {
1944            let test_data = TestData {
1945                id: format!("prefix_{}", i),
1946                value: i,
1947                name: format!("Prefix {}", i),
1948            };
1949
1950            storage
1951                .insert("test_table", &format!("prefix_{}", i), &test_data)
1952                .await
1953                .expect("Insert failed");
1954        }
1955
1956        let keys = storage
1957            .scan_prefix("test_table", "prefix_")
1958            .await
1959            .expect("Scan prefix failed");
1960
1961        assert!(keys.len() >= 5);
1962        assert!(keys.iter().all(|k| k.starts_with("prefix_")));
1963    }
1964
1965    #[tokio::test]
1966    async fn test_compare_and_swap() {
1967        let storage = create_test_storage().await;
1968
1969        let test_data = TestData {
1970            id: "test8".to_string(),
1971            value: 80,
1972            name: "CAS Test".to_string(),
1973        };
1974
1975        storage
1976            .insert("test_table", "cas_key", &test_data)
1977            .await
1978            .expect("Insert failed");
1979
1980        let new_data = TestData {
1981            id: "test8".to_string(),
1982            value: 81,
1983            name: "CAS Updated".to_string(),
1984        };
1985
1986        // CAS with correct version should succeed
1987        let success = storage
1988            .compare_and_swap("test_table", "cas_key", 1, &new_data)
1989            .await
1990            .expect("CAS failed");
1991        assert!(success);
1992
1993        // CAS with wrong version should fail
1994        let failure = storage
1995            .compare_and_swap("test_table", "cas_key", 1, &new_data)
1996            .await
1997            .expect("CAS failed");
1998        assert!(!failure);
1999    }
2000
2001    #[tokio::test]
2002    async fn test_batch_operations() {
2003        let storage = create_test_storage().await;
2004
2005        let mut batch = Batch::new(10);
2006
2007        for i in 0..5 {
2008            let test_data = TestData {
2009                id: format!("batch_{}", i),
2010                value: i,
2011                name: format!("Batch {}", i),
2012            };
2013
2014            let data = serde_json::to_vec(&test_data).unwrap();
2015            batch.add(Operation::Insert {
2016                table: "test_table".to_string(),
2017                data,
2018            }).expect("Failed to add to batch");
2019        }
2020
2021        storage
2022            .execute_batch(batch)
2023            .await
2024            .expect("Batch execution failed");
2025
2026        // Verify entries were inserted
2027        for i in 0..5 {
2028            let entry: Option<StorageEntry<TestData>> = storage
2029                .get("test_table", &format!("batch_{}", i))
2030                .await
2031                .expect("Get failed");
2032            assert!(entry.is_some());
2033        }
2034    }
2035
2036    #[tokio::test]
2037    async fn test_transaction_commit() {
2038        let storage = create_test_storage().await;
2039
2040        let transaction = storage
2041            .begin_transaction()
2042            .await
2043            .expect("Begin transaction failed");
2044
2045        storage
2046            .commit_transaction(transaction)
2047            .await
2048            .expect("Commit failed");
2049    }
2050
2051    #[tokio::test]
2052    async fn test_transaction_rollback() {
2053        let storage = create_test_storage().await;
2054
2055        let transaction = storage
2056            .begin_transaction()
2057            .await
2058            .expect("Begin transaction failed");
2059
2060        storage
2061            .rollback_transaction(transaction)
2062            .await
2063            .expect("Rollback failed");
2064    }
2065
2066    #[tokio::test]
2067    async fn test_get_modified_since() {
2068        let storage = create_test_storage().await;
2069
2070        let now = Utc::now();
2071
2072        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
2073
2074        let test_data = TestData {
2075            id: "test9".to_string(),
2076            value: 90,
2077            name: "Modified Test".to_string(),
2078        };
2079
2080        storage
2081            .insert("test_table", "modified_key", &test_data)
2082            .await
2083            .expect("Insert failed");
2084
2085        let entries: Vec<StorageEntry<TestData>> = storage
2086            .get_modified_since("test_table", now)
2087            .await
2088            .expect("Get modified since failed");
2089
2090        assert!(!entries.is_empty());
2091    }
2092
2093    #[tokio::test]
2094    async fn test_cleanup_expired() {
2095        let storage = create_test_storage().await;
2096
2097        let test_data = TestData {
2098            id: "test10".to_string(),
2099            value: 100,
2100            name: "Cleanup Test".to_string(),
2101        };
2102
2103        storage
2104            .insert_with_ttl("test_table", "cleanup_key", &test_data, 1)
2105            .await
2106            .expect("Insert with TTL failed");
2107
2108        tokio::time::sleep(std::time::Duration::from_secs(2)).await;
2109
2110        let count = storage
2111            .cleanup_expired("test_table")
2112            .await
2113            .expect("Cleanup failed");
2114
2115        assert!(count >= 1);
2116    }
2117
2118    #[tokio::test]
2119    async fn test_metadata() {
2120        let storage = create_test_storage().await;
2121
2122        let metadata = storage.metadata().await.expect("Metadata failed");
2123
2124        assert_eq!(metadata.backend, StorageBackend::PostgreSQL);
2125        assert!(!metadata.capabilities.is_empty());
2126        assert!(metadata.version.contains("PostgreSQL"));
2127    }
2128
2129    #[tokio::test]
2130    async fn test_stats() {
2131        let storage = create_test_storage().await;
2132
2133        let stats = storage.stats().await.expect("Stats failed");
2134
2135        assert!(stats.active_connections > 0);
2136    }
2137}