machiavelli
Lightweight application-level schema for Javascript models.
Why not Mongoose or another ORM
ORMs don't cover completely the features that the official drivers have. Furthermore, ORMs are notorious for being slow compared to official drivers, and tend to be irregularly maintained as time goes on to be more prone to bugs.
This module is made for those who are frustrated by reading two docs to communicate with one database. Having a separate Schema from built-in database schemas can be advantageous; data can be validated directly from your application instead of unnecessarily over network requests.
Getting Started
Don't be disheartened by all the constructors, they are there to modularize the logic and allow easy implementation of nested validation.
var Schema = Schemavar Field = SchemaField;var postingSchema = title: type: String price: type: Number description: type: String required: false ;
Synchronous validation
var postingDocument = title: 'Old windows mouse' price: 20 ;if postingSchema /* save posting to database */ else /* handle error */
Asynchronous validation
postingSchema;
Schema inheritance
The inherits method need to be declared after schema declaration. Will not overwrite existing fields, but will inherit validation requirements of other fields.
var ticketSchema = artist: type: String ;ticketSchema;
Extending schemas
A schema can be extended with new fields using the method addField()
ticketSchema;
Why use a Schema at all
Light-weight schemas can provide another protection layer for malicious database injections.
Using DataType
Required is now true by default.
var DataType = DataType;var ticketSchema = _id: type: DataTypeObjectID title: type: DataTypeString price: type: DataTypeInteger required: false createdAt: type: DataTypeDate owner: _id: type: DataTypeObjectID username: type: DataTypeString ;
Machiavelli-Defined Types
- Function
- String
- Integer
- Double
- Date
- Boolean
- Array
Defining new data types
Simply define a function that returns true if object is of type data type, else returns false. Here we define a new DataType called Coordinate.
DataTypeCoordinate = { var longitude = coord0; var latitude = coord1; return longitude >= -180 && longitude <= 180 && latitude >= -90 && latitude <= 90};
Your own wrappers
If your data is already wrapped in your own constructor, there is no need to define a new function.
var { thisspecie = specie }var zooSchema = animal: type: Animal ;
Collection Validation @notImplemented
DataType.isValidCollection() validates type on a collection level
Optional keys
We have seen the the 'required' field, a boolean determining if Schema should fail if the field is not specified. Specifying the 'required' field, unlike the 'type' field, is optional since the default is set to true. There are many other arguments we could use to enhance our schema.
validators - Custom validators
The argument to 'validate' should always be in an array, even if it only contains one element.
Functions specified under the validate argument should return a boolean that specifies whether or not the data is valid. Custom validators can be made by the Validator constructor which takes in arguments isValid as your validation function and error as your error throwing object.
var { return price >= 0; };var Validator = FieldValidator;var smallerThanTen = { return price < 10 } error: 'Value not smaller than 10'; var coffeeSchema = flavor: type: String price: type: Number validators: isPostive smallerThanTen ;;
required - Default is true
Specify required to be false if you want the Schema to not require the field in a document. If value passed to 'default' is a function, the schema will invocate the field's value at runtime.
var dateSchema = date: type: Number default: Datenow ;;
default
Specify default value for capture function to pass in second argument of validate.
Constructor tree
Accessing the constructors from the module. They are organized less for accessibility than for logic. You will never need to use Validator without using Field, and never Field without using Schema. As for DataType, I found it can be used without Schema.
Schema Field Validator DataType
2.0.4
Nested schemas
Schemas can now specify attributes as nested schemas
var helloSchema = world: worldSchema
Philosophy
Why so many constructors? While JavaScript is a dynamically-typed language, it can be extremely beneficial to separate concerns by using constructors as dependency injections. Hacking JavaScript can be both fast AND reliable!