use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use crate::common;
use super::{Aggregate, AggregateKey, Filter, FlussoType, Join, JoinKind, Through, Transform};
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub struct Field {
pub field: common::FieldName,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub options: BTreeMap<String, common::GenericValue>,
pub source: FieldSource,
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FieldSource {
Column(Column),
Group(Vec<Field>),
Geo(Geo),
Relation(Relation),
Constant(common::GenericValue),
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub struct Column {
pub column: common::ColumnName,
pub ty: FlussoType,
pub nullable: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub transforms: Vec<Transform>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default: Option<common::GenericValue>,
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub struct Geo {
pub lat: common::ColumnName,
pub lon: common::ColumnName,
pub nullable: bool,
}
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Relation {
Join(Join),
Aggregate(Aggregate),
}
impl Field {
pub fn children(&self) -> &[Field] {
match &self.source {
FieldSource::Group(fields) => fields,
FieldSource::Relation(Relation::Join(join)) => &join.fields,
FieldSource::Column(_)
| FieldSource::Geo(_)
| FieldSource::Relation(Relation::Aggregate(_))
| FieldSource::Constant(_) => &[],
}
}
pub fn relation(&self) -> Option<&Relation> {
match &self.source {
FieldSource::Relation(relation) => Some(relation),
_ => None,
}
}
pub fn column(&self) -> Option<&common::ColumnName> {
match &self.source {
FieldSource::Column(column) => Some(&column.column),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum RelationKey<'a> {
Local(&'a common::ColumnName),
Direct(&'a common::ColumnName),
Through(&'a Through),
}
impl Relation {
pub fn table(&self) -> &common::TableName {
match self {
Relation::Join(join) => &join.table,
Relation::Aggregate(aggregate) => &aggregate.table,
}
}
pub fn key(&self) -> RelationKey<'_> {
match self {
Relation::Join(join) => match &join.kind {
JoinKind::BelongsTo { column } => RelationKey::Local(column),
JoinKind::HasOne { foreign_key } | JoinKind::HasMany { foreign_key } => {
RelationKey::Direct(foreign_key)
}
JoinKind::ManyToMany { through } => RelationKey::Through(through),
},
Relation::Aggregate(aggregate) => match &aggregate.key {
AggregateKey::Direct(foreign_key) => RelationKey::Direct(foreign_key),
AggregateKey::Through(through) => RelationKey::Through(through),
},
}
}
pub fn filters(&self) -> Option<&[Filter]> {
match self {
Relation::Join(join) => join.filters.as_deref(),
Relation::Aggregate(aggregate) => aggregate.filters.as_deref(),
}
}
}
#[derive(Debug, Clone, Hash)]
pub struct Mapping {
pub mapping_type: MappingType,
pub extra: BTreeMap<String, common::GenericValue>,
pub map_values: Option<MappingType>,
pub decimal: bool,
}
impl Serialize for Mapping {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeMap;
let mut map = serializer.serialize_map(Some(1 + self.extra.len()))?;
map.serialize_entry("type", &self.mapping_type)?;
for (key, value) in &self.extra {
map.serialize_entry(key, value)?;
}
map.end()
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum MappingType {
Text,
Keyword,
Boolean,
Byte,
Short,
Integer,
Long,
Float,
Double,
HalfFloat,
ScaledFloat,
Date,
Object,
Nested,
Other(String),
}
impl MappingType {
pub fn name(&self) -> &str {
match self {
MappingType::Text => "text",
MappingType::Keyword => "keyword",
MappingType::Boolean => "boolean",
MappingType::Byte => "byte",
MappingType::Short => "short",
MappingType::Integer => "integer",
MappingType::Long => "long",
MappingType::Float => "float",
MappingType::Double => "double",
MappingType::HalfFloat => "half_float",
MappingType::ScaledFloat => "scaled_float",
MappingType::Date => "date",
MappingType::Object => "object",
MappingType::Nested => "nested",
MappingType::Other(name) => name,
}
}
pub fn from_name(name: &str) -> MappingType {
match name {
"text" => MappingType::Text,
"keyword" => MappingType::Keyword,
"boolean" => MappingType::Boolean,
"byte" => MappingType::Byte,
"short" => MappingType::Short,
"integer" => MappingType::Integer,
"long" => MappingType::Long,
"float" => MappingType::Float,
"double" => MappingType::Double,
"half_float" => MappingType::HalfFloat,
"scaled_float" => MappingType::ScaledFloat,
"date" => MappingType::Date,
"object" => MappingType::Object,
"nested" => MappingType::Nested,
other => MappingType::Other(other.to_owned()),
}
}
}
impl Serialize for MappingType {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.name())
}
}