Skip to content
This repository has been archived by the owner on Jan 9, 2018. It is now read-only.

Add support for CSV headers and fix parsing of numbers #16

Closed
wants to merge 9 commits into from
32 changes: 20 additions & 12 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,66 +1,74 @@
1.0.0 / 2015-09-18
==================

* Fixed tests
* Added support for a header row
* Better handling of data types
* Clean up


0.6.0 / 2013-03-14
0.6.0 / 2013-03-14
==================

* Added support for Node 0.10
* Added Node 0.10 to travis

0.5.0 / 2012-11-01
0.5.0 / 2012-11-01
==================

* Support serializing an array of objects
* Added travis.yml

0.4.1 / 2012-06-26
0.4.1 / 2012-06-26
==================

* Added support for Node 0.8.0

0.4.0 / 2012-06-17
0.4.0 / 2012-06-17
==================

* Avoid extending `http.ServerResponse.prototype` with Express 3.x

0.3.1 / 2012-04-20
0.3.1 / 2012-04-20
==================

* Fixed broken csv output when use `preventCast` option.

0.3.0 / 2012-03-28
0.3.0 / 2012-03-28
==================

* Added option `ignoreNullOrUndefined`.
* Added test.

0.2.1 / 2012-03-28
0.2.1 / 2012-03-28
==================

* Adding clause setting undefined columns to an empty string. [mblackshaw]
* Added `Makefile`.
* Added test.
* Added benchmark.

0.2.0 / 2012-03-21
0.2.0 / 2012-03-21
==================

* Add option `preventCast`.

0.1.1 / 2012-03-18
0.1.1 / 2012-03-18
=================

* Fixed `repository` in package.json

0.1.0 / 2012-03-18
0.1.0 / 2012-03-18
==================

* Added test

0.0.2 / 2012-03-17
0.0.2 / 2012-03-17
==================

* Add option `separator`. Default is `,`.

0.0.1 / 2012-03-17
0.0.1 / 2012-03-17
==================

* Initial release.
108 changes: 57 additions & 51 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
[![build status](https://secure.travis-ci.org/nulltask/express-csv.png)](http://travis-ci.org/nulltask/express-csv)
# Express CSV
# csv-express

```
_____ ____ ______ __
| ____|_ ___ __ _ __ ___ ___ ___ / ___/ ___\ \ / /
| _| \ \/ / '_ \| '__/ _ \/ __/ __| | | \___ \\ \ / /
| |___ > <| |_) | | | __/\__ \__ \ | |___ ___) |\ V /
|_____/_/\_\ .__/|_| \___||___/___/ \____|____/ \_/
|_|
```
A CSV response module for [Express](http://expressjs.com/). This is an up-to-date fork of [express-csv](https://github.com/nulltask/express-csv) that merges outstanding pull requests.


## Changes from [express-csv](https://github.com/nulltask/express-csv)
+ Adds support for adding a header row to the CSV ([#16](https://github.com/nulltask/express-csv/pull/16))
+ Better escaping of numbers so that applications such as Excel properly recognize data types
+ Actively maintained for use with more current versions of Express
+ Up to date dependencies and tests

Express CSV provides response CSV easily to [Express](http://expressjs.com/).

## Installation

npm:
````
npm install csv-express
````

## API
### Methods

#### res.csv([data] [, csvHeaders] [, responseHeaders] [, statusCode])

$ npm install express-csv
+ data (**required**) is an array of arrays or objects
+ csvHeaders (*optional*) is a Boolean for returning headers on the output CSV file. Default is false.
+ responseHeaders (*optional*) are custom response headers
+ statusCode (*optional*) is a custom response status code

### Settings
#### #separator
The delimiter to use, default is `','`.

#### #preventCast
Prevent Excels type casting, default is `false`.

#### #ignoreNullOrUndefined
Treat `null` and `undefined` values as empty strings in the output, default is `true`.

## Usage

Example:

```js
var express = require('express')
, csv = require('express-csv')
, app = module.exports = express.createServer();
````
var express = require('express'),
csv = require('csv-express'),
app = express();

app.get('/', function(req, res) {
res.csv([
Expand All @@ -35,41 +53,26 @@ app.get('/', function(req, res) {
});

app.listen(3000);
```

Response:

```
$ curl --verbose http://127.0.0.1:3000/
* About to connect() to 127.0.0.1 port 3000 (#0)
* Trying 127.0.0.1... connected
* Connected to 127.0.0.1 (127.0.0.1) port 3000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5
> Host: 127.0.0.1:3000
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/csv; charset=utf-8
< Content-Length: 26
< Connection: keep-alive
<
"a","b","c"
"d","e","f"
* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0
```

Alternatively, you can also pass an array of objects to be serialized, in which case the object's
properties will be iterated over. E.g.:

```js
res.csv([ { name: "joe", id: 1 }]
//=> "joe", 1
```
````

You can also pass an array of objects and optionally return a header row.
Useful when working with the results from database queries using [node-mysql](https://github.com/felixge/node-mysql/) or [node-postgres](https://github.com/brianc/node-postgres).

````
res.csv([
{"name": "Sam", "age": 1},
{"name": "Mary": "age": 2}
], true);

=> name, age
Sam, 1
Mary, 2
````



## License
The original license is as follows:

The MIT License

Expand All @@ -92,4 +95,7 @@ res.csv([ { name: "joe", id: 1 }]
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

All modifications from the original are CC0.

2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./lib/express-csv');
module.exports = require('./lib/csv-express');
89 changes: 41 additions & 48 deletions lib/express-csv.js → lib/csv-express.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,23 @@
/*!
* express-csv
* Copyright 2011 Seiya Konno <[email protected]>
* MIT Licensed
*/

/**
* Module dependencies.
*/
/*
csv-express
Forked and modified by John J Czaplewski <[email protected]>

var http = require('http')
, express = require('express')
, res = express.response || http.ServerResponse.prototype;

/**
* Import package information.
Copyright 2011 Seiya Konno <[email protected]>
MIT Licensed
*/

var package = require('../package');

/**
* Library version.
*/

exports.version = package.version;
'use strict';

/**
* CSV separator
*/
var res = require('http').ServerResponse.prototype;
var iconv = require('iconv-lite');

// Configurable settings
exports.separator = ',';

/**
* Prevent Excel's casting.
*/

exports.preventCast = false;

/**
* Ignore `null` or `undefined`
*/

exports.ignoreNullOrUndefined = true;

/**
/*
* Escape CSV field
*
* @param {Mixed} field
Expand All @@ -57,6 +32,9 @@ function escape(field) {
if (exports.preventCast) {
return '="' + String(field).replace(/\"/g, '""') + '"';
}
if (!isNaN(parseFloat(field)) && isFinite(field)) {
return parseFloat(field);
}
return '"' + String(field).replace(/\"/g, '""') + '"';
}

Expand All @@ -82,27 +60,42 @@ function objToArray(obj) {
return result;
}

/**
* Send CSV response with `obj`, optional `headers`, and optional `status`.
*
* @param {Array} obj
* @param {Object|Number} headers or status
* @param {Number} status
* @return {ServerResponse}
* @api public

/*
Send CSV response

{data} - Array objects or arrays
{csvHeaders} - If true uses the keys of the objects in {obj} to set a header row
{headers} - Optional response headers
{stats} - Optional status code
*/

res.csv = function(obj, headers, status) {
res.csv = function(data, csvHeaders, headers, status) {
var body = '';

this.charset = this.charset || 'utf-8';
this.header('Content-Type', 'text/csv');

obj.forEach(function(item) {
if (!(item instanceof Array)) item = objToArray(item);
if (csvHeaders) {
var header = [];
for (var prop in data[0]) {
if (data[0].hasOwnProperty(prop)) {
header.push(prop);
}
}
body += header + '\r\n';
}

data.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);
};
if (this.charset !== 'utf-8') {
body = iconv.encode(body, this.charset);
}

return this.send(body, headers, status);
}
Loading