sql-insert-query-stream
Version:
A Transform stream that generates a bulk SQL insert query
79 lines (57 loc) • 2.12 kB
JavaScript
'use strict'
var Transform = require('stream').Transform
var inherits = require('util').inherits
module.exports = InsertQueryStream
function InsertQueryStream (options) {
if (!(this instanceof InsertQueryStream)) {
return new InsertQueryStream(options)
}
this.table = options.table
this.columns = null
this.quote = options.quote || '"'
this.indent = options.indent || ' '
this.first = true
Transform.call(this, {
objectMode: true
})
}
inherits(InsertQueryStream, Transform)
/*
I wrote this with the odd-looking handling of this.previous via this.unshift
in order to only flush each line when the next line is received. This way the
stream can know whether this.previous is the last line (written in _flush) or
should be followed by a comma (normal _transform). The first line will push
the prefixes (insert + values) and each subsequent line will push a line of
values.
*/
InsertQueryStream.prototype._transform = function transform (chunk, enc, callback) {
if (this.first) {
this.prefix(chunk)
this.first = false
}
if (this.previous) this.unshift()
var invalid = Object.keys(chunk).find((key) => !this.columns.includes(key))
if (invalid) return callback(new Error(`Invalid column: "${invalid}"`))
this.previous = this.columns.map((column) => chunk[column])
callback()
}
InsertQueryStream.prototype._flush = function flush (callback) {
this.unshift(true)
callback()
}
InsertQueryStream.prototype.unshift = function unshift (last) {
this.push(this.indent + this.list(this.previous) + (last ? ';' : ',\n'))
}
InsertQueryStream.prototype.prefix = function prefix (chunk, enc, callback) {
this.columns = Object.keys(chunk)
this.push('insert into ' + this.wrap(this.table) + '\n')
this.push(this.indent + this.list(this.columns) + '\n')
this.push('values' + '\n')
}
InsertQueryStream.prototype.wrap = function wrap (value) {
if (typeof value !== 'string') return value
return this.quote + value + this.quote
}
InsertQueryStream.prototype.list = function list (values) {
return '(' + values.map(this.wrap.bind(this)).join(', ') + ')'
}