UNPKG

pg-copy-streams

Version:

Low-Level COPY TO and COPY FROM streams for PostgreSQL in JavaScript using

377 lines (299 loc) 8.59 kB
const Buffer = require('buffer').Buffer function OffsetBuffer() { this.offset = 0 this.size = 0 this.buffers = [] } module.exports = OffsetBuffer OffsetBuffer.prototype.isEmpty = function isEmpty() { return this.size === 0 } OffsetBuffer.prototype.clone = function clone(size) { const r = new OffsetBuffer() r.offset = this.offset r.size = size r.buffers = this.buffers.slice() return r } OffsetBuffer.prototype.toChunks = function toChunks() { if (this.size === 0) return [] // We are going to slice it anyway if (this.offset !== 0) { this.buffers[0] = this.buffers[0].slice(this.offset) this.offset = 0 } const chunks = [] let off = 0 let i for (i = 0; off <= this.size && i < this.buffers.length; i++) { let buf = this.buffers[i] off += buf.length // Slice off last buffer if (off > this.size) { buf = buf.slice(0, buf.length - (off - this.size)) this.buffers[i] = buf } chunks.push(buf) } // If some buffers were skipped - trim length if (i < this.buffers.length) this.buffers.length = i return chunks } OffsetBuffer.prototype.toString = function toString(enc) { return this.toChunks() .map(function (c) { return c.toString(enc) }) .join('') } OffsetBuffer.prototype.use = function use(buf, off, n) { this.buffers = [buf] this.offset = off this.size = n } OffsetBuffer.prototype.push = function push(data) { // Ignore empty writes if (data.length === 0) return this.size += data.length this.buffers.push(data) } OffsetBuffer.prototype.has = function has(n) { return this.size >= n } OffsetBuffer.prototype.skip = function skip(n) { if (this.size === 0) return this.size -= n // Fast case, skip bytes in a first buffer if (this.offset + n < this.buffers[0].length) { this.offset += n return } let left = n - (this.buffers[0].length - this.offset) this.offset = 0 let shift for (shift = 1; left > 0 && shift < this.buffers.length; shift++) { const buf = this.buffers[shift] if (buf.length > left) { this.offset = left break } left -= buf.length } this.buffers = this.buffers.slice(shift) } OffsetBuffer.prototype.copy = function copy(target, targetOff, off, n) { if (this.size === 0) return if (off !== 0) throw new Error('Unsupported offset in .copy()') let toff = targetOff const first = this.buffers[0] const toCopy = Math.min(n, first.length - this.offset) first.copy(target, toff, this.offset, this.offset + toCopy) toff += toCopy let left = n - toCopy for (let i = 1; left > 0 && i < this.buffers.length; i++) { const buf = this.buffers[i] const toCopy = Math.min(left, buf.length) buf.copy(target, toff, 0, toCopy) toff += toCopy left -= toCopy } } OffsetBuffer.prototype.take = function take(n) { if (n === 0) return Buffer.alloc(0) this.size -= n // Fast cases const first = this.buffers[0].length - this.offset if (first === n) { let r = this.buffers.shift() if (this.offset !== 0) { r = r.slice(this.offset) this.offset = 0 } return r } else if (first > n) { const r = this.buffers[0].slice(this.offset, this.offset + n) this.offset += n return r } // Allocate and fill buffer const out = Buffer.alloc(n) let toOff = 0 let startOff = this.offset let i for (i = 0; toOff !== n && i < this.buffers.length; i++) { const buf = this.buffers[i] const toCopy = Math.min(buf.length - startOff, n - toOff) buf.copy(out, toOff, startOff, startOff + toCopy) if (startOff + toCopy < buf.length) { this.offset = startOff + toCopy break } else { toOff += toCopy startOff = 0 } } this.buffers = this.buffers.slice(i) if (this.buffers.length === 0) this.offset = 0 return out } OffsetBuffer.prototype.peekUInt8 = function peekUInt8() { return this.buffers[0][this.offset] } OffsetBuffer.prototype.readUInt8 = function readUInt8() { this.size -= 1 const first = this.buffers[0] const r = first[this.offset] if (++this.offset === first.length) { this.offset = 0 this.buffers.shift() } return r } OffsetBuffer.prototype.readUInt16LE = function readUInt16LE() { const first = this.buffers[0] this.size -= 2 let r let shift // Fast case - first buffer has all bytes if (first.length - this.offset >= 2) { r = first.readUInt16LE(this.offset) shift = 0 this.offset += 2 // One byte here - one byte there } else { r = first[this.offset] | (this.buffers[1][0] << 8) shift = 1 this.offset = 1 } if (this.offset === this.buffers[shift].length) { this.offset = 0 shift++ } if (shift !== 0) this.buffers = this.buffers.slice(shift) return r } OffsetBuffer.prototype.readUInt24LE = function readUInt24LE() { const first = this.buffers[0] let r let shift const firstHas = first.length - this.offset // Fast case - first buffer has all bytes if (firstHas >= 3) { r = first.readUInt16LE(this.offset) | (first[this.offset + 2] << 16) shift = 0 this.offset += 3 // First buffer has 2 of 3 bytes } else if (firstHas >= 2) { r = first.readUInt16LE(this.offset) | (this.buffers[1][0] << 16) shift = 1 this.offset = 1 // Slow case: First buffer has 1 of 3 bytes } else { r = first[this.offset] this.offset = 0 this.buffers.shift() this.size -= 1 r |= this.readUInt16LE() << 8 return r } this.size -= 3 if (this.offset === this.buffers[shift].length) { this.offset = 0 shift++ } if (shift !== 0) this.buffers = this.buffers.slice(shift) return r } OffsetBuffer.prototype.readUInt32LE = function readUInt32LE() { const first = this.buffers[0] let r let shift const firstHas = first.length - this.offset // Fast case - first buffer has all bytes if (firstHas >= 4) { r = first.readUInt32LE(this.offset) shift = 0 this.offset += 4 // First buffer has 3 of 4 bytes } else if (firstHas >= 3) { r = (first.readUInt16LE(this.offset) | (first[this.offset + 2] << 16)) + this.buffers[1][0] * 0x1000000 shift = 1 this.offset = 1 // Slow case: First buffer has 2 of 4 bytes } else if (firstHas >= 2) { r = first.readUInt16LE(this.offset) this.offset = 0 this.buffers.shift() this.size -= 2 r += this.readUInt16LE() * 0x10000 return r // Slow case: First buffer has 1 of 4 bytes } else { r = first[this.offset] this.offset = 0 this.buffers.shift() this.size -= 1 r += this.readUInt24LE() * 0x100 return r } this.size -= 4 if (this.offset === this.buffers[shift].length) { this.offset = 0 shift++ } if (shift !== 0) this.buffers = this.buffers.slice(shift) return r } OffsetBuffer.prototype.readUInt16BE = function readUInt16BE() { const r = this.readUInt16LE() return ((r & 0xff) << 8) | (r >> 8) } OffsetBuffer.prototype.readUInt24BE = function readUInt24BE() { const r = this.readUInt24LE() return ((r & 0xff) << 16) | (((r >> 8) & 0xff) << 8) | (r >> 16) } OffsetBuffer.prototype.readUInt32BE = function readUInt32BE() { const r = this.readUInt32LE() return (((r & 0xff) << 24) | (((r >>> 8) & 0xff) << 16) | (((r >>> 16) & 0xff) << 8) | (r >>> 24)) >>> 0 } // Signed number APIs function signedInt8(num) { if (num >= 0x80) return -(0xff ^ num) - 1 else return num } OffsetBuffer.prototype.peekInt8 = function peekInt8() { return signedInt8(this.peekUInt8()) } OffsetBuffer.prototype.readInt8 = function readInt8() { return signedInt8(this.readUInt8()) } function signedInt16(num) { if (num >= 0x8000) return -(0xffff ^ num) - 1 else return num } OffsetBuffer.prototype.readInt16BE = function readInt16BE() { return signedInt16(this.readUInt16BE()) } OffsetBuffer.prototype.readInt16LE = function readInt16LE() { return signedInt16(this.readUInt16LE()) } function signedInt24(num) { if (num >= 0x800000) return -(0xffffff ^ num) - 1 else return num } OffsetBuffer.prototype.readInt24BE = function readInt24BE() { return signedInt24(this.readUInt24BE()) } OffsetBuffer.prototype.readInt24LE = function readInt24LE() { return signedInt24(this.readUInt24LE()) } function signedInt32(num) { if (num >= 0x80000000) return -(0xffffffff ^ num) - 1 else return num } OffsetBuffer.prototype.readInt32BE = function readInt32BE() { return signedInt32(this.readUInt32BE()) } OffsetBuffer.prototype.readInt32LE = function readInt32LE() { return signedInt32(this.readUInt32LE()) }