use std::collections::HashMap;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct Schema {
pub lexicon: u32,
pub id: String,
#[serde(default)]
pub revision: Option<u32>,
#[serde(default)]
pub description: Option<String>,
pub defs: HashMap<String, Def>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
#[allow(clippy::enum_variant_names)]
pub enum Def {
#[serde(rename = "record")]
Record(RecordDef),
#[serde(rename = "query")]
Query(QueryDef),
#[serde(rename = "procedure")]
Procedure(ProcedureDef),
#[serde(rename = "subscription")]
Subscription(SubscriptionDef),
#[serde(rename = "object")]
Object(ObjectDef),
#[serde(rename = "token")]
Token(TokenDef),
#[serde(rename = "string")]
StringDef(StringTypeDef),
#[serde(rename = "boolean")]
BooleanDef(BooleanTypeDef),
#[serde(rename = "integer")]
IntegerDef(IntegerTypeDef),
#[serde(rename = "bytes")]
BytesDef(BytesTypeDef),
#[serde(rename = "array")]
ArrayDef(ArrayTypeDef),
#[serde(other)]
Unknown,
}
#[derive(Debug, Deserialize)]
pub struct RecordDef {
#[serde(default)]
pub key: Option<String>,
pub record: ObjectDef,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ObjectDef {
#[serde(default)]
pub required: Vec<String>,
#[serde(default)]
pub nullable: Vec<String>,
#[serde(default)]
pub properties: HashMap<String, FieldSchema>,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum FieldSchema {
#[serde(rename = "string")]
String {
#[serde(default, rename = "minLength")]
min_length: Option<u64>,
#[serde(default, rename = "maxLength")]
max_length: Option<u64>,
#[serde(default, rename = "maxGraphemes")]
max_graphemes: Option<u64>,
#[serde(default, rename = "knownValues")]
known_values: Vec<String>,
#[serde(default)]
r#enum: Option<Vec<String>>,
#[serde(default)]
format: Option<String>,
#[serde(default)]
description: Option<String>,
#[serde(default)]
default: Option<String>,
#[serde(default, rename = "const")]
const_val: Option<String>,
},
#[serde(rename = "integer")]
Integer {
#[serde(default)]
minimum: Option<i64>,
#[serde(default)]
maximum: Option<i64>,
#[serde(default)]
r#enum: Option<Vec<i64>>,
#[serde(default)]
default: Option<i64>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "boolean")]
Boolean {
#[serde(default)]
default: Option<bool>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "bytes")]
Bytes {
#[serde(default, rename = "minLength")]
min_length: Option<u64>,
#[serde(default, rename = "maxLength")]
max_length: Option<u64>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "cid-link")]
CidLink {
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "blob")]
Blob {
#[serde(default)]
accept: Option<Vec<String>>,
#[serde(default, rename = "maxSize")]
max_size: Option<u64>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "array")]
Array {
items: Box<FieldSchema>,
#[serde(default, rename = "minLength")]
min_length: Option<u64>,
#[serde(default, rename = "maxLength")]
max_length: Option<u64>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "object")]
Object(ObjectDef),
#[serde(rename = "ref")]
Ref {
#[serde(rename = "ref")]
reference: String,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "union")]
Union {
refs: Vec<String>,
#[serde(default)]
closed: Option<bool>,
#[serde(default)]
description: Option<String>,
},
#[serde(rename = "unknown")]
Unknown {
#[serde(default)]
description: Option<String>,
},
}
impl FieldSchema {
pub fn description(&self) -> Option<&str> {
match self {
FieldSchema::String { description, .. }
| FieldSchema::Integer { description, .. }
| FieldSchema::Boolean { description, .. }
| FieldSchema::Bytes { description, .. }
| FieldSchema::CidLink { description, .. }
| FieldSchema::Blob { description, .. }
| FieldSchema::Array { description, .. }
| FieldSchema::Ref { description, .. }
| FieldSchema::Union { description, .. }
| FieldSchema::Unknown { description, .. } => description.as_deref(),
FieldSchema::Object(_) => None,
}
}
}
#[derive(Debug, Deserialize)]
pub struct QueryDef {
#[serde(default)]
pub parameters: Option<ParamsDef>,
#[serde(default)]
pub output: Option<BodyDef>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub errors: Vec<ErrorDef>,
}
#[derive(Debug, Deserialize)]
pub struct ProcedureDef {
#[serde(default)]
pub input: Option<BodyDef>,
#[serde(default)]
pub output: Option<BodyDef>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub errors: Vec<ErrorDef>,
}
#[derive(Debug, Deserialize)]
pub struct SubscriptionDef {
#[serde(default)]
pub parameters: Option<ParamsDef>,
#[serde(default)]
pub message: Option<MessageDef>,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub errors: Vec<ErrorDef>,
}
#[derive(Debug, Deserialize)]
pub struct BodyDef {
pub encoding: String,
#[serde(default)]
pub schema: Option<FieldSchema>,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ParamsDef {
#[serde(default)]
pub required: Vec<String>,
#[serde(default)]
pub properties: HashMap<String, FieldSchema>,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct MessageDef {
#[serde(default)]
pub schema: Option<FieldSchema>,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ErrorDef {
pub name: String,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct TokenDef {
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct StringTypeDef {
#[serde(default)]
pub description: Option<String>,
#[serde(default, rename = "knownValues")]
pub known_values: Vec<String>,
}
#[derive(Debug, Deserialize)]
pub struct BooleanTypeDef {
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct IntegerTypeDef {
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct BytesTypeDef {
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Deserialize)]
pub struct ArrayTypeDef {
pub items: FieldSchema,
#[serde(default)]
pub description: Option<String>,
}
pub fn split_ref<'a>(context_nsid: &str, reference: &'a str) -> (String, &'a str) {
if let Some(def_name) = reference.strip_prefix('#') {
(context_nsid.to_owned(), def_name)
} else if let Some(hash_pos) = reference.rfind('#') {
(reference[..hash_pos].to_owned(), &reference[hash_pos + 1..])
} else {
(reference.to_owned(), "main")
}
}