use crate::*;
use std::ops::{Deref, DerefMut};
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Schema {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub deprecated: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub description: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub name: Option<String>,
#[cfg_attr(feature = "serde", serde(default, skip_serializing))]
pub nullable: bool,
pub ty: SchemaType,
}
impl Schema {
pub fn new(ty: impl Into<SchemaType>) -> Self {
Self {
ty: ty.into(),
..Default::default()
}
}
pub fn array(value: ArrayType) -> Self {
Self::new(SchemaType::Array(Box::new(value)))
}
pub fn boolean(value: BooleanType) -> Self {
Self::new(SchemaType::Boolean(Box::new(value)))
}
pub fn enumerable(value: EnumType) -> Self {
Self::new(SchemaType::Enum(Box::new(value)))
}
pub fn float(value: FloatType) -> Self {
Self::new(SchemaType::Float(Box::new(value)))
}
pub fn integer(value: IntegerType) -> Self {
Self::new(SchemaType::Integer(Box::new(value)))
}
pub fn literal(value: LiteralType) -> Self {
Self::new(SchemaType::Literal(Box::new(value)))
}
pub fn literal_value(value: LiteralValue) -> Self {
Self::new(SchemaType::Literal(Box::new(LiteralType::new(value))))
}
pub fn object(value: ObjectType) -> Self {
Self::new(SchemaType::Object(Box::new(value)))
}
pub fn string(value: StringType) -> Self {
Self::new(SchemaType::String(Box::new(value)))
}
pub fn structure(value: StructType) -> Self {
Self::new(SchemaType::Struct(Box::new(value)))
}
pub fn tuple(value: TupleType) -> Self {
Self::new(SchemaType::Tuple(Box::new(value)))
}
pub fn union(value: UnionType) -> Self {
Self::new(SchemaType::Union(Box::new(value)))
}
pub fn null() -> Self {
Self::new(SchemaType::Null)
}
pub fn unknown() -> Self {
Self::new(SchemaType::Unknown)
}
pub fn nullify(&mut self) {
if self.nullable {
return;
}
self.nullable = true;
if let SchemaType::Union(inner) = &mut self.ty {
if self.name.is_none() {
if !inner.variants_types.iter().any(|t| t.is_null()) {
inner.variants_types.push(Box::new(Schema::null()));
}
return;
}
}
let mut new_schema = Schema::new(std::mem::replace(&mut self.ty, SchemaType::Unknown));
new_schema.name = self.name.take();
new_schema.description.clone_from(&self.description);
new_schema.deprecated.clone_from(&self.deprecated);
self.ty = SchemaType::Union(Box::new(UnionType::new_any([new_schema, Schema::null()])));
}
pub fn partialize(&mut self) {
match &mut self.ty {
SchemaType::Array(ref mut inner) => inner.items_type.partialize(),
SchemaType::Object(ref mut inner) => inner.value_type.partialize(),
SchemaType::Struct(ref mut inner) => {
inner.partial = true;
}
SchemaType::Union(ref mut inner) => {
inner.partial = true;
let is_nullable = inner.variants_types.iter().any(|t| t.ty.is_null());
if is_nullable {
for item in inner.variants_types.iter_mut() {
if !item.is_null() {
item.partialize();
}
}
}
}
_ => {}
};
}
}
impl Deref for Schema {
type Target = SchemaType;
fn deref(&self) -> &Self::Target {
&self.ty
}
}
impl DerefMut for Schema {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.ty
}
}
impl From<Schema> for SchemaType {
fn from(val: Schema) -> Self {
val.ty
}
}
impl Schematic for Schema {}
fn is_false(value: &bool) -> bool {
!value
}
#[derive(Clone, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct SchemaField {
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub comment: Option<String>,
pub schema: Schema,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub deprecated: Option<String>,
#[cfg_attr(
feature = "serde",
serde(default, skip_serializing_if = "Option::is_none")
)]
pub env_var: Option<String>,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
pub hidden: bool,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
pub nullable: bool,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
pub optional: bool,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
pub read_only: bool,
#[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "is_false"))]
pub write_only: bool,
}
impl SchemaField {
pub fn new(schema: impl Into<Schema>) -> Self {
Self {
schema: schema.into(),
..Default::default()
}
}
}
impl From<SchemaField> for Schema {
fn from(val: SchemaField) -> Self {
val.schema
}
}
impl From<Schema> for SchemaField {
fn from(mut schema: Schema) -> Self {
SchemaField {
comment: schema.description.take(),
schema,
..Default::default()
}
}
}
impl Schematic for SchemaField {}