connect-session-knex
Advanced tools
Comparing version 1.0.14 to 1.0.15
@@ -9,14 +9,14 @@ const express = require('express'); | ||
const knex = Knex({ | ||
client: 'pg', | ||
connection: { | ||
host: '127.0.0.1', | ||
user: 'postgres', | ||
password: '', | ||
database: 'travis_ci_test' | ||
} | ||
client: 'pg', | ||
connection: { | ||
host: '127.0.0.1', | ||
user: 'postgres', | ||
password: '', | ||
database: 'travis_ci_test' | ||
} | ||
}); | ||
const store = new KnexSessionStore({ | ||
knex: knex, | ||
tablename: 'sessions' // optional. Defaults to 'sessions' | ||
knex: knex, | ||
tablename: 'sessions' // optional. Defaults to 'sessions' | ||
}); | ||
@@ -26,7 +26,7 @@ | ||
app.use(session({ | ||
secret: 'keyboard cat', | ||
cookie: { | ||
maxAge: 10000 // ten seconds, for testing | ||
}, | ||
store: store | ||
secret: 'keyboard cat', | ||
cookie: { | ||
maxAge: 10000 // ten seconds, for testing | ||
}, | ||
store: store | ||
})); | ||
@@ -37,7 +37,7 @@ | ||
app.use('/', function (req, res, next) { | ||
var n = req.session.views || 0 | ||
req.session.views = ++n | ||
res.end(n + ' views') | ||
var n = req.session.views || 0 | ||
req.session.views = ++n | ||
res.end(n + ' views') | ||
}) | ||
app.listen(3000); |
const express = require('express'); // Express 4 | ||
const app = express(); | ||
const app = express(); | ||
const session = require('express-session'); | ||
const KnexSessionStore = require('connect-session-knex')(session); | ||
const KnexSessionStore = require('./index.js')(session); | ||
const store = new KnexSessionStore(/* options here */); // defaults to a sqlite3 database | ||
app.use(session({ | ||
secret: 'keyboard cat', | ||
cookie: { | ||
maxAge: 10000 // ten seconds, for testing | ||
}, | ||
store: store | ||
secret: 'keyboard cat', | ||
cookie: { | ||
maxAge: 30000 // 2 seconds for testing | ||
}, | ||
store: store | ||
})); | ||
@@ -19,7 +19,19 @@ | ||
app.use('/', function (req, res, next) { | ||
var n = req.session.views || 0 | ||
req.session.views = ++n | ||
res.end(n + ' views') | ||
var n = req.session.views || 0 | ||
req.session.views = ++n | ||
res.end(n + ' views') | ||
}) | ||
app.listen(3000); | ||
setInterval(function () { | ||
store.length().then(function (length) { | ||
console.log('There are ' + JSON.stringify(length) + ' sessions'); | ||
}) | ||
}, 2000); | ||
setInterval(function () { | ||
store.clear().then(function (length) { | ||
console.log('Cleared ' + JSON.stringify(length) + ' sessions'); | ||
}) | ||
}, 30000); |
469
index.js
@@ -8,92 +8,97 @@ 'use strict'; | ||
/** | ||
* Connect's Store. | ||
*/ | ||
var Store = (connect.session) ? connect.session.Store : connect.Store; | ||
/** | ||
* Connect's Store. | ||
*/ | ||
var Store = (connect.session) ? connect.session.Store : connect.Store; | ||
/* | ||
* Return an ISO compliant string of the current time | ||
* @api private | ||
* @return {String} an ISO compliant string of the current time | ||
*/ | ||
function nowAsISO() { | ||
return (new Date()).toISOString(); | ||
} | ||
/* | ||
* Return an ISO compliant string of the current time | ||
* @api private | ||
* @return {String} an ISO compliant string of the current time | ||
*/ | ||
function nowAsISO() { | ||
return (new Date()).toISOString(); | ||
} | ||
/* | ||
* Return dialect-aware type name for timestamp | ||
* @return {String} type name for timestamp | ||
* @api private | ||
*/ | ||
function timestampTypeName(knex) { | ||
return (['mysql', 'mariasql', 'mariadb'].indexOf(knex.client.dialect) > -1) ? 'DATETIME' : 'timestamp'; | ||
} | ||
/* | ||
* Return dialect-aware type name for timestamp | ||
* @return {String} type name for timestamp | ||
* @api private | ||
*/ | ||
function timestampTypeName(knex) { | ||
return (['mysql', 'mariasql', 'mariadb'].indexOf(knex.client.dialect) > -1) ? 'DATETIME' : 'timestamp'; | ||
} | ||
/* | ||
* Remove expired sessions from database. | ||
* @param {Object} store | ||
* @api private | ||
*/ | ||
function dbCleanup(store) { | ||
return store.ready.then(function () { | ||
return store.knex(store.tablename).del() | ||
.whereRaw('expired < CAST(? as ' + timestampTypeName(store.knex) + ')', nowAsISO()); | ||
}); | ||
} | ||
/* | ||
* Remove expired sessions from database. | ||
* @param {Object} store | ||
* @api private | ||
*/ | ||
function dbCleanup(store) { | ||
return store.ready.then(function () { | ||
return store.knex(store.tablename).del() | ||
.whereRaw('expired < CAST(? as ' + timestampTypeName(store.knex) + ')', nowAsISO()); | ||
}); | ||
} | ||
/* | ||
* Initialize KnexStore with the given options. | ||
* | ||
* @param {Object} options | ||
* @api public | ||
*/ | ||
function KnexStore(options) { | ||
var self = this; | ||
/* | ||
* Initialize KnexStore with the given options. | ||
* | ||
* @param {Object} options | ||
* @api public | ||
*/ | ||
function KnexStore(options) { | ||
var self = this; | ||
options = options || {}; | ||
Store.call(self, options); | ||
options = options || {}; | ||
Store.call(self, options); | ||
self.tablename = options.tablename || 'sessions'; | ||
self.knex = options.knex || require('knex')({ | ||
client: 'sqlite3', | ||
// debug: true, | ||
connection: { | ||
filename: "connect-session-knex.sqlite" | ||
if (!options.clearInterval) { | ||
// Time to run clear expired function. | ||
options.clearInterval = 60000; | ||
} | ||
}); | ||
self.ready = self.knex.schema.hasTable(self.tablename) | ||
.then(function (exists) { | ||
if (!exists) { | ||
return self.knex.schema.createTable(self.tablename, function (table) { | ||
table.string('sid').primary(); | ||
table.json('sess').notNullable(); | ||
if (['mysql', 'mariasql'].indexOf(self.knex.client.dialect) > -1) { | ||
table.dateTime('expired').notNullable(); | ||
} else { | ||
table.timestamp('expired', 'true').notNullable(); | ||
} | ||
}); | ||
} | ||
}) | ||
.then(function () { | ||
dbCleanup(self); | ||
setInterval(dbCleanup, oneDay, self).unref(); | ||
}); | ||
} | ||
self.tablename = options.tablename || 'sessions'; | ||
self.knex = options.knex || require('knex')({ | ||
client: 'sqlite3', | ||
// debug: true, | ||
connection: { | ||
filename: "connect-session-knex.sqlite" | ||
} | ||
}); | ||
// KnexStore.prototype.__proto__ = Store.prototype; | ||
util.inherits(KnexStore, Store); | ||
self.ready = self.knex.schema.hasTable(self.tablename) | ||
.then(function (exists) { | ||
if (!exists) { | ||
return self.knex.schema.createTable(self.tablename, function (table) { | ||
table.string('sid').primary(); | ||
table.json('sess').notNullable(); | ||
if (['mysql', 'mariasql'].indexOf(self.knex.client.dialect) > -1) { | ||
table.dateTime('expired').notNullable(); | ||
} else { | ||
table.timestamp('expired', 'true').notNullable(); | ||
} | ||
}); | ||
} | ||
}) | ||
.then(function () { | ||
dbCleanup(self); | ||
self._clearer = setInterval(dbCleanup, options.clearInterval, self).unref(); | ||
}); | ||
} | ||
/* | ||
* Attempt to fetch session by the given sid. | ||
* | ||
* @param {String} sid | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.get = function(sid, fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex | ||
// KnexStore.prototype.__proto__ = Store.prototype; | ||
util.inherits(KnexStore, Store); | ||
/* | ||
* Attempt to fetch session by the given sid. | ||
* | ||
* @param {String} sid | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.get = function(sid, fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex | ||
.select('sess') | ||
@@ -111,202 +116,150 @@ .from(self.tablename) | ||
} | ||
if (fn) fn(null, ret); | ||
return ret; | ||
}).catch(function(err) { | ||
if (fn) fn(err); | ||
throw err; | ||
}); | ||
}); | ||
}; | ||
}) | ||
.asCallback(fn) | ||
}); | ||
}; | ||
/* | ||
* Commit the given `sess` object associated with the given `sid`. | ||
* | ||
* @param {String} sid | ||
* @param {Session} sess | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.set = function(sid, sess, fn) { | ||
var self = this; | ||
var maxAge = sess.cookie.maxAge; | ||
var now = new Date().getTime(); | ||
var expired = maxAge ? now + maxAge : now + oneDay; | ||
sess = JSON.stringify(sess); | ||
var postgresfastq = 'with new_values (sid, expired, sess) as (' + | ||
' values (?, ?::timestamp without time zone, ?::json)' + | ||
'), ' + | ||
'upsert as ' + | ||
'( ' + | ||
' update ' + self.tablename + ' cs set ' + | ||
' sid = nv.sid, ' + | ||
' expired = nv.expired, ' + | ||
' sess = nv.sess ' + | ||
' from new_values nv ' + | ||
' where cs.sid = nv.sid ' + | ||
' returning cs.* ' + | ||
')' + | ||
'insert into ' + self.tablename + ' (sid, expired, sess) ' + | ||
'select sid, expired, sess ' + | ||
'from new_values ' + | ||
'where not exists (select 1 from upsert up where up.sid = new_values.sid)'; | ||
/* | ||
* Commit the given `sess` object associated with the given `sid`. | ||
* | ||
* @param {String} sid | ||
* @param {Session} sess | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.set = function(sid, sess, fn) { | ||
var self = this; | ||
var maxAge = sess.cookie.maxAge; | ||
var now = new Date().getTime(); | ||
var expired = maxAge ? now + maxAge : now + oneDay; | ||
sess = JSON.stringify(sess); | ||
var postgresfastq = 'with new_values (sid, expired, sess) as (' + | ||
' values (?, ?::timestamp with time zone, ?::json)' + | ||
'), ' + | ||
'upsert as ' + | ||
'( ' + | ||
' update ' + self.tablename + ' cs set ' + | ||
' sid = nv.sid, ' + | ||
' expired = nv.expired, ' + | ||
' sess = nv.sess ' + | ||
' from new_values nv ' + | ||
' where cs.sid = nv.sid ' + | ||
' returning cs.* ' + | ||
')' + | ||
'insert into ' + self.tablename + ' (sid, expired, sess) ' + | ||
'select sid, expired, sess ' + | ||
'from new_values ' + | ||
'where not exists (select 1 from upsert up where up.sid = new_values.sid)'; | ||
var sqlitefastq = 'insert or replace into ' + self.tablename + ' (sid, expired, sess) values (?, ?, ?);'; | ||
var sqlitefastq = 'insert or replace into ' + self.tablename + ' (sid, expired, sess) values (?, ?, ?);'; | ||
var mysqlfastq = 'insert into ' + self.tablename + ' (sid, expired, sess) values (?, ?, ?) on duplicate key update expired=values(expired), sess=values(sess);'; | ||
var mysqlfastq = 'insert into ' + self.tablename + ' (sid, expired, sess) values (?, ?, ?) on duplicate key update expired=values(expired), sess=values(sess);'; | ||
if (self.knex.client.dialect === 'sqlite3') { | ||
// sqlite optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(sqlitefastq, [sid, new Date(expired).toISOString(), sess ]) | ||
.then(function (result) { | ||
if (fn && result instanceof Array) { | ||
fn(null, [1]); | ||
} | ||
if (result instanceof Array) { | ||
if (self.knex.client.dialect === 'sqlite3') { | ||
// sqlite optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(sqlitefastq, [sid, new Date(expired).toISOString(), sess ]) | ||
.then(function (result) { | ||
return [1]; | ||
} | ||
}) | ||
.catch(function (err) { | ||
fn(err); | ||
throw err; | ||
}) | ||
.asCallback(fn); | ||
}); | ||
}); | ||
} else if (self.knex.client.dialect === 'postgresql' && parseFloat(self.knex.client.version) >= 9.2) { | ||
// postgresql optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(postgresfastq, [sid, new Date(expired).toISOString(), sess ]) | ||
.then(function (result) { | ||
if (fn) fn(null, result); | ||
return result; | ||
}) | ||
.catch(function (err) { | ||
fn(err); | ||
throw err; | ||
} else if (self.knex.client.dialect === 'postgresql' && parseFloat(self.knex.client.version) >= 9.2) { | ||
// postgresql optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(postgresfastq, [sid, new Date(expired).toISOString(), sess ]) | ||
.asCallback(fn); | ||
}); | ||
}); | ||
} else if (['mysql', 'mariasql'].indexOf(self.knex.client.dialect) > -1) { | ||
// mysql/mariaDB optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(mysqlfastq, [sid, new Date(expired).toISOString().slice(0, 19).replace('T', ' '), sess ]) | ||
.then(function (result) { | ||
if (fn) fn(null, result); | ||
return result; | ||
}) | ||
.catch(function (err) { | ||
fn(err); | ||
throw err; | ||
} else if (['mysql', 'mariasql'].indexOf(self.knex.client.dialect) > -1) { | ||
// mysql/mariaDB optimized query | ||
return self.ready.then(function () { | ||
return self.knex.raw(mysqlfastq, [sid, new Date(expired).toISOString().slice(0, 19).replace('T', ' '), sess ]) | ||
.asCallback(fn); | ||
}); | ||
}); | ||
} else { | ||
return self.ready.then(function () { | ||
return self.knex.transaction(function (trx) { | ||
return trx.select('*') | ||
.forUpdate() | ||
.from(self.tablename) | ||
.where('sid', '=', sid) | ||
.then(function (foundKeys) { | ||
if (foundKeys.length === 0) { | ||
return trx.from(self.tablename) | ||
.insert({ | ||
sid: sid, | ||
expired: new Date(expired).toISOString(), | ||
sess: sess | ||
}); | ||
} else { | ||
return trx(self.tablename) | ||
.where('sid', '=', sid) | ||
.update({ | ||
expired: new Date(expired).toISOString(), | ||
sess: sess | ||
}); | ||
} | ||
}); | ||
}) | ||
.then(function (res) { | ||
if (fn) fn(null, res); | ||
return res; | ||
}) | ||
.catch(function(err) { | ||
if (fn) fn(err); | ||
throw err; | ||
} else { | ||
return self.ready.then(function () { | ||
return self.knex.transaction(function (trx) { | ||
return trx.select('*') | ||
.forUpdate() | ||
.from(self.tablename) | ||
.where('sid', '=', sid) | ||
.then(function (foundKeys) { | ||
if (foundKeys.length === 0) { | ||
return trx.from(self.tablename) | ||
.insert({ | ||
sid: sid, | ||
expired: new Date(expired).toISOString(), | ||
sess: sess | ||
}); | ||
} else { | ||
return trx(self.tablename) | ||
.where('sid', '=', sid) | ||
.update({ | ||
expired: new Date(expired).toISOString(), | ||
sess: sess | ||
}); | ||
} | ||
}); | ||
}) | ||
.asCallback(fn) | ||
}); | ||
}); | ||
} | ||
}; | ||
} | ||
}; | ||
/* | ||
* Destroy the session associated with the given `sid`. | ||
* | ||
* @param {String} sid | ||
* @api public | ||
*/ | ||
KnexStore.prototype.destroy = function(sid, fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.del() | ||
.from(self.tablename) | ||
.where('sid', '=', sid) | ||
.then(function (res) { | ||
if (fn) fn(null, res); | ||
return res; | ||
}) | ||
.catch(function(err) { | ||
if (fn) fn(err); | ||
throw err; | ||
/* | ||
* Destroy the session associated with the given `sid`. | ||
* | ||
* @param {String} sid | ||
* @api public | ||
*/ | ||
KnexStore.prototype.destroy = function(sid, fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.del() | ||
.from(self.tablename) | ||
.where('sid', '=', sid) | ||
.asCallback(fn) | ||
}); | ||
}); | ||
}; | ||
}; | ||
/* | ||
* Fetch number of sessions. | ||
* | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.length = function(fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.count('sid as count') | ||
.from(self.tablename) | ||
.then(function (response) { | ||
var ret = response[0].count | 0; | ||
if (fn) fn(null, ret); | ||
return ret; | ||
/* | ||
* Fetch number of sessions. | ||
* | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.length = function(fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.count('sid as count') | ||
.from(self.tablename) | ||
.then(function (response) { | ||
return response[0].count | 0; | ||
}) | ||
.asCallback(fn) | ||
}) | ||
.catch(function(err) { | ||
fn(err); | ||
throw err; | ||
}); | ||
}); | ||
}; | ||
}; | ||
/* | ||
* Clear all sessions. | ||
* | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.clear = function(fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.del() | ||
.from(self.tablename) | ||
.then(function (res) { | ||
if (fn) fn(null, res); | ||
return res; | ||
}) | ||
.catch(function(err) { | ||
fn(err); | ||
throw err; | ||
/* | ||
* Clear all sessions. | ||
* | ||
* @param {Function} fn | ||
* @api public | ||
*/ | ||
KnexStore.prototype.clear = function(fn) { | ||
var self = this; | ||
return self.ready.then(function () { | ||
return self.knex.del() | ||
.from(self.tablename) | ||
.asCallback(fn) | ||
}); | ||
}); | ||
}; | ||
}; | ||
return KnexStore; | ||
return KnexStore; | ||
}; |
{ | ||
"name": "connect-session-knex", | ||
"description": "A knex.js session store for Express and Connect", | ||
"version": "1.0.14", | ||
"version": "1.0.15", | ||
"main": "index.js", | ||
@@ -22,10 +22,11 @@ "engines": { | ||
"devDependencies": { | ||
"bluebird": "^2.9.25", | ||
"express-session": "^1.10.2", | ||
"knex": "^0.8.3", | ||
"mysql": "^2.5.4", | ||
"pg": "^4.2.0", | ||
"sqlite3": "^3.0.7", | ||
"tape": "^4.0.0" | ||
"bluebird": "^2.10.0", | ||
"express": "^4.13.3", | ||
"express-session": "^1.11.3", | ||
"knex": "^0.8.6", | ||
"mysql": "^2.9.0", | ||
"pg": "^4.4.1", | ||
"sqlite3": "^3.0.10", | ||
"tape": "^4.2.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16276
8
10
419