Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/johnhof/mongoman
A node utility to simplify model and schema management
https://github.com/johnhof/mongoman
Last synced: about 1 month ago
JSON representation
A node utility to simplify model and schema management
- Host: GitHub
- URL: https://github.com/johnhof/mongoman
- Owner: johnhof
- License: mit
- Created: 2014-12-28T16:01:59.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2015-04-14T14:27:08.000Z (over 9 years ago)
- Last Synced: 2024-09-28T20:43:13.580Z (about 2 months ago)
- Language: JavaScript
- Size: 537 KB
- Stars: 5
- Watchers: 3
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-MIT
Awesome Lists containing this project
README
Mongoman
========[![Build Status](https://travis-ci.org/johnhof/mongoman.svg)](https://travis-ci.org/johnhof/mongoman)
A node utility to simplify schema and model management. Most utility is wrapped around the [mongoose module](http://mongoosejs.com/index.html). If you would like to use mongoman as a replacement for mongoose, mongoose is aliased at both `mon.mongoose` and `mon.goose`
# Key
- [Usage](#usage)
- [Property Builder](#property-builder)
- [Universal](#universal)
- [`prop.set(key, value)`](#propsetkey-value)
- [`prop.validate(errorMsg, valFunction)`](#propvalidateerrormsg-valfunction)
- [`prop.index(key|value, [value])`](#propindexkeyvalue-value)
- [Types](#types)
- [`prop.string()`](#propstring)
- [`prop.date()`](#propdate)
- [`prop.number()`](#propnumber)
- [`prop.buffer()`](#propbuffer)
- [`prop.mixed()`](#propmixed)
- [`prop.objectId()`](#propobjectid)
- [`prop.array()`](#proparray)
- [`prop.schema()`](#propschemaref-type)
- [Middleware](#middleware)
- [Shared](#shared)
- [`prop.onGet(function)`](#propongetfunction)
- [`prop.onSet(function)`](#proponsetfunction)
- [Date](#date)
- [`expires(dateTime)`](#propexpiresdateTime)
- [String](#string)
- [`prop.toUppercase()`](#proptouppercase)
- [`prop.toLowercase()`](#proptolowercase)
- [`prop.trim()`](#proptrim)
- [Validation](#validation)
- [Shared](#shared)
- [`prop.required()`](#proprequired)
- [`prop.default(value)`](#propdefaultvalue)
- [`prop.select([value])`](#propselectvalue)
- [`prop.enum(values, [message])`](#propenumvalues-message)
- [`prop.unique([bool])`](#propuniquebool)
- [`prop.ref(model)`](#proprefmodel)
- [`prop.min(value, [message])`](#propminvalue-message)
- [`prop.max(value, [message])`](#propmaxvalue-message)
- [`prop.length(value)`](#proplengthvalue-message)
- [Arrays](#arrays)
- [`prop.sparse([enables])`](#propsparseenabled)
- [Strings](#strings)
- [`prop.alphanum([message])`](#propalphanummessage)
- [`prop.regex(expression, [message])`](#propregexexpression-message)
- [`prop.email([message])`](#propemailmessage)
- [`prop.token([message])`](#proptokenmessage)
- [`prop.guid([message])`](#propguidmessage)
- [`prop.hostname([message])`](#prophostnamemessage)
- [`prop.url([message])`](#propurlmessage)
- [`prop.uppercase([message])`](#propuppercasemessage)
- [`prop.lowercase([message])`](#proplowercasemessage)
- [Numbers](#numbers)
- [`prop.greater(limit, [message])`](#propgreaterlimit-message)
- [`prop.less(limit, [message])`](#proplesslimit-message)
- [`prop.integer([message])`](#propintegermessage)
- [Utilities](#utilities)
- [`mon.drop(collection)`](#mondropcollection)
- [`mon.connect([options])`](#monconnectoptions)
- [`mon.schema(schema)`](#monschemaschema)
- [`mon.model(modelName)`](#monmodelmodelname)
- [`mon.new(modelName)`](#monnewmodelname)
- [`mon.register(schema, [options])`](#monregisterschema-options)
- [`mon.registerAll(directory, [regex])`](#monregisteralldirectory-regex)
- [Tests](#running-unit-tests)# Usage
`npm install mongoman`
leverage mongoman to cut down on bloat in model creation. For example, this
```javascript
var mongoose = require('mongoose');var newSchema = new mongoose.Schema({
email : {
type : String,
required : true,
validation : [{
msg : 'invalid email',
validator : function (value) {
return /^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/.test(value);
}
}]
password : {
type : String,
required : true,
validation : [{
msg : 'too short',
validator : function (value) {
return value.length >= 6
}
}]
}
});mongoose.model('ExampleModel', newSchema);
```becomes this
```javascript
var mon = require('mongoman');mon.register('ExampleModel', {
email : mon().string().required().email().fin(),
password : mon().string().required().min(6).fin()
});
```The focus of mongoman is to simplify validation and schema creation. However, I do recommed looking at the [utilities](#utilities) section for some helpful utilities.
# Property Builder
The core use of mongoman is schema creation via property building. To make a new schema, simply use the property builder chain, initiated with `mongoman()` and terminated with `fin()`. For example. a simple user schema might look something like this
```javascript
mon = require('mongoman');var user = {
// validates the name to be a required string that fits the regex
name : mon().string().required().regex(/[a-z]+\s*[a-z+]/i).fin(),// sets the registered propert to default tothe current date-time
registered : mon().date().default(new Date()).fin(),// validates the age to be a required integer of at least 18
age : mon().required().number().integer.min(18).fin()}
```Every validation middleware function has a default error, but errors can be augmented to inlude a property name by passing in a value to the `mon()` function call.
``` javascript
mon().email().fin(); // validation error : 'invalid email'
mon('My email').email().fin(); // validation error : 'My email is not a valid email'
```## Universal
If a property or validation isn't included as a supported chainable function, you can easily include it using the following functions.
### `prop.set(key, value)`
Set the key/value passed in for the property
```javascript
schema.newProp = mon().set('type', String).fin();
```### `prop.validate(errorMsg, valFunction)`
Bind the validation function to the property, throwing the error message if it returns false
```javascript
function isOdd (value) {
return (value % 2) == 1
}schema.newProp = mon().validate('newProp must be odd', isOdd).fin();
```### `prop.index(key|value, [value])`
Bind the key and value to the index attribute of the property. Providing only one parameter will set `index` equal to that parameter
```javascript
schema.newProp = mon().index('unique', false).fin();
// or
schema.newProp = mon().index('hashed').fin();```
# Types
### `prop.string()`
Set property type to `String`
```javascript
schema.newProp = mon().string().fin();
```### `prop.date()`
Set property type to `Date`
```javascript
schema.newProp = mon().date().fin();
```### `prop.number()`
Set property type to `Number`
```javascript
schema.newProp = mon().number().fin();
```### `prop.buffer()`
Set property type to `Buffer`
```javascript
schema.newProp = mon().buffer().fin();
```### `prop.mixed()`
Set property type to be mixed
```javascript
schema.newProp = mon().mixed().fin();
```### `prop.objectId()`
Set property type to be an object ID
```javascript
schema.newProp = mon().objectId().fin();
```### `prop.array()`
Set property type to be `Array`
```javascript
schema.newProp = mon().array().fin();
```### `prop.schema(ref, type)`
Set property type to be a reference to another schema
```ref``` -- Required - name of referred schema
```type``` -- Optional - Defaults ```ObjectId```, possible values (```Number```, ```String```, ```Buffer```)```javascript
schema.newProp = mon().schema('schemaName').fin();
```In order to create an array of schemas (enabling populate over numerous objects) follow this pattern:
```javascript
.array({ type : mon.mongoose.Schema.Types.ObjectId, ref : 'name_of_schema'})
```# Middleware
Any time `[]` is a function parameter, its is optional.
## Shared
### `prop.onGet(function)`
type: any
Passes the value of the property into the function. the returned value is what is exposed to the document on get
```javascript
schema.newProp = mon().onGet(function (value) {
return value ? value + '-example' : value;
}).fin();
```### `prop.onSet(function)`
type: any
Passes the value of the property into the function. the returned value is what is saved to the document on get
```javascript
schema.newProp = mon().onSet(function (value) {
return value ? value + '-example' : value;
}).fin();
```## Date
### `prop.expires(dateTime)`
type: date
Sets the expiration of the date
```javascript
schema.newProp = mon().expires('1.5h').fin();
```## String
### `prop.toUppercase()`
type: string
Sets the value to uppercase
```javascript
schema.newProp = mon().toUppercase().fin();
```### `prop.toLowercase()`
type: string
Sets the value lowercase
```javascript
schema.newProp = mon().toLowercase().fin();
```### `prop.trim()`
type: string
Trims the whitespace off the beginning and end of the string
```javascript
schema.newProp = mon().trim().fin();
```# Validation
**important:** using validations that do not apply to the property type will throw an error. To allow them to pass silently, set mongo configuration `strict : false`.
Any time `[]` is a function parameter, its is optional. any time `[message]` is included, a default message will be used unless this parameter is specified.
## Shared
### `prop.required()`
type: any
return an error if the property is not defined
```javascript
schema.newProp = mon().required().fin();
```### `prop.default(value)`
type: any
If no value is set for the property, set it to the default value passed in
```javascript
schema.newProp = mon().default('default value').fin();
```### `prop.select([bool])`
type: any
`[bool]` true or undefined if this path should always be included in the results, false if it should be excluded by default. This setting can be overridden at the query level.
```javascript
schema.newProp = mon().select().fin();
```### `prop.enum(values, [message])`
type: any
If the value submitted is not uncluded in the list of enumerated properties, an error is returned.
```javascript
schema.newProp = mon().enum(['foo', 'bar'], 'custom error').fin();
```### `prop.unique([bool])`
type: any
Insures a unique index is generated for the property. defaults to true. False causes the DB to be indifferent
```javascript
schema.newProp = mon().unique().fin();
```### `prop.ref(model)`
type: any
Creates a reference to another model. This is used to populate data from another document
```javascript
schema.newProp = mon().objectId().ref('fooModel').fin();
```### `prop.min(value, [message])`
type: `string` (length), `array` (length), `number` (value), `date` (value), `object` (keys), `buffer` (length)
Check that the value being saved is greater than or equal to the value passed into the property builder
```javascript
schema.newProp = mon().min(5).fin();
```### `prop.max(value, [message])`
type: `string` (length), `array` (length), `number` (value), `date` (value), `object` (keys), `buffer` (length)
Check that the value being saved is less than or equal to the value passed into the property builder
```javascript
schema.newProp = mon().max(5).fin();
```### `prop.length(value, [message])`
type: `string` (length), `array` (length), `object` (keys), `buffer` (length)
Check that the value being saved is the same length as the value passed into the property builder
```javascript
schema.newProp = mon().length(5).fin();
```## Arrays
### `prop.sparse()`
return an error if the array contains undefined values
```javascript
schema.newProp = mon().array().sparse().fin();
```## Strings
### `prop.alphanum([message])`
return an error if the string contains non alpha-numeric values
```javascript
schema.newProp = mon().string().alphanum().fin();
```### `prop.regex(expression, [message])`
return an error if the string does not match the expression
```javascript
schema.newProp = mon().string().regex(expression).fin();
```### `prop.email([message])`
return an error if the string is not a valid email address
```javascript
schema.newProp = mon().string().email().fin();
```### `prop.token([message])`
return an error if the string is not a valid token
```javascript
schema.newProp = mon().string().token().fin();
```### `prop.guid([message])`
return an error if the string is not a valid GUID
```javascript
schema.newProp = mon().string().guid().fin();```
### `prop.hostname([message])`
return an error if the string is not a valid hostname
```javascript
schema.newProp = mon().string().hostname().fin();```
### `prop.url([message])`
return an error if the string is not a valid url
```javascript
schema.newProp = mon().string().url().fin();
```### `prop.uppercase([message])`
return an error if the string is not uppercase
```javascript
schema.newProp = mon().string().uppercase().fin();
```### `prop.lowercase([message])`
return an error if the string is not lowercase
```javascript
schema.newProp = mon().string().lowercase().fin();
```## Numbers
### `prop.greater(limit, [message])`
return an error if the number is below the limit
```javascript
schema.newProp = mon().number().greater(5).fin();
```### `prop.less(limit, [message])`
return an error if the number is above the limit
```javascript
schema.newProp = mon().number().less(5).fin();
```### `prop.integer([message])`
return an error if the string is not an integer
```javascript
schema.newProp = mon().string().integer().fin();
```# Utilities
### `mon.drop(collection)`
drop a collection by name (normally just 'db')
```javascript
mon.drop('db');
```### `mon.connect([options])`
takes options, defaulting to 'mongodb://localhost/database'. returns an instance of the database. also accessable through `mon.db`
```javascript
var db = mon.connect();
```### `mon.schema(schema)`
returns an instance of a schema with the given schema object definition
```javascript
var mySchema = mon.schema({
name : mon().string().required().fin()
});
```### `mon.model(modelName)`
returns the model matching the given name
```javascript
var MyModel = mon.model('MyModel');
```### `mon.new(modelName)`
returns a new instance of the model specified. applies the inputs if they are defined
```javascript
var tester = mon.new('MyModel', {
name : 'tester'
});
```### `mon.register(schema, [options])`
registers a new model with the given schema and options. The options object is where middleware, methods, index properties, and virtual properties are defined. A minimalistic model is defined below
```javascript
var mon = require('mongoman');
var bcrypt = require('bcrypt-nodejs');mon.register('Person', {
firstName : mon().string().required().fin(),
lastName : mon().string().required().fin(),
secret : mon().string().fin()
}, {
middleware : {
pre : {
save : function (callback) {
if (this.isModified('secret')) {
this.secret = bcrypt.hashSync(this.secret, bcrypt.genSaltSync());
}return callback();
}
}
},
methods : {
findFamily : function (callback) {
return mon.model('Person').find({
lastName : this.lastName
}, callback);
},
compareSecret : function(submitted, callback) {
var result = bcrypt.compareSync(submitted, this.secret);
return callback(null, result);
}
},
statics : {
findByFirst : function (first, callback) {
return mon.model('Person').find({
firstName : first
}, callback);
}
},
virtuals : {
fullName : {
get : function () {
return this.firstName + ' ' + this.lastName;
}
}
}
});
```### `mon.registerAll(directory, [regex])`
traverses the directory tree requiring all js files (to register models on server startup). optional regex to filter files
**./models/foo.js**
```javascript
var mon = require('mongoman');
mon.register('foo', { foo : mon().string().fin() });
```**./models/sub_models/bar_model.js**
```javascript
var mon = require('mongoman');
mon.register('bar', { bar : mon().string().fin() });
```**./server.js**
```javascript
// ... server setupmon.connect();
mon.registerAll('../models', /_model/); // registers ['bar']
// OR
mon.registerAll('../models'); // registers ['foo', 'bar']
// ... server finalizing
```# Running Unit Tests
To run the unit tests, execute the following:
```
npm test
```Please make sure all unit tests pass before making a new PR