Skip to main content

f_ck/engine/
salsa_db.rs

1use crate::dsl::Source;
2use salsa::Database;
3use std::collections::HashMap;
4use std::path::PathBuf;
5use std::time::SystemTime;
6
7// Use the salsa::DatabaseImpl directly
8pub type DatabaseImpl = salsa::DatabaseImpl;
9
10// Salsa input representing a source file
11#[salsa::input]
12pub struct SourceFile {
13    pub path: PathBuf,
14    pub content_hash: u64,
15    pub modified_time: SystemTime,
16}
17
18// Simple tracked function that returns metadata as a string
19#[salsa::tracked]
20pub fn source_metadata(db: &dyn salsa::Database, source_file: SourceFile) -> String {
21    let path = source_file.path(db);
22    
23    // Create a temporary Source for compatibility with existing DataReader
24    let temp_source = Source {
25        id: "temp".to_string(),
26        path: path.clone(),
27        format: if path.extension().and_then(|s| s.to_str()) == Some("csv") {
28            "csv".to_string()
29        } else {
30            "tsv".to_string()
31        },
32    };
33
34    match crate::engine::DataReader::get_schema(&temp_source) {
35        Ok(schema) => {
36            // Convert schema to a simple string representation since Schema doesn't implement Serialize
37            let schema_map: std::collections::HashMap<String, String> = schema
38                .iter()
39                .map(|(name, dtype)| (name.to_string(), format!("{:?}", dtype)))
40                .collect();
41            serde_json::to_string(&schema_map).unwrap_or_default()
42        },
43        Err(_) => "error".to_string(),
44    }
45}
46
47// Tracked function for parsing data source  
48#[salsa::tracked]
49pub fn parsed_source_id(db: &dyn salsa::Database, source_file: SourceFile) -> String {
50    // Trigger metadata computation first (dependency)
51    let _metadata = source_metadata(db, source_file);
52    
53    // Generate a unique ID for this parsed source
54    format!("df_{}", source_file.content_hash(db))
55}
56
57// Tracked function for query execution
58#[salsa::tracked] 
59pub fn execute_query_cached(
60    db: &dyn salsa::Database,
61    query_json: String,
62    source_files: Vec<SourceFile>,
63) -> String {
64    // Ensure all sources are processed (creates dependencies)
65    for source_file in &source_files {
66        let _parsed_id = parsed_source_id(db, *source_file);
67        let _metadata = source_metadata(db, *source_file);
68    }
69    
70    // Generate a result ID based on query and inputs
71    use std::collections::hash_map::DefaultHasher;
72    use std::hash::{Hash, Hasher};
73    
74    let mut hasher = DefaultHasher::new();
75    query_json.hash(&mut hasher);
76    for sf in &source_files {
77        sf.content_hash(db).hash(&mut hasher);
78    }
79    
80    format!("result_{}", hasher.finish())
81}
82
83// Helper functions for cache management
84pub fn invalidate_source_in_db(db: &mut DatabaseImpl, _path: &PathBuf) {
85    // In a real implementation, we'd track and invalidate specific SourceFile inputs
86    // For now, we'll use a simple approach
87    db.synthetic_write(salsa::Durability::LOW);
88}
89
90pub fn get_cache_stats(_db: &DatabaseImpl) -> HashMap<String, usize> {
91    // Return basic cache statistics
92    // In a real implementation, this would use Salsa's introspection APIs
93    let mut stats = HashMap::new();
94    stats.insert("total_inputs".to_string(), 0);
95    stats.insert("computed_values".to_string(), 0);
96    stats
97}