tessera/readers/
polars.rs1use polars::prelude::*;
8
9use super::ResolvedPartition;
10use crate::error::TesseraError;
11
12const EXPIRY_MARKERS: [&str; 5] = [
14 "403",
15 "expired",
16 "accessdenied",
17 "access denied",
18 "forbidden",
19];
20
21pub fn build_lazyframe(
30 parts: &[ResolvedPartition],
31 columns: Option<&[&str]>,
32) -> Result<LazyFrame, TesseraError> {
33 let multi = parts.len() > 1;
34 let mut frames = Vec::with_capacity(parts.len());
35 for (partition, url) in parts {
36 let mut lazy = LazyFrame::scan_parquet(url.as_str().into(), ScanArgsParquet::default())
37 .map_err(|err| TesseraError::Network(err.to_string()))?;
38 if let Some(columns) = columns {
39 lazy = lazy.select(
40 columns
41 .iter()
42 .map(|column| col(*column))
43 .collect::<Vec<_>>(),
44 );
45 }
46 if multi {
47 lazy = lazy.with_columns(vec![
48 lit(partition.coin.as_str()).alias("coin"),
49 lit(partition.month.as_str()).alias("month"),
50 ]);
51 }
52 frames.push(lazy);
53 }
54 if let [single] = &frames[..] {
55 return Ok(single.clone());
56 }
57 concat(
58 frames,
59 UnionArgs {
60 rechunk: true,
61 parallel: true,
62 to_supertypes: true,
63 ..Default::default()
64 },
65 )
66 .map_err(|err| TesseraError::Network(err.to_string()))
67}
68
69pub fn collect(lazy: LazyFrame) -> Result<DataFrame, TesseraError> {
78 lazy.collect().map_err(|err| {
79 let message = err.to_string().to_lowercase();
80 if EXPIRY_MARKERS.iter().any(|marker| message.contains(marker)) {
81 TesseraError::PresignExpired
82 } else {
83 TesseraError::Network(err.to_string())
84 }
85 })
86}