Skip to content

Add pg cursor #2030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 97 commits into from
Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
5d27cf2
Initial commit
brianc Oct 7, 2013
fc875b0
Rename method
brianc Oct 7, 2013
31fd30d
Fix test
brianc Oct 7, 2013
8a3b3d4
Bump version
brianc Oct 7, 2013
40af7c2
Update package.jsn
brianc Nov 8, 2013
9e2f622
Port tests to use mocha
brianc Nov 8, 2013
2e33d4a
Add default mocha options
brianc Nov 8, 2013
31b2b1d
All tests passing in isolation
brianc Nov 12, 2013
9af987f
Pass all tests
brianc Nov 21, 2013
a275ada
Create README.md
brianc Nov 21, 2013
dc92b12
Update README.md
brianc Nov 21, 2013
87c3cf5
Bump version
brianc Dec 17, 2013
a3074e9
Bump mocha version
brianc Feb 26, 2014
4925172
Fix require problem for `pg` module
brianc Feb 26, 2014
cc9f08a
Bump version
brianc Feb 26, 2014
f1dbe78
Normalize parameter values
brianc Feb 26, 2014
b1b39bb
Bump version
brianc Feb 26, 2014
1a9fd7f
Do not callback with final empty array until readyForQuery is received
brianc Mar 21, 2014
37de20e
Bump version
brianc Mar 21, 2014
f7b6572
fix typo
grncdr May 21, 2014
9cc3e52
add failing test for noData queries
grncdr May 21, 2014
5084624
fix test command in package.json
grncdr May 21, 2014
8283fd9
add support for queries that don't return a row description
grncdr May 21, 2014
8bfd3a5
Merge pull request #5 from grncdr/no-row-description
brianc May 22, 2014
b9fd38d
Bump version
brianc May 22, 2014
19a2d26
Add client#close
brianc Sep 25, 2014
40f361f
Add boilerplate files
brianc Sep 25, 2014
8d395ff
Bump version
brianc Sep 25, 2014
56ebc6a
Fix typo: itterate -> iterate
dmnd Mar 18, 2015
a01a555
Merge pull request #12 from dmnd/patch-1
brianc Mar 19, 2015
74b6891
handle empty query
rickbergfalk Jun 28, 2016
02dc31f
Merge pull request #17 from rickbergfalk/master
brianc Jun 29, 2016
4f62085
Bump version
brianc Jun 29, 2016
af84d5c
Fix require for webpack compatibility
crisvergara Dec 5, 2016
24d85f5
Merge pull request #19 from crisvergara/master
brianc Apr 27, 2017
a320416
Bump version
brianc Apr 27, 2017
557e5f8
Return result accumulator in callback
sberan Apr 27, 2017
3cad54e
Merge pull request #23 from sberan/cursor-result
brianc Apr 27, 2017
4bf66e6
Bump version
brianc Apr 27, 2017
42af014
Update travis.yml
brianc May 8, 2017
acae15d
Emit Query Events
sberan May 8, 2017
2f48021
fix: only dispatch error events if we have a listener
sberan May 9, 2017
4427e31
fix travis build env
sberan May 9, 2017
bbc2b41
Merge pull request #25 from sberan/cursor-result
brianc May 16, 2017
6e462ff
Bump version
brianc May 16, 2017
9c7d2c8
Test cursor with pg-pool
rickbergfalk Aug 4, 2017
6072bce
Merge remote-tracking branch 'brianc/master'
rickbergfalk Aug 4, 2017
620ddc0
Do not send close after readyForQuery
brianc Aug 4, 2017
25d978e
Merge pull request #28 from brianc/rickbergfalk-master
brianc Aug 5, 2017
5a0af8c
Bump version
brianc Aug 5, 2017
a720dc7
Some cleanup
brianc Aug 5, 2017
3675d2b
Fix to support node@4 LTS
brianc Aug 5, 2017
2ced8f1
Integrate eslint
brianc Aug 5, 2017
bbefeb8
Remove unused file
brianc Aug 5, 2017
71f30fa
Merge pull request #29 from brianc/no-sync-callbacks
brianc Aug 5, 2017
5b4bb7b
Bump version
brianc Aug 5, 2017
4ff97f5
Add support for rowMode & custom types
brianc Aug 5, 2017
e0b2e41
Fix lint
brianc Aug 5, 2017
b97a442
Merge pull request #30 from brianc/suport-query-config
brianc Aug 6, 2017
796d141
Bump version
brianc Aug 6, 2017
c0f5518
Update README.md
brianc Aug 8, 2017
24e485e
Fix closing a finished cursor without supplying a callback
Oct 4, 2017
2398e99
return rowCount on insert
jakobrun Jan 1, 2018
7eabfbe
Add repo to package.json
savvymas Jun 20, 2018
91bdbbd
Merge pull request #40 from savvymas/patch-1
brianc Jun 21, 2018
19c68c7
fix: AWS Redshift requires a portal name to honor fetchSize
jafl Oct 17, 2018
37997fe
fix formatting issues
jafl Oct 23, 2018
6fc07b4
fix: remove support for deprecated pg.js package
mikl Dec 4, 2018
73506d3
Merge pull request #47 from pistor/remove-pg.js-support
brianc Jan 8, 2019
0a10525
Merge pull request #44 from jafl/redshift-requires-portal-name
brianc Jan 8, 2019
1200da5
Fix test
brianc Jan 8, 2019
67b880a
Merge pull request #35 from jakobrun/master
brianc Jan 8, 2019
71dde04
Merge branch 'master' of github.com:brianc/node-pg-cursor
brianc Jan 8, 2019
1cdad4d
Bump version. Drop support for pg.js
brianc Jan 8, 2019
b0f7958
Fix hanging listener when error occured
juneidy Jun 27, 2019
414fac6
Apply prettier to code, change lint rules
brianc Oct 25, 2019
4164686
meh
brianc Oct 25, 2019
be03212
Update lint, fix for [email protected]
brianc Oct 25, 2019
6d47026
Merge pull request #57 from brianc/bmc/lint-changes
brianc Oct 25, 2019
ff09b3f
Merge branch 'master' into fix-closing-finished-connections
brianc Oct 25, 2019
d3aee3d
Add additional pool test & deprecate .end
brianc Oct 28, 2019
389d5d8
Fix named portal being left open
brianc Oct 30, 2019
bd86514
Add another test
brianc Oct 30, 2019
d0e67a9
Merge pull request #59 from brianc/bmc/fix-named-portal
brianc Oct 30, 2019
507c7ea
Merge branch 'master' into bmc/add-test-and-deprecate-method
brianc Oct 30, 2019
cedce4b
Fix lint & enable all tests
brianc Oct 30, 2019
5055b3a
Merge pull request #58 from brianc/bmc/add-test-and-deprecate-method
brianc Oct 30, 2019
3790609
Bump version
brianc Oct 30, 2019
124c89b
fix lint issues
Dec 13, 2019
e34c602
Merge pull request #32 from hetul/fix-closing-finished-connections
brianc Dec 18, 2019
e20d012
Merge branch 'master' of https://github.com/juneidysoo/node-pg-cursor…
brianc Dec 18, 2019
492fbdb
Merge branch 'juneidysoo-master'
brianc Dec 18, 2019
37d1574
Add 'packages/pg-cursor/' from commit '492fbdbb65f6f33396d1017fa4cdbb…
brianc Dec 18, 2019
423baa6
Update lint rules for pg-cursor
brianc Dec 18, 2019
5c0c93c
Remove nested travis file
brianc Dec 18, 2019
57177d7
Use public npm - accidentally had my work npm configured
brianc Dec 18, 2019
b14cf67
Remove postgres 9.1 from test matrix - json is not supported
brianc Dec 18, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
{
"plugins": [
"node"
],
"extends": [
"standard",
"eslint:recommended",
"plugin:node/recommended"
],
"plugins": ["node"],
"extends": ["standard", "eslint:recommended", "plugin:node/recommended"],
"parserOptions": {
"ecmaVersion": 2017
},
"env": {
"node": true,
"es6": true
"es6": true,
"mocha": true
},
"rules": {
"space-before-function-paren": "off",
"node/no-unpublished-require": [
"error",
{
"allowModules": ["pg"]
}
]
}
}
6 changes: 1 addition & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ matrix:
addons:
postgresql: "9.6"

# PostgreSQL 9.1 and 9.2 only work on precise
- node_js: lts/carbon
addons:
postgresql: "9.1"
dist: precise
# PostgreSQL 9.2 only works on precise
- node_js: lts/carbon
addons:
postgresql: "9.2"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"packages/*"
],
"scripts": {
"test": "yarn lerna exec --parallel yarn test"
"test": "yarn lerna exec --parallel yarn test",
"lint": "yarn lerna exec --parallel yarn lint"
},
"devDependencies": {
"lerna": "^3.19.0"
Expand Down
1 change: 1 addition & 0 deletions packages/pg-cursor/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
15 changes: 15 additions & 0 deletions packages/pg-cursor/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.PHONY: test
test:
npm test

.PHONY: patch
patch: test
npm version patch -m "Bump version"
git push origin master --tags
npm publish

.PHONY: minor
minor: test
npm version minor -m "Bump version"
git push origin master --tags
npm publish
37 changes: 37 additions & 0 deletions packages/pg-cursor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
node-pg-cursor
==============

Use a PostgreSQL result cursor from node with an easy to use API.

### install

```sh
$ npm install pg-cursor
```
___note___: this depends on _either_ `npm install pg` or `npm install pg.js`, but you __must__ be using the pure JavaScript client. This will __not work__ with the native bindings.

### :star: [Documentation](https://node-postgres.com/api/cursor) :star:

### license

The MIT License (MIT)

Copyright (c) 2013 Brian M. Carlson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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.
218 changes: 218 additions & 0 deletions packages/pg-cursor/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
'use strict'
const Result = require('pg/lib/result.js')
const prepare = require('pg/lib/utils.js').prepareValue
const EventEmitter = require('events').EventEmitter
const util = require('util')

let nextUniqueID = 1 // concept borrowed from org.postgresql.core.v3.QueryExecutorImpl

function Cursor (text, values, config) {
EventEmitter.call(this)

this._conf = config || {}
this.text = text
this.values = values ? values.map(prepare) : null
this.connection = null
this._queue = []
this.state = 'initialized'
this._result = new Result(this._conf.rowMode, this._conf.types)
this._cb = null
this._rows = null
this._portal = null
this._ifNoData = this._ifNoData.bind(this)
this._rowDescription = this._rowDescription.bind(this)
}

util.inherits(Cursor, EventEmitter)

Cursor.prototype._ifNoData = function () {
this.state = 'idle'
this._shiftQueue()
}

Cursor.prototype._rowDescription = function () {
if (this.connection) {
this.connection.removeListener('noData', this._ifNoData)
}
}

Cursor.prototype.submit = function (connection) {
this.connection = connection
this._portal = 'C_' + nextUniqueID++

const con = connection

con.parse(
{
text: this.text
},
true
)

con.bind(
{
portal: this._portal,
values: this.values
},
true
)

con.describe(
{
type: 'P',
name: this._portal // AWS Redshift requires a portal name
},
true
)

con.flush()

if (this._conf.types) {
this._result._getTypeParser = this._conf.types.getTypeParser
}

con.once('noData', this._ifNoData)
con.once('rowDescription', this._rowDescription)
}

Cursor.prototype._shiftQueue = function () {
if (this._queue.length) {
this._getRows.apply(this, this._queue.shift())
}
}

Cursor.prototype._closePortal = function () {
// because we opened a named portal to stream results
// we need to close the same named portal. Leaving a named portal
// open can lock tables for modification if inside a transaction.
// see https://github.com/brianc/node-pg-cursor/issues/56
this.connection.close({ type: 'P', name: this._portal })
this.connection.sync()
}

Cursor.prototype.handleRowDescription = function (msg) {
this._result.addFields(msg.fields)
this.state = 'idle'
this._shiftQueue()
}

Cursor.prototype.handleDataRow = function (msg) {
const row = this._result.parseRow(msg.fields)
this.emit('row', row, this._result)
this._rows.push(row)
}

Cursor.prototype._sendRows = function () {
this.state = 'idle'
setImmediate(() => {
const cb = this._cb
// remove callback before calling it
// because likely a new one will be added
// within the call to this callback
this._cb = null
if (cb) {
this._result.rows = this._rows
cb(null, this._rows, this._result)
}
this._rows = []
})
}

Cursor.prototype.handleCommandComplete = function (msg) {
this._result.addCommandComplete(msg)
this._closePortal()
}

Cursor.prototype.handlePortalSuspended = function () {
this._sendRows()
}

Cursor.prototype.handleReadyForQuery = function () {
this._sendRows()
this.state = 'done'
this.emit('end', this._result)
}

Cursor.prototype.handleEmptyQuery = function () {
this.connection.sync()
}

Cursor.prototype.handleError = function (msg) {
this.connection.removeListener('noData', this._ifNoData)
this.connection.removeListener('rowDescription', this._rowDescription)
this.state = 'error'
this._error = msg
// satisfy any waiting callback
if (this._cb) {
this._cb(msg)
}
// dispatch error to all waiting callbacks
for (let i = 0; i < this._queue.length; i++) {
this._queue.pop()[1](msg)
}

if (this.listenerCount('error') > 0) {
// only dispatch error events if we have a listener
this.emit('error', msg)
}
// call sync to keep this connection from hanging
this.connection.sync()
}

Cursor.prototype._getRows = function (rows, cb) {
this.state = 'busy'
this._cb = cb
this._rows = []
const msg = {
portal: this._portal,
rows: rows
}
this.connection.execute(msg, true)
this.connection.flush()
}

// users really shouldn't be calling 'end' here and terminating a connection to postgres
// via the low level connection.end api
Cursor.prototype.end = util.deprecate(function (cb) {
if (this.state !== 'initialized') {
this.connection.sync()
}
this.connection.once('end', cb)
this.connection.end()
}, 'Cursor.end is deprecated. Call end on the client itself to end a connection to the database.')

Cursor.prototype.close = function (cb) {
if (this.state === 'done') {
if (cb) {
return setImmediate(cb)
} else {
return
}
}
this._closePortal()
this.state = 'done'
if (cb) {
this.connection.once('closeComplete', function () {
cb()
})
}
}

Cursor.prototype.read = function (rows, cb) {
if (this.state === 'idle') {
return this._getRows(rows, cb)
}
if (this.state === 'busy' || this.state === 'initialized') {
return this._queue.push([rows, cb])
}
if (this.state === 'error') {
return setImmediate(() => cb(this._error))
}
if (this.state === 'done') {
return setImmediate(() => cb(null, []))
} else {
throw new Error('Unknown state: ' + this.state)
}
}

module.exports = Cursor
33 changes: 33 additions & 0 deletions packages/pg-cursor/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "pg-cursor",
"version": "2.0.1",
"description": "Query cursor extension for node-postgres",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "mocha && eslint .",
"lint": "eslint ."
},
"repository": {
"type": "git",
"url": "git://github.com/brianc/node-pg-cursor.git"
},
"author": "Brian M. Carlson",
"license": "MIT",
"devDependencies": {
"eslint": "^6.5.1",
"eslint-config-prettier": "^6.4.0",
"eslint-plugin-prettier": "^3.1.1",
"mocha": "^6.2.2",
"pg": "7.x",
"prettier": "^1.18.2"
},
"prettier": {
"semi": false,
"printWidth": 120,
"trailingComma": "none",
"singleQuote": true
}
}
Loading