Browse files

added validation

  • Loading branch information...
1 parent 8cf82b4 commit 81510cebd66e8b95c1225051705be687b4fa907e Karl Seguin committed Feb 15, 2012
Showing with 94 additions and 7 deletions.
  1. +17 −1 readme.md
  2. +2 −2 spec/model/creationSpec.coffee
  3. +39 −0 spec/model/validationSpec.coffee
  4. +36 −4 src/model.coffee
View
18 readme.md
@@ -1,4 +1,20 @@
# Models for Node
[![Build Status](https://secure.travis-ci.org/karlseguin/node-model.png)](http://travis-ci.org/karlseguin/node-model)
-A lightweight base model object. This is currently storage-agnostic (and may remain that way). It is meant to provide a simple facility for binding a hash-input (as you might receive from an http request) to an object, and providing validation features.
+A lightweight base model object. This is currently storage-agnostic (and may remain that way). It is meant to provide a simple facility for binding a hash-input (as you might receive from an http request) to an object, and providing validation features.
+
+
+# Usage
+
+
+ model = require('node-model')
+
+ class User extends model.Model
+ @attr 'name', model.types.string
+ @attr 'age', model.types.integer
+ @validateLength 'name', {required: true, min: 2, max: 20}, 'please enter a name'
+ @validatePresence 'age', 'please enter an age'
+
+You can now create a `User` directly from a hash input: `user = new User(req.query)`.
+
+You can also call `user.validate()` which will return true or false. When false is returned, you can access `user.errors` for a list of errors
View
4 spec/model/creationSpec.coffee
@@ -8,8 +8,8 @@ class Test extends model.Model
describe 'Model Creation', ->
it "defines the attributes", ->
- expect(Test.attributes.name).toEqual(1)
- expect(Test.attributes.score).toEqual(2)
+ expect(Test._attributes.name).toEqual(1)
+ expect(Test._attributes.score).toEqual(2)
it "creates an empty mobject", ->
test = new Test()
View
39 spec/model/validationSpec.coffee
@@ -0,0 +1,39 @@
+helper = require('./../helper')
+model = helper.require('./src/index')
+
+class Test extends model.Model
+ @attr 'name', model.types.string
+ @attr 'score', model.types.integer
+ @validateLength 'name', {required: true, min: 2, max: 5}, 'please enter a name'
+ @validatePresence 'score', 'please enter a score'
+
+
+describe 'Model Validation', ->
+
+ it "validates presence", ->
+ test = new Test()
+ expect(test.validate()).toEqual(false)
+ expect(test.errors['score'].length).toEqual(1)
+ expect(test.errors['score'][0]).toEqual('please enter a score')
+
+ it "validates required", ->
+ test = new Test()
+ expect(test.validate()).toEqual(false)
+ expect(test.errors['name'].length).toEqual(1)
+ expect(test.errors['name'][0]).toEqual('please enter a name')
+
+ it "validates min length", ->
+ test = new Test({name: '1'})
+ expect(test.validate()).toEqual(false)
+ expect(test.errors['name'].length).toEqual(1)
+ expect(test.errors['name'][0]).toEqual('please enter a name')
+
+ it "validates max length", ->
+ test = new Test({name: '123456'})
+ expect(test.validate()).toEqual(false)
+ expect(test.errors['name'].length).toEqual(1)
+ expect(test.errors['name'][0]).toEqual('please enter a name')
+
+ it "valid object is valid", ->
+ test = new Test({name: '12345', score: '44'})
+ expect(test.validate()).toEqual(true)
View
40 src/model.coffee
@@ -1,6 +1,10 @@
moduleKeywords = ['extended', 'included']
types = require('./types')
+ruleTypes =
+ presence: 1
+ length: 2
+
class Model
@extend: (obj) ->
for key, value of obj when key not in moduleKeywords
@@ -17,18 +21,46 @@ class Model
this
@attr: (name, type) ->
- @attributes = {} unless @attributes?
- @attributes[name] = type
+ @_attributes = {} unless @_attributes?
+ @_attributes[name] = type
+
+ @validatePresence: (name, message) ->
+ @addValidationRule name, ruleTypes.presence, null, message
+
+ @validateLength: (name, options, message) ->
+ @addValidationRule name, ruleTypes.length, options, message
+
+ @addValidationRule: (name, type, options, message) ->
+ @_rules = {} unless @_rules?
+ @_rules[name] = [] unless @_rules[name]?
+ @_rules[name].push({type: type, options: options, message: message})
constructor: (params) ->
- for name, type of @.constructor.attributes
+ for name, type of @.constructor._attributes
value = params?[name]
if !value?
value = null
else if type == types.integer
value = parseInt(value)
value = null if isNaN(value)
-
@[name] = value
+ validate: ->
+ @errors = {}
+ for name, rules of @.constructor._rules
+ for rule in rules
+ value = @[name]
+ if rule.options && rule.options.required && !value?
+ @_addError(name, rule.message)
+ else if rule.type == ruleTypes.presence
+ @_addError(name, rule.message) unless value?
+ else if rule.type == ruleTypes.length
+ @_addError(name, rule.message) if (rule.options.min? && value.length < rule.options.min ) || (rule.options.max? && value.length > rule.options.max)
+
+ return Object.keys(@errors).length == 0
+
+ _addError: (name, message) ->
+ @errors[name] = [] unless @errors[name]?
+ @errors[name].push(message)
+
module.exports = Model

0 comments on commit 81510ce

Please sign in to comment.