Skip to main content
The Schema struct provides JSON Schema-based validation for documents in collections.

Creating a schema

use jasonisnthappy::{Schema, ValueType};
use std::collections::HashMap;

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);

Schema fields

value_type
Option<ValueType>
Expected type of the value
required
Option<Vec<String>>
List of required fields (for objects)
properties
Option<HashMap<String, Schema>>
Schema for object properties
items
Option<Box<Schema>>
Schema for array items
minimum
Option<f64>
Minimum value for numbers
maximum
Option<f64>
Maximum value for numbers
min_length
Option<usize>
Minimum length for strings and arrays
max_length
Option<usize>
Maximum length for strings and arrays
enum_values
Option<Vec<Value>>
Allowed values (enum)

ValueType enum

ValueType::String
enum variant
String value
ValueType::Number
enum variant
Numeric value (integer or float)
ValueType::Integer
enum variant
Integer value (stricter than Number)
ValueType::Boolean
enum variant
Boolean value
ValueType::Object
enum variant
Object/map value
ValueType::Array
enum variant
Array value
ValueType::Null
enum variant
Null value

Validation methods

validate

Validate a document against the schema.
pub fn validate(&self, value: &Value) -> Result<()>
value
&Value
required
The value to validate
Returns: Result<()> - Ok if valid, or Error::SchemaValidation with details

Examples

Basic type validation

use jasonisnthappy::{Schema, ValueType};
use serde_json::json;

let mut schema = Schema::new();
schema.value_type = Some(ValueType::String);

// Valid
assert!(schema.validate(&json!("hello")).is_ok());

// Invalid
assert!(schema.validate(&json!(42)).is_err());

Required fields

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);
schema.required = Some(vec!["name".to_string(), "email".to_string()]);

// Valid
let valid_doc = json!({
    "name": "Alice",
    "email": "alice@example.com"
});
assert!(schema.validate(&valid_doc).is_ok());

// Invalid - missing required field
let invalid_doc = json!({"name": "Alice"});
assert!(schema.validate(&invalid_doc).is_err());

Property validation

use std::collections::HashMap;

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);

let mut properties = HashMap::new();

// Name must be a non-empty string
let mut name_schema = Schema::new();
name_schema.value_type = Some(ValueType::String);
name_schema.min_length = Some(1);
properties.insert("name".to_string(), name_schema);

// Age must be a number between 0 and 150
let mut age_schema = Schema::new();
age_schema.value_type = Some(ValueType::Number);
age_schema.minimum = Some(0.0);
age_schema.maximum = Some(150.0);
properties.insert("age".to_string(), age_schema);

schema.properties = Some(properties);

// Valid
let doc = json!({"name": "Alice", "age": 30});
assert!(schema.validate(&doc).is_ok());

// Invalid - age out of range
let doc = json!({"name": "Alice", "age": 200});
assert!(schema.validate(&doc).is_err());

Number validation

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Number);
schema.minimum = Some(0.0);
schema.maximum = Some(100.0);

assert!(schema.validate(&json!(50)).is_ok());
assert!(schema.validate(&json!(-1)).is_err());
assert!(schema.validate(&json!(101)).is_err());

String validation

let mut schema = Schema::new();
schema.value_type = Some(ValueType::String);
schema.min_length = Some(3);
schema.max_length = Some(10);

assert!(schema.validate(&json!("hello")).is_ok());
assert!(schema.validate(&json!("hi")).is_err()); // Too short
assert!(schema.validate(&json!("this is too long")).is_err());

Array validation

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Array);
schema.min_length = Some(1);
schema.max_length = Some(5);

// Items must be numbers
let mut item_schema = Schema::new();
item_schema.value_type = Some(ValueType::Number);
schema.items = Some(Box::new(item_schema));

assert!(schema.validate(&json!([1, 2, 3])).is_ok());
assert!(schema.validate(&json!([])).is_err()); // Too short
assert!(schema.validate(&json!([1, 2, 3, 4, 5, 6])).is_err()); // Too long
assert!(schema.validate(&json!([1, "two", 3])).is_err()); // Wrong item type

Enum validation

let mut schema = Schema::new();
schema.enum_values = Some(vec![
    json!("pending"),
    json!("active"),
    json!("completed"),
]);

assert!(schema.validate(&json!("pending")).is_ok());
assert!(schema.validate(&json!("active")).is_ok());
assert!(schema.validate(&json!("invalid")).is_err());

Integer validation

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Integer);

assert!(schema.validate(&json!(42)).is_ok());
assert!(schema.validate(&json!(-10)).is_ok());
assert!(schema.validate(&json!(3.14)).is_err()); // Not an integer

Nested object validation

use std::collections::HashMap;

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);

let mut address_schema = Schema::new();
address_schema.value_type = Some(ValueType::Object);
address_schema.required = Some(vec!["city".to_string()]);

let mut city_schema = Schema::new();
city_schema.value_type = Some(ValueType::String);

let mut address_props = HashMap::new();
address_props.insert("city".to_string(), city_schema);
address_schema.properties = Some(address_props);

let mut properties = HashMap::new();
properties.insert("address".to_string(), address_schema);
schema.properties = Some(properties);

// Valid
let doc = json!({"address": {"city": "NYC"}});
assert!(schema.validate(&doc).is_ok());

// Invalid - missing required nested field
let doc = json!({"address": {}});
assert!(schema.validate(&doc).is_err());

Setting a schema on a collection

use jasonisnthappy::{Database, Schema, ValueType};
use std::collections::HashMap;

let db = Database::open("my.db")?;

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);
schema.required = Some(vec!["name".to_string(), "email".to_string()]);

let mut properties = HashMap::new();

let mut name_schema = Schema::new();
name_schema.value_type = Some(ValueType::String);
name_schema.min_length = Some(1);
properties.insert("name".to_string(), name_schema);

let mut email_schema = Schema::new();
email_schema.value_type = Some(ValueType::String);
email_schema.min_length = Some(3);
properties.insert("email".to_string(), email_schema);

schema.properties = Some(properties);

// Set schema on collection
db.set_schema("users", schema)?;

// Now all inserts/updates will be validated
let users = db.collection("users");

// Valid insert
users.insert(json!({
    "name": "Alice",
    "email": "alice@example.com"
}))?;

// Invalid insert - will fail validation
let result = users.insert(json!({
    "name": "Bob"
    // Missing required 'email' field
}));
assert!(result.is_err());

Schema serialization

Schemas can be serialized to/from JSON:
use jasonisnthappy::{Schema, ValueType};

let mut schema = Schema::new();
schema.value_type = Some(ValueType::Object);
schema.required = Some(vec!["name".to_string()]);

// Serialize to JSON
let json_str = serde_json::to_string(&schema)?;

// Deserialize from JSON
let deserialized: Schema = serde_json::from_str(&json_str)?;

Build docs developers (and LLMs) love