2121
2222/**
2323 * @module FrameworkBuilders
24- * @version 2.8 .0
24+ * @version 2.9 .0
2525 */
2626
2727'use strict' ;
@@ -30,8 +30,8 @@ const REQUIRED = 'The field "@" is invalid.';
3030const DEFAULT_SCHEMA = 'default' ;
3131const SKIP = { $$schema : true , $$result : true , $$callback : true , $$async : true , $$index : true , $$repository : true , $$can : true , $$controller : true } ;
3232const REGEXP_CLEAN_EMAIL = / \s / g;
33- const REGEXP_CLEAN_PHONE = / \s | \. | \ -| \( | \) / g;
34- const REGEXP_NEWOPERATION = / ^ f u n c t i o n ( \s ) ? \( [ a - z A - Z 0 - 9 \ $] + \) / ;
33+ const REGEXP_CLEAN_PHONE = / \s | \. | - | \( | \) / g;
34+ const REGEXP_NEWOPERATION = / ^ f u n c t i o n ( \s ) ? \( [ a - z A - Z 0 - 9 $ ] + \) / ;
3535const hasOwnProperty = Object . prototype . hasOwnProperty ;
3636const Qs = require ( 'querystring' ) ;
3737
@@ -50,10 +50,33 @@ function SchemaOptions(error, model, options, callback, controller) {
5050 this . options = options ;
5151 this . callback = this . next = callback ;
5252 this . controller = controller ;
53+
54+ if ( controller ) {
55+
56+ if ( controller . user )
57+ this . user = controller . user ;
58+
59+ if ( controller . session )
60+ this . session = controller . session ;
61+
62+ this . language = controller . language || '' ;
63+ this . ip = controller . ip ;
64+ this . id = controller . id ;
65+ this . query = controller . query ;
66+ this . body = controller . body ;
67+ this . files = controller . files ;
68+ } else
69+ this . language = '' ;
5370}
5471
55- SchemaOptions . prototype . throw = function ( name , error , path , index ) {
72+ SchemaOptions . prototype . success = function ( a , b ) {
73+ this . callback ( SUCCESS ( a === undefined ? true : a , b ) ) ;
74+ return this ;
75+ } ;
76+
77+ SchemaOptions . prototype . invalid = function ( name , error , path , index ) {
5678 this . error . push ( name , error , path , index ) ;
79+ this . callback ( ) ;
5780 return this ;
5881} ;
5982
@@ -152,6 +175,44 @@ SchemaBuilderEntity.prototype.allow = function() {
152175 return self ;
153176} ;
154177
178+ SchemaBuilderEntity . prototype . required = function ( name , fn ) {
179+
180+ var self = this ;
181+
182+ if ( ! name )
183+ return self ;
184+
185+ if ( name . indexOf ( ',' ) !== - 1 ) {
186+ var arr = name . split ( ',' ) ;
187+ for ( var i = 0 ; i < arr . length ; i ++ )
188+ self . required ( arr [ i ] . trim ( ) , fn ) ;
189+ return self ;
190+ }
191+
192+ if ( fn === false ) {
193+ self . properties && ( self . properties = self . properties . remove ( name ) ) ;
194+ return self ;
195+ }
196+
197+ var prop = self . schema [ name ] ;
198+ if ( ! prop )
199+ throw new Error ( 'Property "{0}" doesn\'t exist in "{1}" schema.' . format ( name , self . name ) ) ;
200+
201+ var is = prop . required ;
202+
203+ prop . can = typeof ( fn ) === 'function' ? fn : null ;
204+
205+ if ( ! prop . required ) {
206+ prop . required = true ;
207+ if ( self . properties ) {
208+ self . properties . indexOf ( name ) === - 1 && self . properties . push ( name ) ;
209+ } else
210+ self . properties = [ name ] ;
211+ }
212+
213+ return self ;
214+ } ;
215+
155216/**
156217 * Define type in schema
157218 * @param {String|String[] } name
@@ -168,7 +229,9 @@ SchemaBuilderEntity.prototype.define = function(name, type, required, custom) {
168229 return this ;
169230 }
170231
171- if ( required !== undefined && typeof ( required ) !== 'boolean' ) {
232+ var rt = typeof ( required ) ;
233+
234+ if ( required !== undefined && rt === 'string' ) {
172235 custom = required ;
173236 required = false ;
174237 }
@@ -189,13 +252,12 @@ SchemaBuilderEntity.prototype.define = function(name, type, required, custom) {
189252
190253 this . fields = Object . keys ( this . schema ) ;
191254
192- if ( ! required )
193- return this ;
194-
195- if ( this . properties == null )
196- this . properties = [ ] ;
255+ if ( required ) {
256+ if ( this . properties == null )
257+ this . properties = [ ] ;
258+ this . properties . indexOf ( name ) === - 1 && this . properties . push ( name ) ;
259+ }
197260
198- this . properties . indexOf ( name ) === - 1 && this . properties . push ( name ) ;
199261 return this ;
200262} ;
201263
@@ -364,10 +426,10 @@ SchemaBuilderEntity.prototype.filter = function(custom, model, reverse) {
364426function parseLength ( lower , result ) {
365427 result . raw = 'string' ;
366428 var beg = lower . indexOf ( '(' ) ;
367- if ( beg === - 1 )
368- return result ;
369- result . length = lower . substring ( beg + 1 , lower . length - 1 ) . parseInt ( ) ;
370- result . raw = lower . substring ( 0 , beg ) ;
429+ if ( beg !== - 1 ) {
430+ result . length = lower . substring ( beg + 1 , lower . length - 1 ) . parseInt ( ) ;
431+ result . raw = lower . substring ( 0 , beg ) ;
432+ }
371433 return result ;
372434}
373435
@@ -380,6 +442,8 @@ SchemaBuilderEntity.prototype.$parse = function(name, value, required, custom) {
380442 result . type = 0 ;
381443 result . length = 0 ;
382444 result . required = required ? true : false ;
445+ result . validate = typeof ( required ) === 'function' ? required : null ;
446+ result . can = null ;
383447 result . isArray = false ;
384448 result . custom = custom || '' ;
385449
@@ -1178,18 +1242,22 @@ SchemaBuilderEntity.prototype.validate = function(model, resourcePrefix, resourc
11781242 var s = self . parent . collection [ schema . raw ] ;
11791243
11801244 if ( ! s ) {
1181- F . error ( new Error ( 'Schema "' + schema . raw + ' " not found (validation).') ) ;
1245+ F . error ( new Error ( 'Schema "{0} " not found (validation).' . format ( schema . raw ) ) ) ;
11821246 continue ;
11831247 }
11841248
1185- if ( ! schema . isArray ) {
1186- ( model [ key ] != null || schema . required ) && s . validate ( model [ key ] , resourcePrefix , resourceName , builder , filter , path + key , - 1 ) ;
1187- continue ;
1249+ if ( schema . isArray ) {
1250+ var arr = model [ key ] ;
1251+ for ( var j = 0 , jl = arr . length ; j < jl ; j ++ ) {
1252+ if ( model [ key ] [ j ] != null || schema . required ) {
1253+ if ( ! schema . can || schema . can ( model ) )
1254+ s . validate ( model [ key ] [ j ] , resourcePrefix , resourceName , builder , filter , path + key + '[' + j + ']' , j ) ;
1255+ }
1256+ }
1257+ } else if ( model [ key ] != null || schema . required ) {
1258+ if ( ! schema . can || schema . can ( model ) )
1259+ s . validate ( model [ key ] , resourcePrefix , resourceName , builder , filter , path + key , - 1 ) ;
11881260 }
1189-
1190- var arr = model [ key ] ;
1191- for ( var j = 0 , jl = arr . length ; j < jl ; j ++ )
1192- ( model [ key ] [ j ] != null || schema . required ) && s . validate ( model [ key ] [ j ] , resourcePrefix , resourceName , builder , filter , path + key + '[' + j + ']' , j ) ;
11931261 }
11941262
11951263 return builder ;
@@ -1423,6 +1491,7 @@ SchemaBuilderEntity.prototype.prepare = function(model, dependencies) {
14231491 val = val ( ) ;
14241492
14251493 if ( ! type . isArray ) {
1494+
14261495 switch ( type . type ) {
14271496 // undefined
14281497 case 0 :
@@ -1438,7 +1507,16 @@ SchemaBuilderEntity.prototype.prepare = function(model, dependencies) {
14381507
14391508 // string
14401509 case 3 :
1441- tmp = val == null ? '' : autotrim ( self , val . toString ( ) ) ;
1510+
1511+ var tv = typeof ( val ) ;
1512+
1513+ if ( val == null || tv === 'object' )
1514+ tmp = '' ;
1515+ else if ( tv === 'string' )
1516+ tmp = autotrim ( self , val ) ;
1517+ else
1518+ tmp = autotrim ( self , val . toString ( ) ) ;
1519+
14421520 if ( type . length && type . length < tmp . length )
14431521 tmp = tmp . substring ( 0 , type . length ) ;
14441522
@@ -2650,6 +2728,7 @@ exports.validate = function(name, model, resourcePrefix, resourceName) {
26502728 if ( schema === undefined )
26512729 return null ;
26522730 schema = schema . get ( name ) ;
2731+ model = schema . prepare ( model ) ;
26532732 return schema === undefined ? null : schema . validate ( model , resourcePrefix , resourceName ) ;
26542733} ;
26552734
@@ -2755,7 +2834,7 @@ ErrorBuilder.prototype._resource = function() {
27552834
27562835ErrorBuilder . prototype . _resource_handler = function ( name ) {
27572836 var self = this ;
2758- return typeof ( framework ) !== 'undefined' ? F . resource ( self . resourceName || 'default' , self . resourcePrefix + name ) : '' ;
2837+ return typeof ( F ) !== 'undefined' ? F . resource ( self . resourceName || 'default' , name ) : '' ;
27592838} ;
27602839
27612840ErrorBuilder . prototype . exception = function ( message ) {
@@ -2783,7 +2862,8 @@ ErrorBuilder.prototype.add = function(name, error, path, index) {
27832862 * @param {Number } index Array Index, optional.
27842863 * @return {ErrorBuilder }
27852864 */
2786- ErrorBuilder . prototype . push = function ( name , error , path , index ) {
2865+ ErrorBuilder . prototype . push = function ( name , error , path , index , prefix ) {
2866+
27872867 this . isPrepared = false ;
27882868
27892869 if ( name instanceof ErrorBuilder ) {
@@ -2797,13 +2877,13 @@ ErrorBuilder.prototype.push = function(name, error, path, index) {
27972877
27982878 if ( name instanceof Array ) {
27992879 for ( var i = 0 , length = name . length ; i < length ; i ++ )
2800- this . push ( name [ i ] , undefined , path , index ) ;
2880+ this . push ( name [ i ] , undefined , path , index , prefix ) ;
28012881 return this ;
28022882 }
28032883
28042884 if ( error instanceof Array ) {
28052885 for ( var i = 0 , length = error . length ; i < length ; i ++ )
2806- this . push ( name , error [ i ] , path , index ) ;
2886+ this . push ( name , error [ i ] , path , index , prefix ) ;
28072887 return this ;
28082888 }
28092889
@@ -2825,7 +2905,7 @@ ErrorBuilder.prototype.push = function(name, error, path, index) {
28252905 error = error . toString ( ) ;
28262906 }
28272907
2828- this . items . push ( { name : name , error : typeof ( error ) === 'string' ? error : error . toString ( ) , path : path , index : index } ) ;
2908+ this . items . push ( { name : name , error : typeof ( error ) === 'string' ? error : error . toString ( ) , path : path , index : index , prefix : prefix } ) ;
28292909 this . count = this . items . length ;
28302910 return this ;
28312911} ;
@@ -2925,11 +3005,12 @@ ErrorBuilder.prototype._prepare = function() {
29253005 for ( var i = 0 , length = arr . length ; i < length ; i ++ ) {
29263006
29273007 var o = arr [ i ] ;
3008+
29283009 if ( o . error [ 0 ] !== '@' )
29293010 continue ;
29303011
29313012 if ( o . error . length === 1 )
2932- o . error = this . onResource ( o . name ) ;
3013+ o . error = this . onResource ( o . prefix ? o . prefix : ( this . resourcePrefix + o . name ) ) ;
29333014 else
29343015 o . error = this . onResource ( o . error . substring ( 1 ) ) ;
29353016
@@ -3646,6 +3727,8 @@ RESTBuilder.prototype.auth = function(user, password) {
36463727
36473728RESTBuilder . prototype . schema = function ( group , name ) {
36483729 this . $schema = exports . getschema ( group , name ) ;
3730+ if ( ! this . $schema )
3731+ throw Error ( 'RESTBuilder: Schema "{0}" not found.' . format ( name ? ( group + '/' + name ) : group ) ) ;
36493732 return this ;
36503733} ;
36513734
@@ -4005,7 +4088,7 @@ global.NEWOPERATION = function(name, fn) {
40054088
40064089global . OPERATION = function ( name , value , callback , param ) {
40074090
4008- if ( callback === undefined ) {
4091+ if ( typeof ( value ) === 'function' ) {
40094092 callback = value ;
40104093 value = EMPTYOBJECT ;
40114094 }
@@ -4015,31 +4098,55 @@ global.OPERATION = function(name, value, callback, param) {
40154098
40164099 if ( fn ) {
40174100 if ( fn . $newversion ) {
4018- var opt = { } ;
4019- opt . error = error ;
4020- opt . value = opt . model = value ;
4021- opt . callback = function ( value ) {
4022- if ( value instanceof Error ) {
4023- error . push ( value ) ;
4024- value = EMPTYOBJECT ;
4025- }
4026- callback ( error . hasError ( ) ? error : null , value , param ) ;
4027- } ;
4028- fn ( opt ) ;
4101+ fn ( new OperationOptions ( error , value , callback , param ) ) ;
40294102 } else
40304103 fn ( error , value , function ( value ) {
4031- if ( value instanceof Error ) {
4032- error . push ( value ) ;
4033- value = EMPTYOBJECT ;
4104+ if ( callback ) {
4105+ if ( value instanceof Error ) {
4106+ error . push ( value ) ;
4107+ value = EMPTYOBJECT ;
4108+ }
4109+ callback ( error . hasError ( ) ? error : null , value , param ) ;
40344110 }
4035- callback ( error . hasError ( ) ? error : null , value , param ) ;
40364111 } ) ;
40374112 } else {
40384113 error . push ( 'Operation "{0}" not found.' . format ( name ) ) ;
4039- callback ( error , EMPTYOBJECT , param ) ;
4114+ callback && callback ( error , EMPTYOBJECT , param ) ;
40404115 }
40414116} ;
40424117
4118+ function OperationOptions ( error , value , callback , options ) {
4119+ this . model = this . value = value ;
4120+ this . error = error ;
4121+ this . $callback = callback ;
4122+ this . options = options ;
4123+ }
4124+
4125+ OperationOptions . prototype . callback = function ( value ) {
4126+ var self = this ;
4127+
4128+ if ( self . $callback ) {
4129+ if ( value instanceof Error ) {
4130+ self . error . push ( value ) ;
4131+ value = EMPTYOBJECT ;
4132+ }
4133+ self . $callback ( self . error . hasError ( ) ? self . error : null , value , self . options ) ;
4134+ }
4135+
4136+ return self ;
4137+ } ;
4138+
4139+ OperationOptions . prototype . success = function ( a , b ) {
4140+ this . callback ( SUCCESS ( a === undefined ? true : a , b ) ) ;
4141+ return this ;
4142+ } ;
4143+
4144+ OperationOptions . prototype . invalid = function ( name , error , path , index ) {
4145+ this . error . push ( name , error , path , index ) ;
4146+ this . callback ( ) ;
4147+ return this ;
4148+ } ;
4149+
40434150// ======================================================
40444151// EXPORTS
40454152// ======================================================
@@ -4052,6 +4159,7 @@ exports.Page = Page;
40524159exports . UrlBuilder = UrlBuilder ;
40534160exports . TransformBuilder = TransformBuilder ;
40544161exports . SchemaOptions = SchemaOptions ;
4162+ exports . OperationOptions = OperationOptions ;
40554163exports . RESTBuilderResponse = RESTBuilderResponse ;
40564164global . RESTBuilder = RESTBuilder ;
40574165global . RESTBuilderResponse = RESTBuilderResponse ;
0 commit comments