diff --git a/Readme.md b/Readme.md index 69fabf2..60bc7b9 100644 --- a/Readme.md +++ b/Readme.md @@ -69,6 +69,16 @@ res.csv([ { name: "joe", id: 1 }] //=> "joe", 1 ``` +csv also expose a generate() function that generate a csv string from an array, E.g: + +```js +var csvString = csv.generate([ + ["a", "b", "c"] + , ["d", "e", "f"] + ]); +// => csvString = '"a", "b", "c"\n"d", "e", "f"' +``` + ## License The MIT License diff --git a/lib/express-csv.js b/lib/express-csv.js index fcc1d69..d22c38a 100644 --- a/lib/express-csv.js +++ b/lib/express-csv.js @@ -82,6 +82,23 @@ function objToArray(obj) { return result; } +/** + * Generate a csv string fom an object + * + * @param {Array} obj + * @return {String} +*/ + +exports.generate = function(obj) { + var str = ''; + obj.forEach(function(item) { + if (!(item instanceof Array)) item = objToArray(item); + str += item.map(escape).join(exports.separator) + '\r\n'; + }); + return str; +}; + + /** * Send CSV response with `obj`, optional `headers`, and optional `status`. * @@ -93,16 +110,11 @@ function objToArray(obj) { */ res.csv = function(obj, headers, status) { - var body = ''; + var body = exports.generate(obj); this.charset = this.charset || 'utf-8'; this.header('Content-Type', 'text/csv'); - obj.forEach(function(item) { - if (!(item instanceof Array)) item = objToArray(item); - body += item.map(escape).join(exports.separator) + '\r\n'; - }); - return this.send(body, headers, status); }; diff --git a/test/index.js b/test/index.js index 74cc9ce..6e9b307 100644 --- a/test/index.js +++ b/test/index.js @@ -3,30 +3,35 @@ var express = require('express') , csv = require('../') , app = express.createServer(); +var test1Data = [ + ['a', 'b', 'c'] + , ['d', 'e', 'f'] + ] + , test2Data = [ + [ 'a', 'b', null ] + ] + , test3Data = [ + [ 'a', 'b', undefined ] + ] + , testObjectArrayData = [ + { stringProp: "a", nullProp: null, undefinedProp: undefined }, + { stringProp: "b", nullProp: null, undefinedProp: undefined } + ]; + app.get('/test/1', function(req, res) { - res.csv([ - ['a', 'b', 'c'] - , ['d', 'e', 'f'] - ]); + res.csv(test1Data); }); app.get('/test/2', function(req, res) { - res.csv([ - [ 'a', 'b', null ] - ]); + res.csv(test2Data); }); app.get('/test/3', function(req, res) { - res.csv([ - [ 'a', 'b', undefined ] - ]); + res.csv(test3Data); }); app.get('/test/objectArray', function(req, res) { - res.csv([ - { stringProp: "a", nullProp: null, undefinedProp: undefined }, - { stringProp: "b", nullProp: null, undefinedProp: undefined } - ]); + res.csv(testObjectArrayData); }); app.listen(8383); @@ -37,28 +42,131 @@ describe('express-csv', function() { }); it('should expose .separator', function() { - csv.separator.should.be.a('string'); + csv.separator.should.be.type('string'); }); it('should expose .preventCast', function() { - csv.preventCast.should.be.a('boolean'); + csv.preventCast.should.be.type('boolean'); }); it('should expose .ignoreNullOrUndefined', function() { - csv.ignoreNullOrUndefined.should.be.a('boolean'); + csv.ignoreNullOrUndefined.should.be.type('boolean'); + }); + + it('should expose .generate()', function() { + csv.generate.should.be.type('function'); }); it('should extend res.csv', function() { if (express.version.match(/^2\.[0-9]+\.[0-9]+$/)) { // express 2.x - require('http').ServerResponse.prototype.csv.should.be.a('function'); + require('http').ServerResponse.prototype.csv.should.be.type('function'); } else { // express 3.x - require('express').response.csv.should.be.a('function'); + require('express').response.csv.should.be.type('function'); } }); }); +describe('csv.generate()', function() { + describe('when given an array of objects', function() { + describe('and ignoreNullOrUndefined is true', function() { + var rows; + + beforeEach(function() { + console.log(csv.generate(testObjectArrayData)); + rows = csv.generate(testObjectArrayData).split("\r\n"); + }); + + it('should include values that exist', function() { + rows[0].split(",")[0].should.equal('"a"'); + rows[1].split(",")[0].should.equal('"b"'); + }); + + it('should exclude null', function() { + rows[0].split(",")[1].should.equal(''); + rows[0].split(",")[2].should.equal(''); + }); + + it('should exclude undefined', function() { + rows[0].split(",")[2].should.equal(''); + rows[1].split(",")[2].should.equal(''); + }); + + + describe('and ignoreNullOrUndefined is false', function() { + var rows; + + beforeEach(function() { + csv.ignoreNullOrUndefined = false; + rows = csv.generate(testObjectArrayData).split("\r\n"); + }); + + afterEach(function() { + csv.ignoreNullOrUndefined = true; + }); + + it('should include values that exist', function() { + rows[0].split(",")[0].should.equal('"a"'); + rows[1].split(",")[0].should.equal('"b"'); + }); + + it('should include null', function() { + rows[0].split(",")[1].should.equal('"null"'); + rows[1].split(",")[1].should.equal('"null"'); + }); + + it('should include undefined', function() { + rows[0].split(",")[2].should.equal('"undefined"'); + rows[1].split(",")[2].should.equal('"undefined"'); + }); + }); + }); + }); + + it('should return csv', function() { + csv.generate(test1Data).should.equal('"a","b","c"\r\n"d","e","f"\r\n'); + }); + + it('should generate a csv that ignores null', function() { + csv.generate(test2Data).should.equal('"a","b",\r\n'); + }); + + it('should generate a csv that ignores undefined', function() { + csv.generate(test3Data).should.equal('"a","b",\r\n'); + }); + + it('should generate a csv that include null', function() { + var prevOption = csv.ignoreNullOrUndefined; + csv.ignoreNullOrUndefined = false; + csv.generate(test2Data).should.equal('"a","b","null"\r\n'); + csv.ignoreNullOrUndefined = prevOption; + }); + + it('should generate a csv that includes undefined', function() { + var prevOption = csv.ignoreNullOrUndefined; + csv.ignoreNullOrUndefined = false; + + csv.generate(test3Data).should.equal('"a","b","undefined"\r\n'); + csv.ignoreNullOrUndefined = prevOption; + }); + + it('should generate a tsv', function() { + var prevSeparator = csv.separator; + csv.separator = '\t'; + csv.generate(test1Data).should.equal('"a"\t"b"\t"c"\r\n"d"\t"e"\t"f"\r\n'); + csv.separator = prevSeparator; + }); + + it('should generate a quoted csv', function() { + var prevSetting = csv.preventCast; + csv.preventCast = true; + csv.generate(test1Data).should.equal('="a",="b",="c"\r\n="d",="e",="f"\r\n'); + csv.preventCast = prevSetting; + }); +}); + + describe('res.csv()', function() { describe('when given an array of objects', function() {