description and source-codeconnect-pg-simple = function (session) {
var Store = session.Store || session.session.Store,
PGStore;
PGStore = function (options) {
options = options || {};
Store.call(this, options);
this.schemaName = options.schemaName || null;
this.tableName = options.tableName || 'session';
this.conString = options.conString || process.env.DATABASE_URL;
this.ttl = options.ttl;
this.pg = options.pg || require('pg');
this.ownsPg = !options.pg;
this.errorLog = options.errorLog || console.error.bind(console);
if (options.pruneSessionInterval === false) {
this.pruneSessionInterval = false;
} else {
this.pruneSessionInterval = (options.pruneSessionInterval || 60) * 1000;
setImmediate(function () {
this.pruneSessions();
}.bind(this));
}
};
util.inherits(PGStore, Store);
/**
* Closes the session store
*
* Currently only stops the automatic pruning, if any, from continuing
*
* @access public
*/
PGStore.prototype.close = function () {
this.closed = true;
if (this.pruneTimer) {
clearTimeout(this.pruneTimer);
this.pruneTimer = undefined;
}
if (this.ownsPg) {
this.pg.end();
}
};
/**
* Does garbage collection for expired session in the database
*
* @param {Function} [fn] - standard Node.js callback called on completion
* @access public
*/
PGStore.prototype.pruneSessions = function (fn) {
this.query('DELETE FROM ' + this.quotedTable() + ' WHERE expire < to_timestamp($1)', [currentTimestamp()], function (err) {
if (fn && typeof fn === 'function') {
return fn(err);
}
if (err) {
this.errorLog('Failed to prune sessions:', err.message);
}
if (this.pruneSessionInterval && !this.closed) {
if (this.pruneTimer) {
clearTimeout(this.pruneTimer);
}
this.pruneTimer = setTimeout(this.pruneSessions.bind(this, true), this.pruneSessionInterval);
}
}.bind(this));
};
/**
* Get the quoted table.
*
* @return {String} the quoted schema + table for use in queries
* @access private
*/
PGStore.prototype.quotedTable = function () {
var result = '"' + this.tableName + '"';
if (this.schemaName) {
result = '"' + this.schemaName + '".' + result;
}
return result;
};
/**
* Figure out when a session should expire
*
* @param {Number} [maxAge] - the maximum age of the session cookie
* @return {Number} the unix timestamp, in seconds
* @access private
*/
PGStore.prototype.getExpireTime = function (maxAge) {
var ttl = this.ttl;
ttl = ttl || (typeof maxAge === 'number' ? maxAge / 1000 : oneDay);
ttl = Math.ceil(ttl + currentTimestamp());
return ttl;
};
/**
* Query the database.
*
* @param {String} query - the database query to perform
* @param {(Array|Function)} [params] - the parameters of the query or the callback function
* @param {Function} [fn] - standard Node.js callback returning the resulting rows
* @access private
*/
PGStore.prototype.query = function (query, params, fn) {
if (!fn && typeof params === 'function') {
fn = params;
params = [];
}
this.pg.connect(this.conString, function (err, client, done) {
if (err) {
done(client);
if (fn) { fn(err); }
} else {
client.query(query, params || [], function (err, result) {
done(err || false);
if (fn) { fn(err, result && result.rows[0] ? result.rows[0] : false); }
});
}
});
};
/**
* Attempt to fetch session by the given `sid`.
*
* @param {String} sid – the session id
* @param {Function} fn – a standard Node.js callback returning the parsed session object
* @access public
*/
PGStore.prototype.get = function (sid, fn) {
this.query('SELECT sess FROM ' + this.quotedTable() + ' WHERE sid = $1 AND expire >= to_timestamp($2)', [sid, currentTimestamp
()], function (err, data) {
if (err) { return ...