Last active
April 5, 2020 12:52
-
-
Save cefn/ac18aeb00b4e67afa2043a8f0b8ca6fa to your computer and use it in GitHub Desktop.
Strategy for evaluating + unit-testing Couchdb map, reduce, update functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require("path") | |
const glob = require("glob") | |
const fs = require("fs") | |
const nodeEval = require("node-eval") | |
/** Helper object to construct a map of named design docs from a path containing js scripts. | |
* It populates couchdb design documents from js files targeting Spidermonkey 1.8.5 | |
* | |
* File paths like | |
* * designdocs/map/priority.js | |
* * designdocs/reduce/priority.js` | |
* * designdocs/update/handleSave.js` | |
* ...are mapped to literal js strings containing function definitions... | |
* * lowban.views.priority.map | |
* * lowban.views.priority.reduce | |
* * lowban.updates.handleSave | |
* | |
* Compatible files can be generated through babel, targeting browserlist `Firefox >= 4` | |
*/ | |
class Loader{ | |
constructor({ | |
scriptRoot="../designdocs", | |
scriptExtension=".js" | |
} = {}){ | |
this.scriptRoot = path.resolve(__dirname,scriptRoot) | |
this.scriptExtension = scriptExtension | |
} | |
locateScript(scriptType, scriptId){ | |
return `${this.scriptRoot}/${scriptType}/${scriptId}${this.scriptExtension}` | |
} | |
readScriptPath(scriptPath){ | |
return fs.readFileSync(scriptPath, "utf8") | |
} | |
readScript(scriptType, scriptId) { | |
return this.readScriptPath(this.locateScript(scriptType, scriptId)) | |
} | |
evalScript(scriptType, scriptId, context) { | |
const scriptPath = this.locateScript(scriptType, scriptId) | |
const scriptSource = this.readScriptPath(scriptPath) | |
return nodeEval(scriptSource, scriptPath, context) | |
} | |
getScriptIds(scriptType) { | |
return glob.sync(`${this.scriptRoot}/${scriptType}/*` + this.scriptExtension).map(filePath => path.basename(filePath, this.scriptExtension)) | |
} | |
loadDesignDocs() { | |
const mapIds = this.getScriptIds("map") | |
const reduceIds = this.getScriptIds("reduce") | |
const updateIds = this.getScriptIds("update") | |
const orphanedReducers = reduceIds.filter( id => !mapIds.includes(id)) | |
if(orphanedReducers.length > 0){ | |
throw `No map function for ${orphanedReducers}` | |
} | |
const views = mapIds.length ? {views:{ | |
//merge each view's map (and optional reduce) | |
...Object.assign(...mapIds.map( viewId => ({ | |
[viewId]: { | |
map:this.readScript("map", viewId), //view map is required | |
...reduceIds.includes(viewId) //view reduce is optional | |
? { reduce:this.readScript("reduce", viewId) } | |
: null | |
} | |
}))) | |
}} : null | |
const updates = updateIds.length ? { updates:{ | |
//merge updates | |
...Object.assign(...updateIds.map( updateId => ({ | |
[updateId]:this.readScript("update", updateId) | |
}))) | |
}}: null | |
return [ | |
{ | |
_id:"_design/lowban", | |
...views, | |
...updates, | |
} | |
] | |
} | |
} | |
module.exports = { | |
Loader | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment