micromegas_analytics/lakehouse/
list_view_set_definitions_table_function.rs1use async_trait::async_trait;
8use datafusion::arrow::array::{Int32Array, RecordBatch, StringArray, TimestampNanosecondArray};
9use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef, TimeUnit};
10use datafusion::catalog::Session;
11use datafusion::catalog::TableFunctionArgs;
12use datafusion::catalog::TableFunctionImpl;
13use datafusion::catalog::TableProvider;
14use datafusion::datasource::TableType;
15use datafusion::datasource::memory::{DataSourceExec, MemorySourceConfig};
16use datafusion::error::DataFusionError;
17use datafusion::physical_plan::ExecutionPlan;
18use datafusion::prelude::Expr;
19use micromegas_ingestion::data_lake_connection::DataLakeConnection;
20use sqlx::Row;
21use std::sync::Arc;
22
23fn schema() -> SchemaRef {
24 Arc::new(Schema::new(vec![
25 Field::new("view_set_name", DataType::Utf8, false),
26 Field::new("definition_sql", DataType::Utf8, false),
27 Field::new("update_group", DataType::Int32, false),
28 Field::new(
29 "updated_at",
30 DataType::Timestamp(TimeUnit::Nanosecond, Some("+00:00".into())),
31 false,
32 ),
33 Field::new("updated_by", DataType::Utf8, true),
34 ]))
35}
36
37#[derive(Debug)]
39pub struct ListViewSetDefinitionsTableFunction {
40 lake: Arc<DataLakeConnection>,
41}
42
43impl ListViewSetDefinitionsTableFunction {
44 pub fn new(lake: Arc<DataLakeConnection>) -> Self {
45 Self { lake }
46 }
47}
48
49impl TableFunctionImpl for ListViewSetDefinitionsTableFunction {
50 fn call_with_args(
51 &self,
52 _args: TableFunctionArgs,
53 ) -> datafusion::error::Result<Arc<dyn TableProvider>> {
54 Ok(Arc::new(ListViewSetDefinitionsTableProvider {
55 lake: self.lake.clone(),
56 }))
57 }
58}
59
60#[derive(Debug)]
61struct ListViewSetDefinitionsTableProvider {
62 lake: Arc<DataLakeConnection>,
63}
64
65#[async_trait]
66impl TableProvider for ListViewSetDefinitionsTableProvider {
67 fn schema(&self) -> SchemaRef {
68 schema()
69 }
70
71 fn table_type(&self) -> TableType {
72 TableType::Temporary
73 }
74
75 async fn scan(
76 &self,
77 _state: &dyn Session,
78 projection: Option<&Vec<usize>>,
79 _filters: &[Expr],
80 limit: Option<usize>,
81 ) -> datafusion::error::Result<Arc<dyn ExecutionPlan>> {
82 let rows = sqlx::query(
83 "SELECT view_set_name, definition_sql, update_group, updated_at, updated_by \
84 FROM lakehouse_view_set_definitions ORDER BY view_set_name",
85 )
86 .fetch_all(&self.lake.db_pool)
87 .await
88 .map_err(|e| DataFusionError::External(e.into()))?;
89 let mut view_set_name = Vec::with_capacity(rows.len());
90 let mut definition_sql = Vec::with_capacity(rows.len());
91 let mut update_group = Vec::with_capacity(rows.len());
92 let mut updated_at = Vec::with_capacity(rows.len());
93 let mut updated_by = Vec::with_capacity(rows.len());
94 for row in &rows {
95 view_set_name.push(
96 row.try_get::<String, _>("view_set_name")
97 .map_err(|e| DataFusionError::External(e.into()))?,
98 );
99 definition_sql.push(
100 row.try_get::<String, _>("definition_sql")
101 .map_err(|e| DataFusionError::External(e.into()))?,
102 );
103 update_group.push(
104 row.try_get::<i32, _>("update_group")
105 .map_err(|e| DataFusionError::External(e.into()))?,
106 );
107 let ts: chrono::DateTime<chrono::Utc> = row
108 .try_get("updated_at")
109 .map_err(|e| DataFusionError::External(e.into()))?;
110 updated_at.push(ts.timestamp_nanos_opt().unwrap_or_default());
111 updated_by.push(
112 row.try_get::<Option<String>, _>("updated_by")
113 .map_err(|e| DataFusionError::External(e.into()))?,
114 );
115 }
116 if let Some(n) = limit {
117 view_set_name.truncate(n);
118 definition_sql.truncate(n);
119 update_group.truncate(n);
120 updated_at.truncate(n);
121 updated_by.truncate(n);
122 }
123 let rb = RecordBatch::try_new(
124 schema(),
125 vec![
126 Arc::new(StringArray::from(view_set_name)),
127 Arc::new(StringArray::from(definition_sql)),
128 Arc::new(Int32Array::from(update_group)),
129 Arc::new(
130 TimestampNanosecondArray::from(updated_at).with_timezone("+00:00".to_string()),
131 ),
132 Arc::new(StringArray::from(updated_by)),
133 ],
134 )?;
135 let source =
136 MemorySourceConfig::try_new(&[vec![rb]], schema(), projection.map(|v| v.to_owned()))?;
137 Ok(DataSourceExec::from_data_source(source))
138 }
139}