use std::{collections::BTreeMap, sync::Arc};
use arrow::datatypes::{DataType, Field};
use hashbrown::HashMap;
use crate::{error::_plan_err, DataFusionError, ScalarValue};
#[derive(Debug, Clone)]
pub struct ScalarAndMetadata {
pub value: ScalarValue,
pub metadata: Option<FieldMetadata>,
}
impl ScalarAndMetadata {
pub fn new(value: ScalarValue, metadata: Option<FieldMetadata>) -> Self {
Self { value, metadata }
}
pub fn value(&self) -> &ScalarValue {
&self.value
}
pub fn metadata(&self) -> Option<&FieldMetadata> {
self.metadata.as_ref()
}
pub fn into_inner(self) -> (ScalarValue, Option<FieldMetadata>) {
(self.value, self.metadata)
}
pub fn cast_storage_to(
&self,
target_type: &DataType,
) -> Result<Self, DataFusionError> {
let new_value = self.value().cast_to(target_type)?;
Ok(Self::new(new_value, self.metadata.clone()))
}
}
impl From<ScalarValue> for ScalarAndMetadata {
fn from(value: ScalarValue) -> Self {
Self::new(value, None)
}
}
pub fn check_metadata_with_storage_equal(
actual: (
&DataType,
Option<&std::collections::HashMap<String, String>>,
),
expected: (
&DataType,
Option<&std::collections::HashMap<String, String>>,
),
what: &str,
context: &str,
) -> Result<(), DataFusionError> {
if actual.0 != expected.0 {
return _plan_err!(
"Expected {what} of type {}, got {}{context}",
format_type_and_metadata(expected.0, expected.1),
format_type_and_metadata(actual.0, actual.1)
);
}
let metadata_equal = match (actual.1, expected.1) {
(None, None) => true,
(None, Some(expected_metadata)) => expected_metadata.is_empty(),
(Some(actual_metadata), None) => actual_metadata.is_empty(),
(Some(actual_metadata), Some(expected_metadata)) => {
actual_metadata == expected_metadata
}
};
if !metadata_equal {
return _plan_err!(
"Expected {what} of type {}, got {}{context}",
format_type_and_metadata(expected.0, expected.1),
format_type_and_metadata(actual.0, actual.1)
);
}
Ok(())
}
pub fn format_type_and_metadata(
data_type: &DataType,
metadata: Option<&std::collections::HashMap<String, String>>,
) -> String {
match metadata {
Some(metadata) if !metadata.is_empty() => {
format!("{data_type}<{metadata:?}>")
}
_ => data_type.to_string(),
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
pub struct FieldMetadata {
inner: Arc<BTreeMap<String, String>>,
}
impl Default for FieldMetadata {
fn default() -> Self {
Self::new_empty()
}
}
impl FieldMetadata {
pub fn new_empty() -> Self {
Self {
inner: Arc::new(BTreeMap::new()),
}
}
pub fn merge_options(
m: Option<&FieldMetadata>,
n: Option<&FieldMetadata>,
) -> Option<FieldMetadata> {
match (m, n) {
(Some(m), Some(n)) => {
let mut merged = m.clone();
merged.extend(n.clone());
Some(merged)
}
(Some(m), None) => Some(m.clone()),
(None, Some(n)) => Some(n.clone()),
(None, None) => None,
}
}
pub fn new_from_field(field: &Field) -> Self {
let inner = field
.metadata()
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
Self {
inner: Arc::new(inner),
}
}
pub fn new(inner: BTreeMap<String, String>) -> Self {
Self {
inner: Arc::new(inner),
}
}
pub fn inner(&self) -> &BTreeMap<String, String> {
&self.inner
}
pub fn into_inner(self) -> Arc<BTreeMap<String, String>> {
self.inner
}
pub fn extend(&mut self, other: Self) {
if other.is_empty() {
return;
}
let other = Arc::unwrap_or_clone(other.into_inner());
Arc::make_mut(&mut self.inner).extend(other);
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn to_hashmap(&self) -> std::collections::HashMap<String, String> {
self.inner
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect()
}
pub fn add_to_field(&self, field: Field) -> Field {
if self.inner.is_empty() {
return field;
}
field.with_metadata(self.to_hashmap())
}
}
impl From<&Field> for FieldMetadata {
fn from(field: &Field) -> Self {
Self::new_from_field(field)
}
}
impl From<BTreeMap<String, String>> for FieldMetadata {
fn from(inner: BTreeMap<String, String>) -> Self {
Self::new(inner)
}
}
impl From<std::collections::HashMap<String, String>> for FieldMetadata {
fn from(map: std::collections::HashMap<String, String>) -> Self {
Self::new(map.into_iter().collect())
}
}
impl From<&std::collections::HashMap<String, String>> for FieldMetadata {
fn from(map: &std::collections::HashMap<String, String>) -> Self {
let inner = map
.iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
Self::new(inner)
}
}
impl From<HashMap<String, String>> for FieldMetadata {
fn from(map: HashMap<String, String>) -> Self {
let inner = map.into_iter().collect();
Self::new(inner)
}
}
impl From<&HashMap<String, String>> for FieldMetadata {
fn from(map: &HashMap<String, String>) -> Self {
let inner = map
.into_iter()
.map(|(k, v)| (k.to_string(), v.to_string()))
.collect();
Self::new(inner)
}
}