use std::str::FromStr;
use lazy_static::lazy_static;
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::operation::OperationValue;
use crate::schema::{FieldTypeError, SchemaId};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum FieldType {
Bool,
Int,
Float,
String,
Relation(SchemaId),
RelationList(SchemaId),
PinnedRelation(SchemaId),
PinnedRelationList(SchemaId),
}
impl FieldType {
pub fn serialise(&self) -> String {
match self {
FieldType::Bool => "bool".to_string(),
FieldType::Int => "int".to_string(),
FieldType::Float => "float".to_string(),
FieldType::String => "str".to_string(),
FieldType::Relation(schema_id) => format!("relation({})", schema_id.as_str()),
FieldType::RelationList(schema_id) => format!("relation_list({})", schema_id.as_str()),
FieldType::PinnedRelation(schema_id) => {
format!("pinned_relation({})", schema_id.as_str())
}
FieldType::PinnedRelationList(schema_id) => {
format!("pinned_relation_list({})", schema_id.as_str())
}
}
}
}
impl From<FieldType> for OperationValue {
fn from(field_type: FieldType) -> OperationValue {
OperationValue::Text(field_type.serialise())
}
}
impl FromStr for FieldType {
type Err = FieldTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let text_match = match s {
"bool" => Ok(FieldType::Bool),
"int" => Ok(FieldType::Int),
"float" => Ok(FieldType::Float),
"str" => Ok(FieldType::String),
_ => Err(FieldTypeError::InvalidFieldType(s.into())),
};
if text_match.is_ok() {
return text_match;
}
lazy_static! {
static ref RE: Regex = Regex::new(r"(\w+)(\((.+)\))?").unwrap();
}
let groups = RE.captures(s).unwrap();
let name = groups.get(1).map(|m| m.as_str());
let parameter = groups.get(3).map(|m| m.as_str());
match (name, parameter) {
(Some("relation"), Some(schema_id)) => {
Ok(FieldType::Relation(SchemaId::new(schema_id)?))
}
(Some("relation_list"), Some(schema_id)) => {
Ok(FieldType::RelationList(SchemaId::new(schema_id)?))
}
(Some("pinned_relation"), Some(schema_id)) => {
Ok(FieldType::PinnedRelation(SchemaId::new(schema_id)?))
}
(Some("pinned_relation_list"), Some(schema_id)) => {
Ok(FieldType::PinnedRelationList(SchemaId::new(schema_id)?))
}
_ => Err(FieldTypeError::InvalidFieldType(s.into())),
}
}
}
#[cfg(test)]
mod tests {
use crate::operation::OperationValue;
use crate::schema::{FieldType, SchemaId};
use crate::Validate;
#[test]
fn serialises() {
assert_eq!(FieldType::Bool.serialise(), "bool");
assert!(OperationValue::from(FieldType::Bool).validate().is_ok());
assert_eq!(FieldType::Int.serialise(), "int");
assert_eq!(FieldType::Float.serialise(), "float");
assert_eq!(FieldType::String.serialise(), "str");
assert_eq!(
FieldType::Relation(SchemaId::SchemaFieldDefinition(1)).serialise(),
"relation(schema_field_definition_v1)"
);
assert_eq!(
FieldType::RelationList(SchemaId::SchemaFieldDefinition(1)).serialise(),
"relation_list(schema_field_definition_v1)"
);
assert_eq!(
FieldType::PinnedRelation(SchemaId::SchemaFieldDefinition(1)).serialise(),
"pinned_relation(schema_field_definition_v1)"
);
assert_eq!(
FieldType::PinnedRelationList(SchemaId::SchemaFieldDefinition(1)).serialise(),
"pinned_relation_list(schema_field_definition_v1)"
);
}
#[test]
fn deserialises() {
assert_eq!(FieldType::Bool, "bool".parse().unwrap());
assert_eq!(FieldType::Int, "int".parse().unwrap());
assert_eq!(FieldType::Float, "float".parse().unwrap());
assert_eq!(FieldType::String, "str".parse().unwrap());
assert_eq!(
FieldType::Relation(SchemaId::SchemaFieldDefinition(1)),
"relation(schema_field_definition_v1)".parse().unwrap()
);
assert_eq!(
FieldType::RelationList(SchemaId::SchemaFieldDefinition(1)),
"relation_list(schema_field_definition_v1)".parse().unwrap()
);
assert_eq!(
FieldType::PinnedRelation(SchemaId::SchemaFieldDefinition(1)),
"pinned_relation(schema_field_definition_v1)"
.parse()
.unwrap()
);
assert_eq!(
FieldType::PinnedRelationList(SchemaId::SchemaFieldDefinition(1)),
"pinned_relation_list(schema_field_definition_v1)"
.parse()
.unwrap()
);
let invalid = "relation(no_no_no)".parse::<FieldType>();
assert_eq!(
invalid.unwrap_err().to_string(),
"encountered invalid hash while parsing application schema id: invalid hex encoding \
in hash string"
);
}
#[test]
fn invalid_type_string() {
assert!("poopy".parse::<FieldType>().is_err());
}
}