├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── README.md ├── bin └── couchdb-view-tester ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | cache: 4 | directories: 5 | - node_modules 6 | notifications: 7 | email: false 8 | node_js: 9 | - '4' 10 | before_install: 11 | - npm i -g npm@^3.0.0 12 | before_script: 13 | - npm prune 14 | after_success: 15 | - npm run semantic-release 16 | branches: 17 | except: 18 | - /^v\d+\.\d+\.\d+$/ 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource+coc@martynus.net. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [https://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: https://contributor-covenant.org 74 | [version]: https://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # couchdb-view-tester 2 | 3 | > Your friendly helper to quickly iterate on CouchDB views 4 | 5 | ## CLI usage 6 | 7 | ``` 8 | # npm install -g couchdb-view-tester 9 | couchdb-view-tester [--watch] --map= --reduce= 10 | ``` 11 | 12 | ### Example 13 | 14 | Give your CouchDB database you want to test your map/reduce function on 15 | is accessible at http://localhost:5984/mydb, do 16 | 17 | ``` 18 | couchdb-view-tester http://localhost:5984/mydb --map=./path/to/map.js --reduce=./path/to/reduce.js --limit=3 19 | ``` 20 | 21 | Both, `map.js` and `reduce.js` must return an anonymous function, for example 22 | 23 | ```js 24 | // map.js 25 | module.exports = function(doc) { 26 | if (doc.Type == "customer") { 27 | emit(doc._id, doc.LastName); 28 | } 29 | } 30 | ``` 31 | 32 | ```js 33 | // reduce.js 34 | function (key, values, rereduce) { 35 | return sum(values); 36 | } 37 | ``` 38 | 39 | ### View options 40 | 41 | Options are equal to PouchDB's `db.query` options: 42 | http://pouchdb.com/api.html#query_database 43 | 44 | ## Future plans / ideas 45 | 46 | - add support for built in reduce functions 47 | - add support for map functions only 48 | - add docs for usage via `require('couchdb-view-tester')` 49 | - add yours™ 50 | -------------------------------------------------------------------------------- /bin/couchdb-view-tester: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path') 4 | var args = require('minimist')(process.argv.slice(2)) 5 | 6 | var dbUrl = args._[0] 7 | var map = args.map && path.resolve(process.cwd(), args.map) 8 | var reduce = args.reduce && ({ 9 | '_sum': '_sum', 10 | '_count': '_count', 11 | '_stats': '_stats' 12 | }[args.reduce] || path.resolve(process.cwd(), args.reduce)) 13 | var watch = args.watch 14 | var main = require('../index') 15 | 16 | var options = { 17 | startkey: args.startkey && JSON.parse(args.startkey), 18 | endkey: args.endkey && JSON.parse(args.endkey), 19 | group_level: args.group_level, 20 | group: args.group, 21 | limit: args.limit 22 | } 23 | 24 | main({ 25 | dbUrl: dbUrl, 26 | map: map, 27 | reduce: reduce, 28 | watch: watch, 29 | options: options 30 | }) 31 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* exported map, reduce */ 2 | 3 | var path = require('path') 4 | var gaze = require('gaze') 5 | var PouchDB = require('pouchdb') 6 | var clear = require('clear') 7 | 8 | module.exports = function (config) { 9 | var db = new PouchDB(config.dbUrl) 10 | var mapReduce = { 11 | map: config.map && require(config.map) 12 | } 13 | 14 | if (config.reduce) { 15 | mapReduce.reduce = { 16 | '_sum': '_sum', 17 | '_count': '_count', 18 | '_stats': '_stats' 19 | }[config.reduce] || require(config.reduce) 20 | } 21 | 22 | doQuery(db, mapReduce, config.options) 23 | 24 | if (!config.watch) { 25 | return 26 | } 27 | 28 | gaze([config.map, config.reduce].filter(Boolean), function (error, watcher) { 29 | if (error) { 30 | throw error 31 | } 32 | watcher.on('changed', function (filepath) { 33 | var method = toMethod(config, filepath) 34 | delete require.cache[filepath] 35 | mapReduce[method] = require(filepath) 36 | clear() 37 | console.log('%s changed.\n\n', filepath) 38 | doQuery(db, mapReduce, config.options) 39 | }) 40 | }) 41 | 42 | console.log('watching for changes...\n\n') 43 | } 44 | 45 | function doQuery (db, mapReduce, options) { 46 | db.query(mapReduce, options, function (error, response) { 47 | if (error) { 48 | return console.log(error) 49 | } 50 | 51 | console.log(JSON.stringify(response, null, 2)) 52 | }) 53 | } 54 | 55 | function toMethod (config, filepath) { 56 | return path.resolve(config.map) === filepath ? 'map' : 'reduce' 57 | } 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "couchdb-view-tester", 3 | "description": "Your friendly helper to quickly iterate on CouchDB views", 4 | "main": "index.js", 5 | "bin": { 6 | "couchdb-view-tester": "./bin/couchdb-view-tester" 7 | }, 8 | "scripts": { 9 | "test": "standard", 10 | "start": "node index.js", 11 | "watch": "watch 'clear && node index.js' ./lib", 12 | "semantic-release": "semantic-release pre && npm publish && semantic-release post" 13 | }, 14 | "author": "Gregor Martynus ", 15 | "license": "ISC", 16 | "dependencies": { 17 | "cardinal": "^0.5.0", 18 | "clear": "0.0.1", 19 | "gaze": "^0.5.1", 20 | "minimist": "^1.1.1", 21 | "pouchdb": "^3.5.0" 22 | }, 23 | "devDependencies": { 24 | "semantic-release": "^6.3.0", 25 | "standard": "^7.1.2" 26 | }, 27 | "repository": "github:gr2m/couchdb-view-tester" 28 | } 29 | --------------------------------------------------------------------------------