githubEdit

Schemas

Stof objects as schemas.

The intersection of functions and data in Stof documents presents an interesting opportunity for a metacode approach to applying and defining schemas.

circle-info

Check out the Object Library (Obj) for more details on Obj.schemafy(..).

Schemas in Stof can be used in a lot of use cases: validation, bulk transformations, renaming fields, filtering, etc.

FirstSchema: {
    #[schema((target_value: str): bool => target_value.len() > 2)]
    /// First name - valid if the length is greater than 2.
    first: "First"
    
    #[schema((
        // can use tuples & lists to create pipelines (&& w/short circuits)
        (target_value: unknown): bool => (typeof target_value) == "str",
        (target_value: str): bool => {"Last", "Example"}.contains(target_value),
    ))]
    /// Last name - valid if a string that is either "Last" or "Example".
    last: "Last"
}

#[main]
fn main() {
    const target = new { first: "Bob", last: "Example" };
    assert(self.FirstSchema.schemafy(target)); // returns true (valid)
    
    target.first = "AJ";
    assert_not(self.FirstSchema.schemafy(target)); // returns false (invalid)
    
    target.first = "Bob";
    target.last = "NotInSet";
    assert_not(self.FirstSchema.schemafy(target)); // invalid

    target.last = 53;
    assert_not(self.FirstSchema.schemafy(target)); // not a str (second fn never gets called)
}
circle-info

Schema pipelines, functions, and metadata can come from anywhere in the document and can be composed.

Schema Functions

Functions used in a schema attribute can take many forms - the schemafy operation in the Obj library does its best to fit its behavior to your use case rather than the other way around.

It does this by examining the given argument names and types to associate values with their intended parameters correctly.

Complete Signature

In the example below, all possible parameters are given.

  • schema: obj - this is the schema object (Schema in this case).

  • target: obj - this is the target object (the one being manipulated/validated).

  • field: str - this is the field name ("field" in this case).

  • schema_val: unknown - this is the field value on the schema object ("default" in this case).

  • target_val: unknown - this is the field value on the target object, or null if the field doesn't exist.

circle-info

Any subset or permutation of these parameters will work.

circle-info

If the parameter is a value (schema value or target value), add "val" (Ex. "value") to the parameter name and it will always work regardless of type.

Sub Schemas

You might be wondering about recursive schema applications with object fields that are also schemas. If so, there's a shorthand way to apply sub-schemas recursively - the null #[schema] attribute.

External Field Schema

An object value within the #[schema(..)] attribute will be interpreted as an external schema to use for that field only.

circle-info

For many external schemas on a field, use a list of schema objects as the #[schema([..])] attribute value.

Combinations

Use lists, tuples, and sets to create, combine, and compose schema/validation pipelines.

circle-info

Each schema attribute value is applied recursively, so use lists within lists within lists if you must.

Remove Invalid Fields

Schemafy can optionally remove invalid fields for you with remove_invalid = true, always modifying the target object to be valid.

Remove Not-defined Fields

Schemafy can also optionally remove any fields that are not defined in the schema, with remove_undefined = true.

Last updated