UNPKG

nodulator

Version:

Complete NodeJS Framework for Restfull APIs

651 lines (458 loc) 28.4 kB
<!DOCTYPE html> <html> <head> <title>Schema.ls</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <ul id="jump_to"> <li> <a class="large" href="javascript:void(0);">Jump To &hellip;</a> <a class="small" href="javascript:void(0);">+</a> <div id="jump_wrapper"> <div id="jump_page_wrapper"> <div id="jump_page"> <a class="source" href="Nodulator.html"> Nodulator.ls </a> <a class="source" href="ClientDB.html"> ClientDB.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="Resource.html"> Resource.ls </a> <a class="source" href="Bus.html"> Bus.ls </a> <a class="source" href="Cache.html"> Cache.ls </a> <a class="source" href="ChangeWatcher.html"> ChangeWatcher.ls </a> <a class="source" href="Debug.html"> Debug.ls </a> <a class="source" href="Wrappers.html"> Wrappers.ls </a> <a class="source" href="Nodulator.html"> Nodulator.ls </a> <a class="source" href="Resource.html"> Resource.ls </a> <a class="source" href="Schema.html"> Schema.ls </a> <a class="source" href="NModule.html"> NModule.ls </a> <a class="source" href="AccountResource.html"> AccountResource.ls </a> <a class="source" href="User.html"> User.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="Nodulator-Angular.html"> Nodulator-Angular.ls </a> <a class="source" href="TaskDirective.html"> TaskDirective.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="TaskService.html"> TaskService.ls </a> <a class="source" href="main.html"> main.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="Task.html"> Task.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="DOM.html"> DOM.ls </a> <a class="source" href="View.html"> View.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="Nodulator.html"> Nodulator.ls </a> <a class="source" href="Mongo.html"> Mongo.ls </a> <a class="source" href="Mysql.html"> Mysql.ls </a> <a class="source" href="SqlMem.html"> SqlMem.ls </a> <a class="source" href="index.html"> index.ls </a> <a class="source" href="Resource.html"> Resource.ls </a> <a class="source" href="Request.html"> Request.ls </a> <a class="source" href="Route.html"> Route.ls </a> <a class="source" href="index.html"> index.ls </a> </div> </div> </li> </ul> <ul class="sections"> <li id="title"> <div class="annotation"> <h1>Schema.ls</h1> </div> </li> <li id="section-1"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-1">&#182;</a> </div> </div> <div class="content"><div class='highlight'><pre><span class="hljs-built_in">require</span>! { async underscore: _ validator: Validator \./Helpers/Debug</pre></div></div> </li> <li id="section-2"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>../../ : N</p> </div> <div class="content"><div class='highlight'><pre>} <span class="hljs-function"> <span class="hljs-title">validationError</span> = <span class="hljs-params">(field, value, message)</span> -&gt;</span> field: field value: value message: <span class="hljs-string">"The '#field' field <span class="hljs-subst">#{<span class="hljs-keyword">if</span> value? =&gt; <span class="hljs-string">"with value '#value'"</span>}</span> #message"</span> typeCheck = bool: <span class="hljs-function"><span class="hljs-params">(value)</span> -&gt;</span> <span class="hljs-keyword">typeof</span>(value) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'string'</span> <span class="hljs-keyword">and</span> <span class="hljs-string">''</span> + value <span class="hljs-keyword">is</span> <span class="hljs-string">'true'</span> <span class="hljs-keyword">or</span> <span class="hljs-string">''</span> + value <span class="hljs-keyword">is</span> <span class="hljs-string">'false'</span> int: <span class="hljs-keyword">is</span>-type \Number float: <span class="hljs-keyword">is</span>-type \Number string: <span class="hljs-keyword">is</span>-type \String date: Validator.isDate email: Validator.isEmail array: <span class="hljs-function"><span class="hljs-params">(value)</span> -&gt;</span> Array.isArray value arrayOf: <span class="hljs-function"><span class="hljs-params">(type)</span> -&gt;</span> (value) ~&gt; <span class="hljs-keyword">not</span> _(map (@[type]), value).contains (item) -&gt; item <span class="hljs-keyword">is</span> <span class="hljs-literal">false</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SchemaProperty</span></span> name: <span class="hljs-literal">null</span> default: <span class="hljs-literal">null</span> unique: <span class="hljs-literal">false</span> optional: <span class="hljs-literal">true</span> internal: <span class="hljs-literal">false</span> unique: <span class="hljs-literal">false</span> type: <span class="hljs-literal">null</span> validation: <span class="hljs-literal">null</span> (@name, @type, @optional) -&gt; <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Error <span class="hljs-string">'SchemaProperty must have a name'</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> @name? <span class="hljs-keyword">if</span> <span class="hljs-keyword">is</span>-type \Array @type @validation = typeCheck.arrayOf @type<span class="hljs-number">.0</span> <span class="hljs-keyword">else</span> @validation = typeCheck[@type] Default: <span class="hljs-function"><span class="hljs-params">(@default)</span> -&gt;</span> @ Unique: <span class="hljs-function"><span class="hljs-params">(@unique = <span class="hljs-literal">true</span>)</span> -&gt;</span> @ Optional: <span class="hljs-function"><span class="hljs-params">(@optional = <span class="hljs-literal">true</span>)</span> -&gt;</span> @ Required: <span class="hljs-function"><span class="hljs-params">(required = <span class="hljs-literal">true</span>)</span> -&gt;</span> @optional = !required; @ Virtual: <span class="hljs-function"><span class="hljs-params">(@virtual = <span class="hljs-literal">null</span>)</span> -&gt;</span> @ Internal: <span class="hljs-function"><span class="hljs-params">(@internal = <span class="hljs-literal">true</span>)</span> -&gt;</span> @ Unique: <span class="hljs-function"><span class="hljs-params">(@unique = <span class="hljs-literal">true</span>)</span> -&gt;</span> @ <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Schema</span></span> mode: <span class="hljs-literal">null</span> (@name, @mode = <span class="hljs-string">'free'</span>) -&gt; @properties = [] @assocs = [] @habtm = [] @debug = <span class="hljs-keyword">new</span> Debug <span class="hljs-string">"N::Resource::<span class="hljs-subst">#{@name}</span>::Schema"</span>, Debug.colors.cyan Populate: <span class="hljs-function"><span class="hljs-params">(instance, blob)</span> -&gt;</span> res = obj-to-pairs blob |&gt; filter (<span class="hljs-number">.0</span><span class="hljs-number">.0</span> <span class="hljs-keyword">isnt</span> \_) |&gt; pairs-to-obj instance &lt;&lt;&lt; res @properties |&gt; each (<span class="hljs-function">-&gt;</span> instance[it.name] = | blob[it.name]? =&gt; that | it.default? =&gt; <span class="hljs-keyword">switch</span> | <span class="hljs-keyword">is</span>-type \Function it.default =&gt; it.default! | _ =&gt; it.default | _ =&gt; void) @assocs |&gt; each -&gt; instance[it.name] = that <span class="hljs-keyword">if</span> blob[it.name]? @properties |&gt; filter (.virtual?) |&gt; each ~&gt; <span class="hljs-keyword">try</span> result = it.virtual.call instance, instance, (val) ~&gt; instance[it.name] = val <span class="hljs-keyword">if</span> result? instance[it.name] = result <span class="hljs-keyword">catch</span> e instance[it.name] = <span class="hljs-literal">undefined</span> instance Filter: <span class="hljs-function"><span class="hljs-params">(instance)</span> -&gt;</span> res = {} <span class="hljs-keyword">if</span> @mode <span class="hljs-keyword">is</span> \strict res.id = instance.id @properties |&gt; filter (<span class="hljs-function">-&gt;</span> <span class="hljs-keyword">not</span> it.virtual?) |&gt; each -&gt; res[it.name] = instance[it.name] <span class="hljs-keyword">else</span> each (~&gt; <span class="hljs-keyword">if</span> it[<span class="hljs-number">0</span>] <span class="hljs-keyword">isnt</span> \_ <span class="hljs-keyword">and</span> <span class="hljs-keyword">typeof</span>! instance[it] <span class="hljs-keyword">isnt</span> <span class="hljs-string">'Function'</span> <span class="hljs-keyword">and</span> it <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> map (.name), @assocs <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> _(@properties).findWhere(name: it)?.virtual? <span class="hljs-keyword">and</span> (<span class="hljs-keyword">typeof</span>! instance[it]) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'Object'</span> <span class="hljs-keyword">and</span> (<span class="hljs-keyword">typeof</span>! instance[it]) <span class="hljs-keyword">isnt</span> <span class="hljs-string">'Array'</span> res[it] = instance[it] ), keys instance res RemoveInternals: <span class="hljs-function"><span class="hljs-params">(blob)</span> -&gt;</span> @properties |&gt; filter (.internal) |&gt; each -&gt; <span class="hljs-keyword">delete</span> blob[it.name] blob Field: <span class="hljs-function"><span class="hljs-params">(name, type)</span> -&gt;</span> <span class="hljs-keyword">return</span> that <span class="hljs-keyword">if</span> _(@properties).findWhere name: name @properties.push <span class="hljs-keyword">new</span> SchemaProperty name, type, @mode <span class="hljs-keyword">is</span> <span class="hljs-string">'free'</span> @properties[*<span class="hljs-number">-1</span>]</pre></div></div> </li> <li id="section-3"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Check for schema validity</p> </div> <div class="content"><div class='highlight'><pre> Validate: <span class="hljs-function"><span class="hljs-params">(blob, done)</span> -&gt;</span> errors = [] @properties |&gt; each ~&gt; errors := errors.concat @_CheckPresence blob, it errors := errors.concat @_CheckValid blob, it errors = errors.concat @_CheckNotInSchema blob @_CheckUnique blob, @Resource, <span class="hljs-function"><span class="hljs-params">(err, results)</span> -&gt;</span> <span class="hljs-keyword">if</span> err? errors := errors.concat results done(<span class="hljs-keyword">if</span> errors.length =&gt; {errors} <span class="hljs-keyword">else</span> <span class="hljs-literal">null</span>) GetVirtuals: <span class="hljs-function"><span class="hljs-params">(instance, blob)</span> -&gt;</span> res = {} (@properties <span class="hljs-keyword">or</span> []) |&gt; filter (.virtual?) |&gt; each (<span class="hljs-function">-&gt;</span> res[it.name] = it.virtual.call instance, instance, <span class="hljs-function">-&gt;</span>) res _CheckPresence: <span class="hljs-function"><span class="hljs-params">(blob, property)</span> -&gt;</span> <span class="hljs-keyword">if</span> !property.optional <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> property.default? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> blob[property.name]? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> property.virtual? [validationError property.name, blob[property.name], <span class="hljs-string">' was not present.'</span>] <span class="hljs-keyword">else</span> [] _CheckValid: <span class="hljs-function"><span class="hljs-params">(blob, property)</span> -&gt;</span> <span class="hljs-keyword">if</span> blob[property.name]? <span class="hljs-keyword">and</span> <span class="hljs-keyword">not</span> (property.validation)(blob[property.name]) [validationError property.name, blob[property.name], <span class="hljs-string">' was not a valid '</span> + property.type] <span class="hljs-keyword">else</span> [] _CheckNotInSchema: <span class="hljs-function"><span class="hljs-params">(blob)</span> -&gt;</span> <span class="hljs-keyword">return</span> [] <span class="hljs-keyword">if</span> @mode <span class="hljs-keyword">is</span> \free <span class="hljs-keyword">for</span> field, value <span class="hljs-keyword">of</span> blob <span class="hljs-keyword">when</span> <span class="hljs-keyword">not</span> _(@properties).findWhere name: field <span class="hljs-keyword">and</span> field <span class="hljs-keyword">isnt</span> \id validationError field, blob[field], <span class="hljs-string">' is not in schema'</span> _CheckUnique: <span class="hljs-function"><span class="hljs-params">(blob, Resource, done)</span> -&gt;</span> res = [] async.eachSeries filter(<span class="hljs-function"><span class="hljs-params">(.unique)</span>, @properties), <span class="hljs-params">(property, done)</span> -&gt;</span> Resource.Fetch (property.name): blob[property.name] .Then -&gt; res.push validationError property.name, blob[property.name], <span class="hljs-string">' must be unique'</span> done {err: <span class="hljs-string">'not unique'</span>} .Catch -&gt; done! , <span class="hljs-function"><span class="hljs-params">(err, results)</span> -&gt;</span> done err, res PrepareRelationship: <span class="hljs-function"><span class="hljs-params">(isArray, field, description)</span> -&gt;</span> type = <span class="hljs-literal">null</span> foreign = <span class="hljs-literal">null</span> <span class="hljs-function"> <span class="hljs-title">get</span> = <span class="hljs-params">(blob, done)</span> -&gt;</span> done <span class="hljs-keyword">new</span> Error <span class="hljs-string">'No local or distant key given'</span></pre></div></div> </li> <li id="section-4"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>debug-res.Log “Preparing Relationships with #{description.type.name}”</p> </div> <div class="content"><div class='highlight'><pre> <span class="hljs-keyword">if</span> description.localKey? keyType = \local foreign = description.localKey <span class="hljs-function"> <span class="hljs-title">get</span> = <span class="hljs-params">(blob, done, _depth)</span> -&gt;</span> <span class="hljs-keyword">if</span> _depth &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">return</span> done() <span class="hljs-keyword">if</span> !isArray <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> typeCheck.int blob[description.localKey] <span class="hljs-keyword">return</span> done <span class="hljs-keyword">new</span> Error <span class="hljs-string">'Model association needs integer as id and key'</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> typeCheck.array blob[description.localKey] <span class="hljs-keyword">return</span> done <span class="hljs-keyword">new</span> Error <span class="hljs-string">'Model association needs array of integer as ids and localKeys'</span> description.type._FetchUnwrapped blob[description.localKey], done, _depth <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> description.distantKey? foreign = description.distantKey keyType = \distant <span class="hljs-function"> <span class="hljs-title">get</span> = <span class="hljs-params">(blob, done, _depth)</span> -&gt;</span> <span class="hljs-keyword">if</span> _depth &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> blob.id? <span class="hljs-keyword">return</span> done() <span class="hljs-keyword">if</span> !isArray description.type._FetchUnwrapped {<span class="hljs-string">"<span class="hljs-subst">#{description.distantKey}</span>"</span>: blob.id} , done, _depth <span class="hljs-keyword">else</span> description.type._ListUnwrapped {<span class="hljs-string">"<span class="hljs-subst">#{description.distantKey}</span>"</span>: blob.id}, done, _depth toPush = keyType: keyType type: description.type name: field Get: get foreign: foreign toPush.default = description.default <span class="hljs-keyword">if</span> description.default? @assocs.push toPush</pre></div></div> </li> <li id="section-5"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Get each associated Resource</p> </div> <div class="content"><div class='highlight'><pre> FetchAssoc: <span class="hljs-function"><span class="hljs-params">(blob, done, _depth)</span> -&gt;</span> assocs = {}</pre></div></div> </li> <li id="section-6"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>@debug.Log “Fetching #{@assocs.length} assocs with Depth #{_depth}”</p> </div> <div class="content"><div class='highlight'><pre> async.eachSeries @assocs, (resource, _done) ~&gt; <span class="hljs-function"> <span class="hljs-title">done</span> = <span class="hljs-params">(err, data)</span>-&gt;</span> _done err, data</pre></div></div> </li> <li id="section-7"> <div class="annotation"> <div class="pilwrap "> <a class="pilcrow" href="#section-7">&#182;</a> </div> <p>@debug.Log “Assoc: Fetching #{resource.name}”</p> </div> <div class="content"><div class='highlight'><pre> resource.Get blob, <span class="hljs-function"><span class="hljs-params">(err, instance)</span> -&gt;</span> assocs[resource.name] = resource.default <span class="hljs-keyword">if</span> resource.default? <span class="hljs-keyword">if</span> err? <span class="hljs-keyword">and</span> resource.type <span class="hljs-keyword">is</span> \distant =&gt; done! <span class="hljs-keyword">else</span> assocs[resource.name] = instance <span class="hljs-keyword">if</span> instance? done! , _depth , <span class="hljs-function"><span class="hljs-params">(err)</span> -&gt;</span> <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? done <span class="hljs-literal">null</span>, _.extend blob, assocs HasOneThrough: <span class="hljs-function"><span class="hljs-params">(res, through)</span> -&gt;</span> get = (blob, done, _depth) ~&gt; <span class="hljs-keyword">return</span> done! <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> _depth <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> blob.id? assoc = _(@assocs).findWhere name: capitalize through.name assoc.Get blob, <span class="hljs-function"><span class="hljs-params">(err, instance)</span> -&gt;</span> <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? done <span class="hljs-literal">null</span>, instance[capitalize res._type] , _depth + <span class="hljs-number">1</span> toPush = keyType: <span class="hljs-string">'distant'</span> type: res name: capitalize res._type Get: get @assocs.push toPush HasManyThrough: <span class="hljs-function"><span class="hljs-params">(res, through)</span> -&gt;</span> get = (blob, done, _depth) ~&gt; <span class="hljs-keyword">return</span> done! <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> _depth <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> blob.id? assoc = _(@assocs).findWhere name: capitalize through.name assoc.Get blob, <span class="hljs-function"><span class="hljs-params">(err, instance)</span> -&gt;</span> <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? res._ListUnwrapped instance[capitalize res._type], <span class="hljs-function"><span class="hljs-params">(err, instances)</span> -&gt;</span> <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? done <span class="hljs-literal">null</span>, instances , depth , _depth toPush = keyType: <span class="hljs-string">'distant'</span> type: res name: capitalize res._type Get: get @assocs.push toPush HasAndBelongsToMany: <span class="hljs-function"><span class="hljs-params">(res, through)</span> -&gt;</span> get = (blob, done, _depth) ~&gt; <span class="hljs-keyword">return</span> done! <span class="hljs-keyword">if</span> _depth &lt; <span class="hljs-number">0</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">not</span> blob.id? through._ListUnwrapped {(@name + \Id): blob.id}, (err, instances) ~&gt; <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? async.mapSeries instances, (instance, done) ~&gt; res._FetchUnwrapped instance[res._type + \Id ], done, _depth - <span class="hljs-number">1</span> , (err, results) ~&gt; <span class="hljs-keyword">return</span> done err <span class="hljs-keyword">if</span> err? done <span class="hljs-literal">null</span>, results , _depth toPush = keyType: <span class="hljs-string">'distant'</span> type: res name: capitalize res._type + \s Get: get @assocs.push toPush @habtm.push through Inherit: <span class="hljs-function">-&gt;</span> properties: @properties |&gt; map -&gt; sp = <span class="hljs-keyword">new</span> SchemaProperty it.name, it.type, it.optional sp &lt;&lt;&lt; it assocs: map (<span class="hljs-function">-&gt;</span> _ {} .extend it), @assocs habtm: map (<span class="hljs-function">-&gt;</span> _ {} .extend it), @habtm <span class="hljs-built_in">module</span>.exports = Schema</pre></div></div> </li> </ul> </div> </body> </html>