Simeon, If you're interested in the concept of sharing code, you might want to take a look at Kanso (http://kansojs.org), which aims to bring all the features of the design doc to the client-side. This means you can call validate_doc_update on a document from the browser, or even call list, show and update functions too. Still early days though :)
Caolan On 10 March 2011 00:00, Simeon F. Willbanks <[email protected]> wrote: > Justin, > > Thank you for the reply and helping me brainstorm a solution. I like > the !code macro idea, but my CouchDB server isn't on the same machine > as my application. They communicate through a network. Could I do > this? > > function(newDoc, oldDoc, userCtx) { > //!code path/to/validate.py > validate(newDoc, oldDoc, userCtx); > } > > path/to/validate.py would be network aware and would return valid JavaScript. > > Thanks, > Simeon > > On Wed, Mar 9, 2011 at 1:27 PM, Justin Walgran <[email protected]> wrote: >> Simeon, >> >> the !code macro in CouchApp was created so you can DRY up your >> functions in the exact way you want. If you extract your validator, >> you can include it in both your validate_doc_update function and your >> client code. Something like this: >> >> function(newDoc, oldDoc, userCtx) { >> //!code path/to/validate.js >> validate(newDoc, oldDoc, userCtx); >> } >> >> // Content of validate.js >> var validate = function(newDoc, oldDoc, userCtx) { >> var Errors = {count: 0}; >> >> var Message = function(field, type, text) { >> this.type = type || 'string'; >> this.text = text || field + ' is required'; >> this.required = true; >> }; >> >> var require = function(field, type, text) { >> if (!newDoc[field]) { >> Errors[field] = new Message(field, type, text); >> Errors.count += 1; >> }; >> }; >> >> if (newDoc.type == 'post') { >> require('title'); >> require('created_at', 'datetime'); >> require('body'); >> require('author'); >> }; >> >> if (newDoc.type == 'comment') { >> require('name'); >> require('created_at', 'datetime'); >> require('comment', 'string', 'You may not leave an empty >> comment'); >> }; >> >> if (Errors.count > 0) { >> throw({forbidden: JSON.stringify(Errors)}); >> }; >> } >> >> If you refactor a little further, you could go the next step and >> generate a form from the configuration of the validator without the >> making the extra, intentionally bad request to the server. >> >> Justin >> >> >> On Wed, Mar 9, 2011 at 4:10 PM, Simeon F. Willbanks <[email protected]> >> wrote: >>> From the 'CouchDB The Definitive Guide', "CouchDB uses the >>> validate_doc_update function to prevent invalid or unauthorized >>> document updates from proceeding." This clearly defines the >>> validate_doc_update function's responsibility. That said, can we >>> extend this responsibility a bit? I'd rather not redefine valid >>> document attributes in my external application since >>> validate_doc_update is already doing the work (DRY). Maybe the >>> application can query the validate_doc_update function for the exact >>> attributes of a valid document. Here is a proof of concept >>> validate_doc_update function. >>> >>> function(newDoc, oldDoc, userCtx) { >>> Errors = {count: 0}; >>> >>> function Message(field, type, text) { >>> this.type = type || 'string'; >>> this.text = text || field + ' is required'; >>> this.required = true; >>> }; >>> >>> function require(field, type, text) { >>> if (!newDoc[field]) { >>> Errors[field] = new Message(field, type, text); >>> Errors.count += 1; >>> }; >>> }; >>> >>> if (newDoc.type == 'post') { >>> require('title'); >>> require('created_at', 'datetime'); >>> require('body'); >>> require('author'); >>> }; >>> >>> if (newDoc.type == 'comment') { >>> require('name'); >>> require('created_at', 'datetime'); >>> require('comment', 'string', 'You may not leave an empty comment'); >>> }; >>> >>> if (Errors.count > 0) { >>> throw({forbidden: JSON.stringify(Errors)}); >>> }; >>> } >>> >>> In my application, before putting a new document or building a >>> document input UI (web form), I can "query" the validate_doc_update >>> function like so: >>> >>> $ curl -X PUT couchdb:5984/basic/a1a0d5f1e202b48e5bc55f616d0021ff -d >>> '{"type":"post"}' >>> {"error":"forbidden","reason":"{\"count\":4,\"title\":{\"type\":\"string\",\"text\":\"title >>> is >>> required\",\"required\":true},\"created_at\":{\"type\":\"datetime\",\"text\":\"created_at >>> is >>> required\",\"required\":true},\"body\":{\"type\":\"string\",\"text\":\"body >>> is >>> required\",\"required\":true},\"author\":{\"type\":\"string\",\"text\":\"author >>> is required\",\"required\":true}}"} >>> >>> From the response, I can decode the JSON object's reason property to a >>> useful array. >>> >>> array >>> 'count' => int 4 >>> 'title' => >>> array >>> 'type' => string 'string' (length=6) >>> 'text' => string 'title is required' (length=17) >>> 'required' => boolean true >>> 'created_at' => >>> array >>> 'type' => string 'datetime' (length=8) >>> 'text' => string 'created_at is required' (length=22) >>> 'required' => boolean true >>> 'body' => >>> array >>> 'type' => string 'string' (length=6) >>> 'text' => string 'body is required' (length=16) >>> 'required' => boolean true >>> 'author' => >>> array >>> 'type' => string 'string' (length=6) >>> 'text' => string 'author is required' (length=18) >>> 'required' => boolean true >>> >>> From this array, I can build the input UI or validate the new document >>> before putting. >>> >>> To reiterate, I am trying to DRY up the validation >>> rules/responsibilities by defining them in one spot. This proof of >>> concept uses the validate_doc_update function in CouchDB. The >>> validate_doc_update function is now responsible for preventing invalid >>> documents from being PUT to CouchDB, and it can respond to application >>> queries for what constitutes a valid document. >>> >>> So, is this a bad idea? Is there a more idiomatic way to accomplish this >>> goal? >>> >>> Thanks, >>> Simeon >>> >> >
