本次升级主要是对model进行了抽象,model 表明着系统中的一些数据,也就是一些javaScript对象,对这些数据还能够有操做,好比校验、数据处理、序列化、持久化等 。全部的这些操做,在 bearcat model,统一的抽象成 constraint 和 filter。(在即将更新的 bearcat-dao 0.2 版本里面还能够看到 model 在数据库 O/R mapping 里面的抽象)html
一个简单的 model 能够是这样的:java
jsvar SimpleModel = function() { this.$mid = "simpleModel"; this.num1 = 0; } module.exports = SimpleModel;
就是一个简单javaScript对象,而后经过一个 $mid 属性来指明该model的惟一id,经过这个id,咱们能够经过 bearcat.getModel 方法来获取这个 model 实例数据库
jsvar simpleModel = bearcat.getModel('simpleModel');
获取实例以后咱们能够对这个model进行简单的 set/get 操做api
jssimpleModel.$set('num1', 10); var num1 = simpleModel.$get('num1'); // num1 === 10
也能够对model进行pack操做app
jssimpleModel.$pack({ 'num1': 5 }); num1 = simpleModel.$get('num1'); // num1 === 5
对model属性,还能够经过定义来添加约束、配置,好比添加type的约束ide
jsthis.num2 = "$type:Number";
这个以后,num2 属性则必须是 Number 类型,添加其它类型则会返回一个 Error 对象函数
var r = simpleModel.$set('num2', 'aaa'); if (r) { console.log(r.stack); }
你也能够对属性添加 default 值ui
jsthis.num3 = "$type:Number;default:20";
jsvar num3 = simpleModel.$get('num3'); // num3 === 20
对于model的数据处理、校验其实均可以抽象为对model的 before filter 与 after filterthis
好比你能够添加一个 checkNum 的 before filter,来对 num 属性进行校验编码
jsvar FilterModel = function() { this.$mid = "filterModel"; this.num = 0; } FilterModel.prototype.checkNum = function(key, value) { if (typeof value !== 'number') { return new Error('num must be number'); } if (value > 10) { return new Error('num must be small than 10'); } } module.exports = FilterModel;
jsvar filterModel = bearcat.getModel('filterModel'); var r = filterModel.$before('checkNum').$set('num', 5); // ok r = filterModel.$before('checkNum').$set('num', 'aaa'); // error with the checkNum validation, r is the Error object if(r) { console.log(r.stack); } r = filterModel.$before('checkNum').$set('num', 20); if (r) { console.log(r.stack); }
这里经过 $before api 来指定了 before filter
num 属性就限定必须是Number类型,且值要 <=10
对于after filer,能够添加一个数据处理的方法,用于对数据的后期处理,好比序列化、加密
jsvar FilterModel = function() { this.$mid = "filterModel"; this.num = 0; } FilterModel.prototype.checkNum = function(key, value) { if (typeof value !== 'number') { return new Error('num must be number'); } if (value > 10) { return new Error('num must be small than 10'); } } FilterModel.prototype.transformNum = function() { this.num = 12345; } module.exports = FilterModel;
jsvar filterModel = bearcat.getModel('modelId'); filterModel.$after('transformNum').$set('num', 3); // set num to 10, with the after filter transformNum var num = filterModel.$get('num'); // the num is now 12345
num 值通过after filter的 transformNum 方法以后就变成了 12345
约束描述了对model里的属性的规范、要求。然而,因为javaScript自己的动态性,属性在定义的时候是没有类型的,也就更没必要提定义属性的约束了。开发者要实现约束,就必须实现一个validate方法,而后在须要约束的地方调用该方法来限定属性的约束。这个validate方法的粒度、复用性就成为了问题,并且属性的约束只有被validate方法调用到了才知道是怎样约束的,也不便于后期的维护。
描述老是优于硬编码,这是 bearcat constraint 设计的一个原则。
经过对属性进行必定的描述来进行规范,这里的描述就是约束,而约束是能够相互组合、叠加的、也能够带有参数来更好的复用
一样的,定义一个约束,就像定义一个对象
notNullConstraint.js
jsvar Util = require('util'); var NotNullConstraint = function() { this.$cid = "myNotNull"; this.message = "%s must be not null for value %s"; } NotNullConstraint.prototype.validate = function(key, value) { var message = this.message; if (value === null || typeof value === 'undefined') { return new Error(Util.format(message, key, value)); } } module.exports = NotNullConstraint;
咱们这里定义了一个 notNull 的约束,经过 $cid 属性定义了id 为 myNotNull,在该对象里,咱们实现了 validate 接口,该接口以model属性的key、value作为参数
要在model里面使用这个约束也很是简单,只须要在须要添加约束的属性value里面,加入这个约束的id便可
jsvar ConstaintModel = function() { this.$mid = "constaintModel"; this.num1 = "$myNotNull"; } module.exports = ConstaintModel;
这个model,咱们有一个num1属性,该属性的约束是 myNotNull
jsvar constaintModel = bearcat.getModel('constaintModel'); var r = constaintModel.$set("num1"); // the Error object if(r) { console.log(r.stack); }
而后咱们拿到model,往 num1 属性 set 一个值,就触发了 myNotNull 这个约束
这样,约束能够自由的添加到须要的model属性里面,约束的触发彻底由 bearcat 来管理
约束是能够经过组合成为high level约束的,也即高阶约束
经过约束的组合能够带来以下好处:
* 避免对简单约束的重复定义、组合、使用
* 把简单约束抽象成基础约束来进行复用
好比,咱们能够定义下面的这个组合约束
sizeConstraint.js
var SizeConstraint = function() { this.$cid = "mySize"; this.$constraint = "$myNotNull"; this.message = "key %s value %s length over max %d"; this.max = null; } SizeConstraint.prototype.validate = function(key, value) { var message = this.message; var maxLen = this.max; if (maxLen === null) { return; } if (value && value.length > maxLen) { return new Error(Util.format(message, key, value, maxLen)); } } module.exports = SizeConstraint;
经过 this.$constraint = "$myNotNull"; 属性,咱们添加了 myNotNull 这个基础约束进来,当该约束触发的时候,首先会触发基础约束也即 myNotNull,而后触发本身的 validate 接口所定义的约束
固然,这个例子的基础约束就一个,也能够添加其它基础约束,只须要依次添加约束id,而且以 ; 分隔便可
this.$constraint = "$myNotNull;myType"
要使用这个约束,简单的把 mySize 添加到须要约束的model属性便可
constraintModel.js
var ConstaintModel = function() { this.$mid = "constaintModel"; this.num = "$mySize"; } module.exports = ConstaintModel;
r = constaintModel.$set("num2"); // the Error object if (r) { console.log(r.stack); }
约束能够带有参数,这样就能够把约束进行函数似的抽象,更好的复用
好比,上面的 mySize 约束例子中,mySize 约束实际上是带了一个参数 max
var ConstaintModel = function() { this.$mid = "constaintModel"; this.num1 = "$myNotNull"; this.num2 = "$mySize"; this.value = "$mySize(max=5)"; } module.exports = ConstaintModel;
所以,咱们能够在model属性列中,除了添加 mySize 约束外,还能够指定 约束参数 max 的值,好比 max = 5,限定 value 属性的长度不能大于5
constaintModel.$set("value", "aaa"); // ok var value = constaintModel.$get("value"); console.log(value); r = constaintModel.$set("value", "aaaaaa"); // the Error object if (r) { console.log(r.stack); }
更多关于 bearcat model 请参见官方文档 bearcat model