bearcat 0.4.0 發佈,統一抽象的 model

bearcat model

本次升級主要是對model進行了抽象,model 表明着系統中的一些數據,也就是一些javaScript對象,對這些數據還能夠有操做,好比校驗、數據處理、序列化、持久化等 。全部的這些操做,在 bearcat model,統一的抽象成 constraintfilter。(在即將更新的 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 filter

對於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 constraint

約束描述了對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 來管理

constraint 組合

約束是能夠經過組合成爲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);
}

constraint 參數

約束能夠帶有參數,這樣就能夠把約束進行函數似的抽象,更好的複用

好比,上面的 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

相關文章
相關標籤/搜索