alamid-schema
Version:
Extendable mongoose-like schemas for node.js and the browser
382 lines (288 loc) • 7.99 kB
Markdown
alamid-schema
=============
**Extendable mongoose-like schemas for node.js and the browser**
[](https://npmjs.org/package/alamid-schema)<br>
[](http://travis-ci.org/peerigon/alamid-schema)
[](http://david-dm.org/peerigon/alamid-schema)
[](https://david-dm.org/peerigon/alamid-schema#info=devDependencies)
If you like [mongoose](http://mongoosejs.com/) schemas and you want to use them standalone, **alamid-schema** is the right module for you.
__alamid-schema__ helps you with
- validation of data
- using mongoose-like schemas without using mongoose
- sharing data-definition between client & server
- normalizing data (coming soon)
- striping readable/writeable fields (coming soon)
Use it on the server to...
- normalize and validate incoming requests
- strip private fields from the response
Use it on the client to...
- validate forms
- define view models
```javascript
var Schema = require("alamid-schema");
var Panda = new Schema("Panda", {
name: String,
age: {
type: Number,
required: true,
writable: false,
readable: true
},
mood: {
type: String,
enum: ["grumpy", "happy"]
},
birthday: Date
});
```
## Examples
### Schema Definition
You can define your schema with concrete values...
```javascript
var PandaSchema = new Schema({
name: "panda",
age: 12,
friends: {
type: []
}
});
```
...or with abstract types...
```javascript
var PandaSchema = new Schema({
name: String,
age: Number,
friends: {
type: Array
}
});
```
### Extend
Sometimes you want to extend your Schema and add new properties.
```javascript
var PandaSchema = new Schema({
name: String,
age: Number,
friends: {
type: Array
}
});
var SuperPanda = PandaSchema.extend("SuperPanda", {
xRay: true,
canFly: {
type: Boolean
}
});
```
We have a superpanda now... which can fly and has xray eyes!
That's basically the same as...
```javascript
var SuperPanda = new Schema({
name: String,
age: Number,
friends: {
type: Array
},
xRay: true, //added
canFly: { //added
type: Boolean
}
});
```
__Overwriting properties__
If you define a property in the schema you are extending with, the extending schema takes precedence.
```javascript
var Animal = new Schema({
name: String,
age: String
});
var Panda = Animal.extend("Panda", {
age: Number
color: String
});
```
equals...
```javascript
var Panda = new Schema("Panda", {
name: String,
age: Number, //overwritten
color: String //added
});
```
### Plugin: Validation
The validation plugins adds - *suprise!* - validation support.
```javascript
var Schema = require("alamid-schema");
Schema.use(require("alamid-schema/plugins/validation"));
var PandaSchema = new Schema({
name: {
type: String,
required: true
},
age: {
type: Number,
min: 9,
max: 99
},
mood: {
type: String,
enum: ["happy", "sleepy"]
},
treasures: {
type: Array,
minLength: 3
},
birthday: Date
});
var panda = {
name: "Hugo",
age: 3,
mood: "happy"
};
PandaSchema.validate(panda, function(validation) {
if (!validation.result) {
console.log(validation.errors);
return;
}
console.log("happy panda");
});
```
outputs...
```javascript
{
result: false,
errors: {
age: [ 'min' ]
}
}
```
_Included validators:_
- required
- min (works on Number)
- max (works on Number)
- enum
- minLength (works on String, Array)
- maxLength (works on String, Array)
- hasLength (works on String, Array)
- matches (performs a strict comparison, also accepts RegExp)
_Writing custom validators:_
You can write sync and async validators..
```javascript
// sync
function oldEnough(age) {
return age > 18 || "too-young";
}
// async
function nameIsUnique(name, callback) {
fs.readFile(__dirname + "/names.json", function(err, names) {
if(err) {
throw err;
}
names = JSON.parse(names);
callback(names.indexOf(name) === -1 || "name-already-taken");
});
}
var PandaSchema = new Schema({
name: {
type: String,
required: true,
validate: nameIsUnique
},
age: {
type: Number,
validate: oldEnough,
max: 99
}
});
var panda = {
name: "hugo",
age: 3,
mood: "happy"
};
PandaSchema.validate(panda, function(validation) {
if(!validation.result) {
console.log(validation.errors);
return;
}
console.log("happy panda");
});
```
outputs...
```javascript
{
name: [ "name-already-taken" ],
age: [ "too-young" ]
}
```
_Note:_ validators will be called with `this` bound to `model`.
### Promises
The `validate()` method also returns a promise:
```javascript
PandaSchema.validate(panda)
.then(function (validation) {
...
})
```
The promise will still be resolved even when the validation fails, because a failed validation is
not an error, it's an expected state.
The promise provides a reference to the final validation result object. It contains the intermediate
result of all synchronous validators:
```javascript
var promise = PandaSchema.validate(panda);
if (promise.validation.result) {
console.log("Synchronous validation of " + Object.keys(validation.errors) + " failed");
}
```
__Important notice:__ You must bring your own ES6 Promise compatible polyfill!
## API
### Core
#### Schema([name: String, ]definition: Object)
Creates a new schema.
#### .fields: Array
The array of property names that are defined on the schema. Do not modify this array.
#### .only(key1: Array|String[, key2: String, key3: String, ...]): Schema
Returns a subset with the given keys of the current schema. You may pass an array with keys or just the keys as arguments.
#### .extend([name: String, ]definition: Object): Schema
Creates a new schema that inherits from the current schema. Field definitions are merged where appropriate.
If a definition conflicts with the parent definition, the child's definition supersedes.
#### .strip(model: Object)
Removes all properties from `model` that are not defined in `fields`. Will not remove properties that are inherited from the prototype.
### Readable & Writable fields
You can define readable and writable fields in the schema. By default, every field is read- and writable.
```javascript
var PandaSchema = new Schema({
id: {
type: Number,
required: true,
readable: true,
writable: false
},
lastModified: {
readable: true,
writable: false
}
};
```
#### .writableFields()
Returns an array containing the keys of all writable fields:
```javascript
PandaSchema.writableFields(); // ["name", "age", "mood", "treasures", "birthday"]
```
#### .writable()
Creates a new schema that contains only the writable fields:
```javascript
var PandaWritableSchema = PandaSchema.writable();
```
#### .readableFields()
Returns an array containing the keys of all readable fields:
```javascript
PandaSchema.readableFields(); // ["name", "age", "mood", "treasures", "birthday"]
```
#### .readable()
Creates a new schema that contains only the readable fields:
```javascript
var PandaReadableSchema = PandaSchema.readable();
```
### Plugin: Validation
#### .validate(model: Object[, callback: Function]): Promise
Validate given model using the schema definitions. Callback will be called/Promise will be fulfilled with a validation object with `result` (Boolean) and `errors` (Object) containing the error codes.