mockforge_vbr/
database.rs

1//! Virtual database abstraction
2//!
3//! This module provides a virtual database abstraction trait that supports multiple
4//! storage backends: SQLite (persistent, production-like), JSON files (human-readable),
5//! and in-memory (fast, no persistence).
6
7use crate::{Error, Result};
8use async_trait::async_trait;
9use serde_json::Value;
10use sqlx::{Column, Row};
11use std::collections::HashMap;
12use std::sync::Arc;
13use tokio::sync::RwLock;
14
15/// Virtual database abstraction trait
16///
17/// This trait allows the VBR engine to work with different storage backends
18/// transparently, supporting SQLite, JSON files, and in-memory storage.
19#[async_trait]
20pub trait VirtualDatabase: Send + Sync {
21    /// Initialize the database and create necessary tables/schemas
22    async fn initialize(&mut self) -> Result<()>;
23
24    /// Execute a query that returns rows (SELECT)
25    async fn query(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>>;
26
27    /// Execute a query that modifies data (INSERT, UPDATE, DELETE)
28    async fn execute(&self, query: &str, params: &[Value]) -> Result<u64>;
29
30    /// Execute a query and return the last inserted row ID
31    async fn execute_with_id(&self, query: &str, params: &[Value]) -> Result<String>;
32
33    /// Check if a table exists
34    async fn table_exists(&self, table_name: &str) -> Result<bool>;
35
36    /// Create a table from a CREATE TABLE statement
37    async fn create_table(&self, create_statement: &str) -> Result<()>;
38
39    /// Get database connection information (for debugging)
40    fn connection_info(&self) -> String;
41
42    /// Close the database connection (cleanup)
43    async fn close(&mut self) -> Result<()>;
44}
45
46/// Create a virtual database instance based on the storage backend configuration
47pub async fn create_database(
48    backend: &crate::config::StorageBackend,
49) -> Result<std::sync::Arc<dyn VirtualDatabase + Send + Sync>> {
50    use std::sync::Arc;
51    match backend {
52        crate::config::StorageBackend::Sqlite { path } => {
53            let mut db = SqliteDatabase::new(path.clone()).await?;
54            db.initialize().await?;
55            Ok(Arc::new(db))
56        }
57        crate::config::StorageBackend::Json { path } => {
58            let mut db = JsonDatabase::new(path.clone()).await?;
59            db.initialize().await?;
60            Ok(Arc::new(db))
61        }
62        crate::config::StorageBackend::Memory => {
63            let mut db = InMemoryDatabase::new().await?;
64            db.initialize().await?;
65            Ok(Arc::new(db))
66        }
67    }
68}
69
70/// SQLite database backend implementation
71pub struct SqliteDatabase {
72    pool: sqlx::SqlitePool,
73    path: std::path::PathBuf,
74}
75
76impl SqliteDatabase {
77    /// Create a new SQLite database connection
78    pub async fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
79        let path = path.as_ref().to_path_buf();
80
81        // Ensure parent directory exists
82        if let Some(parent) = path.parent() {
83            tokio::fs::create_dir_all(parent).await.map_err(|e| {
84                Error::generic(format!("Failed to create database directory: {}", e))
85            })?;
86        }
87
88        let db_url = format!("sqlite://{}", path.display());
89        let pool = sqlx::sqlite::SqlitePoolOptions::new()
90            .max_connections(10)
91            .connect(&db_url)
92            .await
93            .map_err(|e| Error::generic(format!("Failed to connect to SQLite database: {}", e)))?;
94
95        // Enable WAL mode for better concurrency
96        sqlx::query("PRAGMA journal_mode = WAL")
97            .execute(&pool)
98            .await
99            .map_err(|e| Error::generic(format!("Failed to enable WAL mode: {}", e)))?;
100
101        // Enable foreign keys
102        sqlx::query("PRAGMA foreign_keys = ON")
103            .execute(&pool)
104            .await
105            .map_err(|e| Error::generic(format!("Failed to enable foreign keys: {}", e)))?;
106
107        Ok(Self { pool, path })
108    }
109}
110
111#[async_trait]
112impl VirtualDatabase for SqliteDatabase {
113    async fn initialize(&mut self) -> Result<()> {
114        // SQLite databases are initialized on connection
115        // Additional initialization can be done here if needed
116        Ok(())
117    }
118
119    async fn query(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>> {
120        use sqlx::Row;
121
122        // For now, use a simple approach - bind parameters one by one
123        // This is a simplified implementation; full implementation would handle
124        // parameterized queries more robustly
125        let mut query_builder = sqlx::query(query);
126
127        // Bind parameters based on their type
128        for param in params {
129            query_builder = match param {
130                Value::String(s) => query_builder.bind(s),
131                Value::Number(n) => {
132                    if let Some(i) = n.as_i64() {
133                        query_builder.bind(i)
134                    } else if let Some(f) = n.as_f64() {
135                        query_builder.bind(f)
136                    } else {
137                        query_builder.bind(n.to_string())
138                    }
139                }
140                Value::Bool(b) => query_builder.bind(*b),
141                Value::Null => query_builder.bind::<Option<String>>(None),
142                Value::Array(_) | Value::Object(_) => {
143                    let json_str = serde_json::to_string(param).unwrap_or_default();
144                    query_builder.bind(json_str)
145                }
146            };
147        }
148
149        let rows = query_builder
150            .fetch_all(&self.pool)
151            .await
152            .map_err(|e| Error::generic(format!("Query execution failed: {}", e)))?;
153
154        // Convert rows to HashMap
155        let mut results = Vec::new();
156        for row in rows {
157            let mut map = HashMap::new();
158            let columns = row.columns();
159            for (idx, column) in columns.iter().enumerate() {
160                let value = row_value_to_json(&row, idx)?;
161                map.insert(column.name().to_string(), value);
162            }
163            results.push(map);
164        }
165
166        Ok(results)
167    }
168
169    async fn execute(&self, query: &str, params: &[Value]) -> Result<u64> {
170        // Build query with parameters
171        let mut query_builder = sqlx::query(query);
172
173        // Bind parameters based on their type
174        for param in params {
175            query_builder = match param {
176                Value::String(s) => query_builder.bind(s),
177                Value::Number(n) => {
178                    if let Some(i) = n.as_i64() {
179                        query_builder.bind(i)
180                    } else if let Some(f) = n.as_f64() {
181                        query_builder.bind(f)
182                    } else {
183                        query_builder.bind(n.to_string())
184                    }
185                }
186                Value::Bool(b) => query_builder.bind(*b),
187                Value::Null => query_builder.bind::<Option<String>>(None),
188                Value::Array(_) | Value::Object(_) => {
189                    let json_str = serde_json::to_string(param).unwrap_or_default();
190                    query_builder.bind(json_str)
191                }
192            };
193        }
194
195        let result = query_builder
196            .execute(&self.pool)
197            .await
198            .map_err(|e| Error::generic(format!("Execute failed: {}", e)))?;
199
200        Ok(result.rows_affected())
201    }
202
203    async fn execute_with_id(&self, query: &str, params: &[Value]) -> Result<String> {
204        // Build query with parameters
205        let mut query_builder = sqlx::query(query);
206
207        // Bind parameters based on their type
208        for param in params {
209            query_builder = match param {
210                Value::String(s) => query_builder.bind(s),
211                Value::Number(n) => {
212                    if let Some(i) = n.as_i64() {
213                        query_builder.bind(i)
214                    } else if let Some(f) = n.as_f64() {
215                        query_builder.bind(f)
216                    } else {
217                        query_builder.bind(n.to_string())
218                    }
219                }
220                Value::Bool(b) => query_builder.bind(*b),
221                Value::Null => query_builder.bind::<Option<String>>(None),
222                Value::Array(_) | Value::Object(_) => {
223                    let json_str = serde_json::to_string(param).unwrap_or_default();
224                    query_builder.bind(json_str)
225                }
226            };
227        }
228
229        let result = query_builder
230            .execute(&self.pool)
231            .await
232            .map_err(|e| Error::generic(format!("Execute failed: {}", e)))?;
233
234        // Get last inserted row ID
235        let last_id = result.last_insert_rowid();
236        Ok(last_id.to_string())
237    }
238
239    async fn table_exists(&self, table_name: &str) -> Result<bool> {
240        let query = "SELECT name FROM sqlite_master WHERE type='table' AND name=?";
241        let result = sqlx::query_scalar::<_, String>(query)
242            .bind(table_name)
243            .fetch_optional(&self.pool)
244            .await
245            .map_err(|e| Error::generic(format!("Failed to check table existence: {}", e)))?;
246
247        Ok(result.is_some())
248    }
249
250    async fn create_table(&self, create_statement: &str) -> Result<()> {
251        sqlx::query(create_statement)
252            .execute(&self.pool)
253            .await
254            .map_err(|e| Error::generic(format!("Failed to create table: {}", e)))?;
255
256        Ok(())
257    }
258
259    fn connection_info(&self) -> String {
260        format!("SQLite: {}", self.path.display())
261    }
262
263    async fn close(&mut self) -> Result<()> {
264        self.pool.close().await;
265        Ok(())
266    }
267}
268
269/// Helper function to extract a row value as JSON
270fn row_value_to_json(row: &sqlx::sqlite::SqliteRow, idx: usize) -> Result<Value> {
271    use sqlx::Row;
272
273    // Try to get the value as different types
274    if let Ok(value) = row.try_get::<String, _>(idx) {
275        return Ok(Value::String(value));
276    }
277    if let Ok(value) = row.try_get::<i64, _>(idx) {
278        return Ok(Value::Number(value.into()));
279    }
280    if let Ok(value) = row.try_get::<f64, _>(idx) {
281        if let Some(n) = serde_json::Number::from_f64(value) {
282            return Ok(Value::Number(n));
283        }
284    }
285    if let Ok(value) = row.try_get::<bool, _>(idx) {
286        return Ok(Value::Bool(value));
287    }
288    if let Ok(value) = row.try_get::<Option<String>, _>(idx) {
289        return Ok(value.map(Value::String).unwrap_or(Value::Null));
290    }
291
292    // Default: try to get as string
293    Ok(Value::String(row.get::<String, _>(idx)))
294}
295
296/// JSON file database backend implementation
297pub struct JsonDatabase {
298    path: std::path::PathBuf,
299    data: Arc<RwLock<HashMap<String, Vec<HashMap<String, Value>>>>>,
300}
301
302impl JsonDatabase {
303    /// Create a new JSON database
304    pub async fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
305        let path = path.as_ref().to_path_buf();
306
307        // Load existing data if file exists
308        let data = if path.exists() {
309            let content = tokio::fs::read_to_string(&path)
310                .await
311                .map_err(|e| Error::generic(format!("Failed to read JSON database: {}", e)))?;
312            serde_json::from_str(&content).unwrap_or_default()
313        } else {
314            HashMap::new()
315        };
316
317        Ok(Self {
318            path,
319            data: Arc::new(RwLock::new(data)),
320        })
321    }
322
323    /// Save data to JSON file
324    async fn save(&self) -> Result<()> {
325        let data = self.data.read().await;
326
327        // Ensure parent directory exists
328        if let Some(parent) = self.path.parent() {
329            tokio::fs::create_dir_all(parent).await.map_err(|e| {
330                Error::generic(format!("Failed to create database directory: {}", e))
331            })?;
332        }
333
334        // Serialize the data (not the RwLock wrapper)
335        let content = serde_json::to_string_pretty(&*data)
336            .map_err(|e| Error::generic(format!("Failed to serialize JSON database: {}", e)))?;
337
338        tokio::fs::write(&self.path, content)
339            .await
340            .map_err(|e| Error::generic(format!("Failed to write JSON database: {}", e)))?;
341
342        Ok(())
343    }
344}
345
346#[async_trait]
347impl VirtualDatabase for JsonDatabase {
348    async fn initialize(&mut self) -> Result<()> {
349        // JSON databases don't need schema initialization
350        Ok(())
351    }
352
353    async fn query(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>> {
354        // Simple SQL-like query parser for JSON backend
355        // This is a basic implementation - for full SQL support, consider using sqlparser crate
356        let data = self.data.read().await;
357        let query_upper = query.trim().to_uppercase();
358
359        // Handle SELECT COUNT(*) queries
360        if query_upper.contains("COUNT(*)") || query_upper.contains("COUNT( * )") {
361            let table_name = extract_table_name_from_select(query)?;
362            if let Some(records) = data.get(table_name) {
363                let count = if query.contains("WHERE") {
364                    apply_json_where_clause(records, query, params)?.len()
365                } else {
366                    records.len()
367                };
368                let mut result = HashMap::new();
369                // Always use "count" as the field name for COUNT(*) queries
370                result.insert("count".to_string(), Value::Number(count.into()));
371                return Ok(vec![result]);
372            }
373        } else if query_upper.starts_with("SELECT") {
374            // Extract table name from query
375            let table_name = extract_table_name_from_select(query)?;
376
377            if let Some(records) = data.get(table_name) {
378                // Apply simple WHERE filtering
379                let filtered = if query.contains("WHERE") {
380                    apply_json_where_clause(records, query, params)?
381                } else {
382                    records.clone()
383                };
384
385                // Apply LIMIT and OFFSET
386                let result = apply_json_pagination(&filtered, query)?;
387                return Ok(result);
388            }
389        } else if query_upper.starts_with("COUNT") {
390            // Handle COUNT queries
391            let table_name = extract_table_name_from_count(query)?;
392            if let Some(records) = data.get(table_name) {
393                let count = if query.contains("WHERE") {
394                    apply_json_where_clause(records, query, params)?.len()
395                } else {
396                    records.len()
397                };
398                let mut result = HashMap::new();
399                result.insert("total".to_string(), Value::Number(count.into()));
400                return Ok(vec![result]);
401            }
402        }
403
404        Ok(vec![])
405    }
406
407    async fn execute(&self, query: &str, params: &[Value]) -> Result<u64> {
408        let mut data = self.data.write().await;
409
410        // Parse INSERT, UPDATE, DELETE queries
411        let query_upper = query.trim().to_uppercase();
412
413        if query_upper.starts_with("INSERT") {
414            let (table_name, record) = parse_insert_query(query, params)?;
415            let records = data.entry(table_name).or_insert_with(Vec::new);
416            records.push(record);
417            self.save().await?;
418            Ok(1)
419        } else if query_upper.starts_with("UPDATE") {
420            let (table_name, updates, where_clause, where_params) =
421                parse_update_query(query, params)?;
422            if let Some(records) = data.get_mut(&table_name) {
423                let mut updated = 0;
424                for record in records.iter_mut() {
425                    if matches_json_where(record, &where_clause, &where_params)? {
426                        record.extend(updates.clone());
427                        updated += 1;
428                    }
429                }
430                self.save().await?;
431                Ok(updated)
432            } else {
433                Ok(0)
434            }
435        } else if query_upper.starts_with("DELETE") {
436            let (table_name, where_clause, where_params) = parse_delete_query(query, params)?;
437            if let Some(records) = data.get_mut(&table_name) {
438                let initial_len = records.len();
439                records.retain(|record| {
440                    !matches_json_where(record, &where_clause, &where_params).unwrap_or(false)
441                });
442                let deleted = initial_len - records.len();
443                self.save().await?;
444                Ok(deleted as u64)
445            } else {
446                Ok(0)
447            }
448        } else {
449            Ok(0)
450        }
451    }
452
453    async fn execute_with_id(&self, query: &str, params: &[Value]) -> Result<String> {
454        // For INSERT, extract the ID from the inserted record
455        let mut data = self.data.write().await;
456
457        if query.trim().to_uppercase().starts_with("INSERT") {
458            let (table_name, mut record) = parse_insert_query(query, params)?;
459
460            // Generate ID if not present
461            if !record.contains_key("id") {
462                use uuid::Uuid;
463                record.insert("id".to_string(), Value::String(Uuid::new_v4().to_string()));
464            }
465
466            let id = record.get("id").and_then(|v| v.as_str()).unwrap_or("").to_string();
467
468            let records = data.entry(table_name).or_insert_with(Vec::new);
469            records.push(record);
470            self.save().await?;
471            Ok(id)
472        } else {
473            self.execute(query, params).await?;
474            Ok(String::new())
475        }
476    }
477
478    async fn table_exists(&self, table_name: &str) -> Result<bool> {
479        let data = self.data.read().await;
480        Ok(data.contains_key(table_name))
481    }
482
483    async fn create_table(&self, _create_statement: &str) -> Result<()> {
484        // JSON backend doesn't need explicit table creation
485        Ok(())
486    }
487
488    fn connection_info(&self) -> String {
489        format!("JSON: {}", self.path.display())
490    }
491
492    async fn close(&mut self) -> Result<()> {
493        self.save().await
494    }
495}
496
497/// In-memory database backend implementation
498pub struct InMemoryDatabase {
499    data: Arc<RwLock<HashMap<String, Vec<HashMap<String, Value>>>>>,
500}
501
502impl InMemoryDatabase {
503    /// Create a new in-memory database
504    pub async fn new() -> Result<Self> {
505        Ok(Self {
506            data: Arc::new(RwLock::new(HashMap::new())),
507        })
508    }
509}
510
511#[async_trait]
512impl VirtualDatabase for InMemoryDatabase {
513    async fn initialize(&mut self) -> Result<()> {
514        // In-memory databases don't need initialization
515        Ok(())
516    }
517
518    async fn query(&self, query: &str, params: &[Value]) -> Result<Vec<HashMap<String, Value>>> {
519        // Reuse JSON backend query logic (same structure)
520        let data = self.data.read().await;
521        let query_upper = query.trim().to_uppercase();
522
523        // Handle SELECT COUNT(*) queries
524        if query_upper.contains("COUNT(*)") || query_upper.contains("COUNT( * )") {
525            let table_name = extract_table_name_from_select(query)?;
526            let count = if let Some(records) = data.get(table_name) {
527                if query.contains("WHERE") {
528                    apply_json_where_clause(records, query, params)?.len()
529                } else {
530                    records.len()
531                }
532            } else {
533                // Table doesn't exist yet, return 0
534                0
535            };
536            let mut result = HashMap::new();
537            result.insert("count".to_string(), Value::Number(count.into()));
538            return Ok(vec![result]);
539        } else if query_upper.starts_with("SELECT") {
540            let table_name = extract_table_name_from_select(query)?;
541
542            if let Some(records) = data.get(table_name) {
543                let filtered = if query.contains("WHERE") {
544                    apply_json_where_clause(records, query, params)?
545                } else {
546                    records.clone()
547                };
548
549                let result = apply_json_pagination(&filtered, query)?;
550                return Ok(result);
551            }
552        } else if query_upper.starts_with("COUNT") {
553            let table_name = extract_table_name_from_count(query)?;
554            if let Some(records) = data.get(table_name) {
555                let count = if query.contains("WHERE") {
556                    apply_json_where_clause(records, query, params)?.len()
557                } else {
558                    records.len()
559                };
560                let mut result = HashMap::new();
561                result.insert("total".to_string(), Value::Number(count.into()));
562                return Ok(vec![result]);
563            }
564        }
565
566        Ok(vec![])
567    }
568
569    async fn execute(&self, query: &str, params: &[Value]) -> Result<u64> {
570        let mut data = self.data.write().await;
571
572        let query_upper = query.trim().to_uppercase();
573
574        if query_upper.starts_with("INSERT") {
575            let (table_name, record) = parse_insert_query(query, params)?;
576            let records = data.entry(table_name).or_insert_with(Vec::new);
577            records.push(record);
578            Ok(1)
579        } else if query_upper.starts_with("UPDATE") {
580            let (table_name, updates, where_clause, where_params) =
581                parse_update_query(query, params)?;
582            if let Some(records) = data.get_mut(&table_name) {
583                let mut updated = 0;
584                for record in records.iter_mut() {
585                    if matches_json_where(record, &where_clause, &where_params)? {
586                        record.extend(updates.clone());
587                        updated += 1;
588                    }
589                }
590                Ok(updated)
591            } else {
592                Ok(0)
593            }
594        } else if query_upper.starts_with("DELETE") {
595            let (table_name, where_clause, where_params) = parse_delete_query(query, params)?;
596            // Ensure table exists (for DELETE FROM table_name without WHERE, we need the table)
597            let records = data.entry(table_name.clone()).or_insert_with(Vec::new);
598            let initial_len = records.len();
599            records.retain(|record| {
600                !matches_json_where(record, &where_clause, &where_params).unwrap_or(false)
601            });
602            let deleted = initial_len - records.len();
603            Ok(deleted as u64)
604        } else {
605            Ok(0)
606        }
607    }
608
609    async fn execute_with_id(&self, query: &str, params: &[Value]) -> Result<String> {
610        let mut data = self.data.write().await;
611
612        if query.trim().to_uppercase().starts_with("INSERT") {
613            let (table_name, mut record) = parse_insert_query(query, params)?;
614
615            if !record.contains_key("id") {
616                use uuid::Uuid;
617                record.insert("id".to_string(), Value::String(Uuid::new_v4().to_string()));
618            }
619
620            let id = record.get("id").and_then(|v| v.as_str()).unwrap_or("").to_string();
621
622            let records = data.entry(table_name).or_insert_with(Vec::new);
623            records.push(record);
624            Ok(id)
625        } else {
626            self.execute(query, params).await?;
627            Ok(String::new())
628        }
629    }
630
631    async fn table_exists(&self, table_name: &str) -> Result<bool> {
632        let data = self.data.read().await;
633        Ok(data.contains_key(table_name))
634    }
635
636    async fn create_table(&self, create_statement: &str) -> Result<()> {
637        // In-memory backend doesn't need explicit table creation, but we should
638        // extract table name and ensure it exists in the data HashMap
639        // Extract table name from CREATE TABLE statement
640        // Format: "CREATE TABLE IF NOT EXISTS table_name (" or "CREATE TABLE table_name ("
641        let query_upper = create_statement.to_uppercase();
642        if query_upper.contains("CREATE TABLE") {
643            let mut rest = create_statement;
644
645            // Skip "CREATE TABLE"
646            if let Some(idx) = query_upper.find("CREATE TABLE") {
647                rest = &create_statement[idx + 12..];
648            }
649
650            // Skip "IF NOT EXISTS" if present
651            let rest_upper = rest.to_uppercase();
652            if rest_upper.trim_start().starts_with("IF NOT EXISTS") {
653                if let Some(idx) = rest_upper.find("IF NOT EXISTS") {
654                    rest = &rest[idx + 13..];
655                }
656            }
657
658            // Find the table name (ends at '(' or whitespace)
659            let table_name = rest
660                .trim_start()
661                .split(|c: char| c == '(' || c.is_whitespace())
662                .next()
663                .unwrap_or("")
664                .trim()
665                .to_string();
666
667            if !table_name.is_empty() {
668                let mut data = self.data.write().await;
669                data.entry(table_name).or_insert_with(Vec::new);
670            }
671        }
672        Ok(())
673    }
674
675    fn connection_info(&self) -> String {
676        "In-Memory".to_string()
677    }
678
679    async fn close(&mut self) -> Result<()> {
680        // In-memory databases don't need cleanup
681        Ok(())
682    }
683}
684
685// Helper functions for JSON/InMemory query parsing
686
687/// Extract table name from SELECT query
688fn extract_table_name_from_select(query: &str) -> Result<&str> {
689    // Simple parser: "SELECT * FROM table_name"
690    let parts: Vec<&str> = query.split_whitespace().collect();
691    if let Some(from_idx) = parts.iter().position(|&p| p.to_uppercase() == "FROM") {
692        if from_idx + 1 < parts.len() {
693            let table_name = parts[from_idx + 1].trim_end_matches(';');
694            return Ok(table_name);
695        }
696    }
697    Err(Error::generic("Invalid SELECT query: missing FROM clause".to_string()))
698}
699
700/// Extract table name from COUNT query
701fn extract_table_name_from_count(query: &str) -> Result<&str> {
702    // "SELECT COUNT(*) FROM table_name" or "SELECT COUNT(*) as total FROM table_name"
703    extract_table_name_from_select(query)
704}
705
706/// Apply WHERE clause filtering to JSON records
707fn apply_json_where_clause(
708    records: &[HashMap<String, Value>],
709    query: &str,
710    params: &[Value],
711) -> Result<Vec<HashMap<String, Value>>> {
712    // Simple WHERE clause parser - supports basic "field = ?" patterns
713    let mut result = Vec::new();
714
715    for record in records {
716        if matches_json_where(record, query, params)? {
717            result.push(record.clone());
718        }
719    }
720
721    Ok(result)
722}
723
724/// Check if a record matches WHERE clause
725fn matches_json_where(
726    record: &HashMap<String, Value>,
727    query: &str,
728    params: &[Value],
729) -> Result<bool> {
730    // Extract WHERE clause from query
731    if let Some(where_idx) = query.to_uppercase().find("WHERE") {
732        let where_clause = &query[where_idx + 5..];
733
734        // Parse simple conditions like "field = ?"
735        let parts: Vec<&str> = where_clause.split_whitespace().collect();
736        if parts.len() >= 3 && parts[1] == "=" {
737            let field = parts[0];
738            let param_idx = parts.iter().position(|&p| p == "?").unwrap_or(0);
739
740            if param_idx < params.len() {
741                let expected_value = &params[0]; // Use first param for simple cases
742                let actual_value = record.get(field);
743
744                return Ok(matches_value(actual_value, expected_value));
745            }
746        }
747    }
748
749    Ok(true) // No WHERE clause or couldn't parse
750}
751
752/// Check if two values match
753fn matches_value(actual: Option<&Value>, expected: &Value) -> bool {
754    match (actual, expected) {
755        (Some(a), e) => a == e,
756        (None, Value::Null) => true,
757        _ => false,
758    }
759}
760
761/// Apply pagination (LIMIT and OFFSET) to results
762fn apply_json_pagination(
763    records: &[HashMap<String, Value>],
764    query: &str,
765) -> Result<Vec<HashMap<String, Value>>> {
766    let mut result = records.to_vec();
767
768    // Extract LIMIT
769    if let Some(limit_idx) = query.to_uppercase().find("LIMIT") {
770        let limit_str = query[limit_idx + 5..]
771            .split_whitespace()
772            .next()
773            .unwrap_or("")
774            .trim_end_matches(';');
775
776        if let Ok(limit) = limit_str.parse::<usize>() {
777            // Extract OFFSET
778            let offset = if let Some(offset_idx) = query.to_uppercase().find("OFFSET") {
779                query[offset_idx + 6..]
780                    .split_whitespace()
781                    .next()
782                    .unwrap_or("0")
783                    .trim_end_matches(';')
784                    .parse::<usize>()
785                    .unwrap_or(0)
786            } else {
787                0
788            };
789
790            let start = offset.min(result.len());
791            let end = (start + limit).min(result.len());
792            result = result[start..end].to_vec();
793        }
794    }
795
796    Ok(result)
797}
798
799/// Parse INSERT query and return (table_name, record)
800fn parse_insert_query(query: &str, params: &[Value]) -> Result<(String, HashMap<String, Value>)> {
801    // Simple parser: "INSERT INTO table_name (field1, field2) VALUES (?, ?)"
802    let parts: Vec<&str> = query.split_whitespace().collect();
803
804    if let Some(into_idx) = parts.iter().position(|&p| p.to_uppercase() == "INTO") {
805        if into_idx + 1 < parts.len() {
806            let table_name = parts[into_idx + 1].to_string();
807
808            // Extract field names
809            if let Some(fields_start) = query.find('(') {
810                if let Some(fields_end) = query[fields_start + 1..].find(')') {
811                    let fields_str = &query[fields_start + 1..fields_start + 1 + fields_end];
812                    let fields: Vec<&str> = fields_str.split(',').map(|s| s.trim()).collect();
813
814                    // Build record from params
815                    let mut record = HashMap::new();
816                    for (idx, field) in fields.iter().enumerate() {
817                        if idx < params.len() {
818                            record.insert(field.to_string(), params[idx].clone());
819                        }
820                    }
821
822                    return Ok((table_name, record));
823                }
824            }
825        }
826    }
827
828    Err(Error::generic("Invalid INSERT query format".to_string()))
829}
830
831/// Parse UPDATE query
832fn parse_update_query(
833    query: &str,
834    params: &[Value],
835) -> Result<(String, HashMap<String, Value>, String, Vec<Value>)> {
836    // "UPDATE table_name SET field1 = ?, field2 = ? WHERE field3 = ?"
837    let parts: Vec<&str> = query.split_whitespace().collect();
838
839    if parts.len() < 4 || parts[0].to_uppercase() != "UPDATE" {
840        return Err(Error::generic("Invalid UPDATE query".to_string()));
841    }
842
843    let table_name = parts[1].to_string();
844
845    // Extract SET clause
846    if let Some(set_idx) = parts.iter().position(|&p| p.to_uppercase() == "SET") {
847        let set_clause = &query[query.to_uppercase().find("SET").unwrap() + 3..];
848        let where_clause = if let Some(where_idx) = set_clause.to_uppercase().find("WHERE") {
849            &set_clause[..where_idx]
850        } else {
851            set_clause
852        };
853
854        // Parse SET fields
855        let mut updates = HashMap::new();
856        let set_parts: Vec<&str> = where_clause.split(',').collect();
857        let mut param_idx = 0;
858
859        for part in set_parts {
860            let field_eq: Vec<&str> = part.split('=').map(|s| s.trim()).collect();
861            if field_eq.len() == 2 && field_eq[1] == "?" {
862                if param_idx < params.len() {
863                    updates.insert(field_eq[0].to_string(), params[param_idx].clone());
864                    param_idx += 1;
865                }
866            }
867        }
868
869        // Extract WHERE clause
870        let (where_clause_str, where_params) =
871            if let Some(where_idx) = set_clause.to_uppercase().find("WHERE") {
872                let where_part = &set_clause[where_idx + 5..];
873                (where_part.to_string(), params[param_idx..].to_vec())
874            } else {
875                (String::new(), Vec::new())
876            };
877
878        return Ok((table_name, updates, where_clause_str, where_params));
879    }
880
881    Err(Error::generic("Invalid UPDATE query: missing SET clause".to_string()))
882}
883
884/// Parse DELETE query
885fn parse_delete_query(query: &str, params: &[Value]) -> Result<(String, String, Vec<Value>)> {
886    // "DELETE FROM table_name WHERE field = ?"
887    let parts: Vec<&str> = query.split_whitespace().collect();
888
889    if let Some(from_idx) = parts.iter().position(|&p| p.to_uppercase() == "FROM") {
890        if from_idx + 1 < parts.len() {
891            let table_name = parts[from_idx + 1].to_string();
892
893            // Extract WHERE clause
894            if let Some(where_idx) = query.to_uppercase().find("WHERE") {
895                let where_clause = query[where_idx + 5..].to_string();
896                return Ok((table_name, where_clause, params.to_vec()));
897            } else {
898                return Ok((table_name, String::new(), Vec::new()));
899            }
900        }
901    }
902
903    Err(Error::generic("Invalid DELETE query".to_string()))
904}