chore: rebrand project to crank
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use crate::{Schema, SchemaKind};
|
||||
|
||||
impl Schema {
|
||||
pub fn from_json_sample(value: &Value) -> Self {
|
||||
match value {
|
||||
Value::Null => Self {
|
||||
kind: SchemaKind::Null,
|
||||
description: None,
|
||||
required: true,
|
||||
nullable: true,
|
||||
default_value: None,
|
||||
fields: BTreeMap::new(),
|
||||
items: None,
|
||||
enum_values: Vec::new(),
|
||||
variants: Vec::new(),
|
||||
},
|
||||
Value::Bool(_) => scalar_schema(SchemaKind::Boolean),
|
||||
Value::String(_) => scalar_schema(SchemaKind::String),
|
||||
Value::Number(number) if number.is_i64() || number.is_u64() => {
|
||||
scalar_schema(SchemaKind::Integer)
|
||||
}
|
||||
Value::Number(_) => scalar_schema(SchemaKind::Number),
|
||||
Value::Array(items) => array_schema(items),
|
||||
Value::Object(fields) => object_schema(fields),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn scalar_schema(kind: SchemaKind) -> Schema {
|
||||
Schema {
|
||||
kind,
|
||||
description: None,
|
||||
required: true,
|
||||
nullable: false,
|
||||
default_value: None,
|
||||
fields: BTreeMap::new(),
|
||||
items: None,
|
||||
enum_values: Vec::new(),
|
||||
variants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn array_schema(items: &[Value]) -> Schema {
|
||||
Schema {
|
||||
kind: SchemaKind::Array,
|
||||
description: None,
|
||||
required: true,
|
||||
nullable: false,
|
||||
default_value: None,
|
||||
fields: BTreeMap::new(),
|
||||
items: items
|
||||
.first()
|
||||
.map(|item| Box::new(Schema::from_json_sample(item))),
|
||||
enum_values: Vec::new(),
|
||||
variants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn object_schema(fields: &Map<String, Value>) -> Schema {
|
||||
Schema {
|
||||
kind: SchemaKind::Object,
|
||||
description: None,
|
||||
required: true,
|
||||
nullable: false,
|
||||
default_value: None,
|
||||
fields: fields
|
||||
.iter()
|
||||
.map(|(name, value)| (name.clone(), Schema::from_json_sample(value)))
|
||||
.collect(),
|
||||
items: None,
|
||||
enum_values: Vec::new(),
|
||||
variants: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{Schema, SchemaKind};
|
||||
|
||||
#[test]
|
||||
fn infers_object_schema_from_json_sample() {
|
||||
let schema = Schema::from_json_sample(&json!({
|
||||
"lead": {
|
||||
"email": "user@example.com",
|
||||
"active": true
|
||||
},
|
||||
"score": 42
|
||||
}));
|
||||
|
||||
assert_eq!(schema.kind, SchemaKind::Object);
|
||||
assert_eq!(
|
||||
schema.field("lead").map(|field| field.kind.clone()),
|
||||
Some(SchemaKind::Object)
|
||||
);
|
||||
assert_eq!(
|
||||
schema
|
||||
.field("lead")
|
||||
.and_then(|field| field.field("email"))
|
||||
.map(|field| field.kind.clone()),
|
||||
Some(SchemaKind::String)
|
||||
);
|
||||
assert_eq!(
|
||||
schema.field("score").map(|field| field.kind.clone()),
|
||||
Some(SchemaKind::Integer)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infers_array_item_schema_from_first_sample_item() {
|
||||
let schema = Schema::from_json_sample(&json!([
|
||||
{
|
||||
"id": "lead_01",
|
||||
"tags": ["warm", "priority"]
|
||||
}
|
||||
]));
|
||||
|
||||
assert_eq!(schema.kind, SchemaKind::Array);
|
||||
assert_eq!(
|
||||
schema
|
||||
.items
|
||||
.as_deref()
|
||||
.and_then(|item| item.field("id"))
|
||||
.map(|field| field.kind.clone()),
|
||||
Some(SchemaKind::String)
|
||||
);
|
||||
assert_eq!(
|
||||
schema
|
||||
.items
|
||||
.as_deref()
|
||||
.and_then(|item| item.field("tags"))
|
||||
.map(|field| field.kind.clone()),
|
||||
Some(SchemaKind::Array)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn infers_null_schema_for_null_sample() {
|
||||
let schema = Schema::from_json_sample(&serde_json::Value::Null);
|
||||
|
||||
assert_eq!(
|
||||
schema,
|
||||
Schema {
|
||||
kind: SchemaKind::Null,
|
||||
description: None,
|
||||
required: true,
|
||||
nullable: true,
|
||||
default_value: None,
|
||||
fields: BTreeMap::new(),
|
||||
items: None,
|
||||
enum_values: Vec::new(),
|
||||
variants: Vec::new(),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user