use std::{collections::HashSet, fmt::Debug};
use crate::{
schema::fields::base::{FieldType, InternalFieldConfig},
IvoErrorTool, IvoSchemaStruct, Schema,
};
pub(super) struct FieldInfoCollection<
'a,
I: IvoSchemaStruct,
O: IvoSchemaStruct,
CtxOptions,
Timestamp: Clone + Debug + Send + Sync + 'static,
ErrorTool: IvoErrorTool,
> {
config_names: HashSet<String>,
schema: &'a Schema<I, O, CtxOptions, Timestamp, ErrorTool>,
pub fields: Vec<FieldInfo>,
pub schema_input_fields: HashSet<String>,
pub schema_output_fields: HashSet<String>,
}
impl<
'a,
I: IvoSchemaStruct,
O: IvoSchemaStruct,
CtxOptions,
Timestamp: Clone + Debug + Send + Sync + 'static,
ErrorTool: IvoErrorTool,
> FieldInfoCollection<'a, I, O, CtxOptions, Timestamp, ErrorTool>
{
pub fn new(schema: &'a Schema<I, O, CtxOptions, Timestamp, ErrorTool>) -> Self {
Self {
schema,
schema_input_fields: I::ivo_internal_field_names(),
schema_output_fields: O::ivo_internal_field_names(),
config_names: HashSet::new(),
fields: Vec::new(),
}
}
pub fn set_fields(&mut self, fields: Vec<FieldInfo>) {
let mut config_names = HashSet::new();
for field_info in fields.iter() {
config_names.insert(field_info.config_name.clone());
}
self.config_names = config_names;
self.fields = fields;
}
pub fn from_fields(
schema: &'a Schema<I, O, CtxOptions, Timestamp, ErrorTool>,
fields: Vec<FieldInfo>,
schema_input_fields: &HashSet<String>,
schema_output_fields: &HashSet<String>,
) -> Self {
let mut config_names = HashSet::new();
for field_info in fields.iter() {
config_names.insert(field_info.config_name.clone());
}
Self {
schema,
schema_input_fields: schema_input_fields.clone(),
schema_output_fields: schema_output_fields.clone(),
config_names,
fields,
}
}
pub fn contains(&self, field_name: &String) -> bool {
self.config_names.contains(field_name)
}
fn _find(&self, field_name: &String) -> Option<FieldInfo> {
self.fields.iter().find(|f| f.name == *field_name).cloned()
}
pub fn get(&self, field_name: &String) -> Option<FieldInfo> {
self._find(field_name).or_else(|| {
Self::get_field_info(
field_name,
&self.schema,
&self.schema_input_fields,
&self.schema_output_fields,
)
})
}
pub fn get_field_info(
field_name: &String,
schema: &Schema<I, O, CtxOptions, Timestamp, ErrorTool>,
schema_input_fields: &HashSet<String>,
schema_output_fields: &HashSet<String>,
) -> Option<FieldInfo> {
if let Some(InternalFieldConfig {
alias, depends_on, ..
}) = schema.field_configs.get(field_name)
{
if depends_on.is_none() {
return Some(FieldInfo {
config_name: field_name.clone(),
is_input: schema_input_fields.contains(field_name),
is_output: schema_output_fields.contains(field_name),
name: alias.clone().unwrap_or(field_name.clone()),
});
}
for parent_name in depends_on.as_ref().unwrap() {
match schema.field_configs.get(&parent_name.to_string()) {
Some(InternalFieldConfig {
alias: Some(alias),
field_type: FieldType::Virtual,
validator: Some(validator),
..
}) if alias == field_name => {
return Some(FieldInfo {
config_name: parent_name.to_string(),
is_input: true,
is_output: false,
name: field_name.clone(),
});
}
_ => {}
}
}
}
None
}
}
impl<
'a,
I: IvoSchemaStruct,
O: IvoSchemaStruct,
CtxOptions,
ErrorTool: IvoErrorTool,
Timestamp: Clone + Debug + Send + Sync + 'static,
> Clone for FieldInfoCollection<'a, I, O, CtxOptions, Timestamp, ErrorTool>
{
fn clone(&self) -> Self {
Self {
config_names: self.config_names.clone(),
fields: self.fields.clone(),
schema: self.schema,
schema_input_fields: self.schema_input_fields.clone(),
schema_output_fields: self.schema_output_fields.clone(),
}
}
}
#[derive(Clone, Debug)]
pub(super) struct FieldInfo {
pub name: String,
pub config_name: String,
pub is_input: bool,
pub is_output: bool,
}