tessera/readers/
duckdb.rs1use duckdb::Connection;
8
9use super::ResolvedPartition;
10use crate::error::TesseraError;
11
12fn sql_str(value: &str) -> String {
14 format!("'{}'", value.replace('\'', "''"))
15}
16
17pub fn build_relation(
28 parts: &[ResolvedPartition],
29 columns: Option<&[&str]>,
30) -> Result<Connection, TesseraError> {
31 let connection =
32 Connection::open_in_memory().map_err(|err| TesseraError::Network(err.to_string()))?;
33
34 let _ = connection.execute_batch("INSTALL httpfs; LOAD httpfs;");
37
38 let multi = parts.len() > 1;
39 let select_cols = columns.map_or_else(|| "*".to_string(), |columns| columns.join(", "));
40 let selects: Vec<String> = parts
41 .iter()
42 .map(|(partition, url)| {
43 let projection = if multi {
44 format!(
45 "{}, {} AS coin, {} AS month",
46 select_cols,
47 sql_str(&partition.coin),
48 sql_str(&partition.month)
49 )
50 } else {
51 select_cols.clone()
52 };
53 format!("SELECT {projection} FROM read_parquet({})", sql_str(url))
54 })
55 .collect();
56 let query = selects.join("\nUNION ALL\n");
57 connection
58 .execute_batch(&format!("CREATE OR REPLACE TEMP VIEW tessera AS {query}"))
59 .map_err(|err| TesseraError::Network(err.to_string()))?;
60 Ok(connection)
61}