mysql-live-select
Advanced tools
Comparing version 0.0.23 to 0.0.24
@@ -10,2 +10,3 @@ /* mysql-live-select, MIT License ben@latenightsketches.com | ||
var LiveMysqlSelect = require('./LiveMysqlSelect'); | ||
var QueryCache = require('./QueryCache'); | ||
@@ -20,4 +21,3 @@ function LiveMysql(settings, callback){ | ||
self._select = []; | ||
// Cache query results for any new, duplicate SELECT statements | ||
self._resultsBuffer = {}; | ||
self._queryCache = {}; | ||
self._schemaCache = {}; | ||
@@ -39,34 +39,14 @@ | ||
if(event.getEventName() === 'tablemap') return; | ||
if(self._select.length === 0) return; | ||
// Cache query results within this update event | ||
var eventResults = {}; | ||
// Update each select statement if matches event | ||
function _nextSelect(index){ | ||
var select; | ||
if(index < self._select.length){ | ||
select = self._select[index]; | ||
if(select.matchRowEvent(event)){ | ||
if(select.query in eventResults){ | ||
select._setRows(eventResults[select.query]); | ||
_nextSelect(index + 1); | ||
}else{ | ||
select.update(function(error, rows){ | ||
if(error === undefined){ | ||
eventResults[select.query] = rows; | ||
} | ||
_nextSelect(index + 1); | ||
}); | ||
} | ||
}else{ | ||
_nextSelect(index + 1); | ||
} | ||
for(var query in self._queryCache){ | ||
if (!self._queryCache.hasOwnProperty(query)){ | ||
continue; | ||
} | ||
var queryCache = self._queryCache[query]; | ||
if(!queryCache.canSkipRowEvent() && queryCache.matchRowEvent(event)){ | ||
queryCache.invalidate(); | ||
} | ||
} | ||
}) | ||
_nextSelect(0); | ||
}); | ||
// Wait for Zongji to be ready before executing callback | ||
@@ -113,4 +93,14 @@ var zongjiInitTime = Date.now(); | ||
} | ||
query = self._escapeQueryFun(query); | ||
var queryCache; | ||
if(self._queryCache.hasOwnProperty(query)){ | ||
queryCache = self._queryCache[query]; | ||
}else{ | ||
queryCache = new QueryCache(query, this); | ||
self._queryCache[query] = queryCache; | ||
} | ||
var newSelect = new LiveMysqlSelect(query, triggers, this); | ||
var newSelect = new LiveMysqlSelect(queryCache, triggers, this); | ||
self._select.push(newSelect); | ||
@@ -120,2 +110,36 @@ return newSelect; | ||
LiveMysql.prototype._escapeQueryFun = function(query){ | ||
var self = this; | ||
if(typeof query === 'function'){ | ||
var escId = self.db.escapeId; | ||
var esc = self.db.escape.bind(self.db); | ||
return query(esc, escId); | ||
} | ||
return query; | ||
}; | ||
LiveMysql.prototype._removeSelect = function(select){ | ||
var self = this; | ||
var index = self._select.indexOf(select); | ||
if(index !== -1){ | ||
// Remove the select object from our list | ||
self._select.splice(index, 1); | ||
var queryCache = select.queryCache; | ||
var queryCacheIndex = queryCache.selects.indexOf(select); | ||
if(queryCacheIndex !== -1){ | ||
// Remove the select object from the query cache's list and remove the | ||
// query cache if no select objects are using it. | ||
queryCache.selects.splice(queryCacheIndex, 1); | ||
if(queryCache.selects.length === 0){ | ||
delete self._queryCache[queryCache.query]; | ||
} | ||
} | ||
return true; | ||
}else{ | ||
return false; | ||
} | ||
} | ||
LiveMysql.prototype.pause = function(){ | ||
@@ -133,5 +157,8 @@ var self = this; | ||
// Update all select statements | ||
self._select.forEach(function(select) { | ||
select.update(); | ||
}); | ||
for(var query in self._queryCache){ | ||
if (!self._queryCache.hasOwnProperty(query)){ | ||
continue; | ||
} | ||
self._queryCache[query].invalidate(); | ||
} | ||
}; | ||
@@ -138,0 +165,0 @@ |
@@ -6,5 +6,5 @@ /* mysql-live-select, MIT License ben@latenightsketches.com | ||
function LiveMysqlSelect(query, triggers, base){ | ||
if(!query) | ||
throw new Error('query required'); | ||
function LiveMysqlSelect(queryCache, triggers, base){ | ||
if(!queryCache) | ||
throw new Error('queryCache required'); | ||
if(!(triggers instanceof Array)) | ||
@@ -19,13 +19,35 @@ throw new Error('triggers array required'); | ||
self.base = base; | ||
self.lastUpdate = 0; | ||
self.query = self._escapeQueryFun(query); | ||
self.data = []; | ||
self.initialized = false; | ||
self.queryCache = queryCache; | ||
queryCache.selects.push(self); | ||
if(self.query in base._resultsBuffer){ | ||
setTimeout(function(){ | ||
self._setRows(base._resultsBuffer[self.query]); | ||
}, 1); | ||
if(queryCache.initialized){ | ||
var refLastUpdate = queryCache.lastUpdate; | ||
// Trigger events for existing data | ||
setTimeout(function() { | ||
if(queryCache.lastUpdate !== refLastUpdate){ | ||
// Query cache has been updated since this select object was created; | ||
// our data would've been updated already. | ||
return; | ||
} | ||
self.emit('update', queryCache.data); | ||
if(queryCache.data.length !== 0 && !self.base.settings.skipDiff){ | ||
var diff = queryCache.data.map(function(row, index) { | ||
return [ 'added', row, index ]; | ||
}); | ||
diff.forEach(function(evt){ | ||
self.emit.apply(self, evt); | ||
// New row added to end | ||
self.data[evt[2]] = evt[1]; | ||
}); | ||
// Output all difference events in a single event | ||
self.emit('diff', diff); | ||
} | ||
}, 50); | ||
}else{ | ||
self.update(); | ||
queryCache.invalidate(); | ||
} | ||
@@ -36,12 +58,2 @@ } | ||
LiveMysqlSelect.prototype._escapeQueryFun = function(query){ | ||
var self = this; | ||
if(typeof query === 'function'){ | ||
var escId = self.base.db.escapeId; | ||
var esc = self.base.db.escape.bind(self.base.db); | ||
return query(esc, escId); | ||
} | ||
return query; | ||
}; | ||
LiveMysqlSelect.prototype.matchRowEvent = function(event){ | ||
@@ -78,110 +90,5 @@ var self = this; | ||
LiveMysqlSelect.prototype._setRows = function(rows){ | ||
var self = this; | ||
var diff = []; | ||
// Determine what changes before updating cache in order to | ||
// be able to skip all event emissions if no change | ||
// TODO update this algorithm to use less data | ||
rows.forEach(function(row, index){ | ||
if(self.data.length - 1 < index){ | ||
diff.push([ 'added', row, index ]); | ||
}else if(JSON.stringify(self.data[index]) !== JSON.stringify(row)){ | ||
diff.push([ 'changed', self.data[index], row, index ]); | ||
} | ||
}); | ||
if(self.data.length > rows.length){ | ||
for(var i = self.data.length - 1; i >= rows.length; i--){ | ||
diff.push([ 'removed', self.data[i], i ]); | ||
} | ||
} | ||
if(diff.length !== 0){ | ||
self.emit('update', rows); | ||
diff.forEach(function(evt){ | ||
if(!self.base.settings.skipDiff){ | ||
self.emit.apply(self, evt); | ||
} | ||
switch(evt[0]){ | ||
case 'added': | ||
// New row added to end | ||
self.data[evt[2]] = evt[1]; | ||
break; | ||
case 'changed': | ||
// Update row data reference | ||
self.data[evt[3]] = evt[2]; | ||
break; | ||
case 'removed': | ||
// Remove extra rows off the end | ||
self.data.splice(evt[2], 1); | ||
break; | ||
} | ||
}); | ||
if(!self.base.settings.skipDiff){ | ||
// Output all difference events in a single event | ||
self.emit('diff', diff); | ||
} | ||
}else if(self.initialized === false){ | ||
// If the result set initializes to 0 rows, it still needs to output an | ||
// update event. | ||
self.emit('update', rows); | ||
} | ||
self.initialized = true; | ||
self.lastUpdate = Date.now(); | ||
}; | ||
LiveMysqlSelect.prototype.update = function(callback){ | ||
var self = this; | ||
function _update(){ | ||
self.base.db.query(self.query, function(error, rows){ | ||
if(error){ | ||
self.emit('error', error); | ||
callback && callback.call(self, error); | ||
}else{ | ||
self.base._resultsBuffer[self.query] = rows; | ||
self._setRows(rows); | ||
callback && callback.call(self, undefined, rows); | ||
} | ||
}); | ||
} | ||
if(self.base.settings.minInterval === undefined){ | ||
_update(); | ||
}else if(self.lastUpdate + self.base.settings.minInterval < Date.now()){ | ||
_update(); | ||
}else{ // Before minInterval | ||
if(!self._updateTimeout){ | ||
self._updateTimeout = setTimeout(function(){ | ||
delete self._updateTimeout; | ||
_update(); | ||
}, self.lastUpdate + self.base.settings.minInterval - Date.now()); | ||
} | ||
} | ||
}; | ||
LiveMysqlSelect.prototype.stop = function(){ | ||
var self = this; | ||
var index = self.base._select.indexOf(self); | ||
if(index !== -1){ | ||
self.base._select.splice(index, 1); | ||
// If no other instance of the same query string, remove the resultsBuffer | ||
var sameCount = self.base._select.filter(function(select) { | ||
return select.query === self.query; | ||
}).length; | ||
if(sameCount === 0) { | ||
delete self.base._resultsBuffer[self.query]; | ||
} | ||
return true; | ||
}else{ | ||
return false; | ||
} | ||
return self.base._removeSelect(self); | ||
}; | ||
@@ -188,0 +95,0 @@ |
{ | ||
"name": "mysql-live-select", | ||
"version": "0.0.23", | ||
"version": "0.0.24", | ||
"description": "Live updating MySQL SELECT statements", | ||
@@ -20,3 +20,3 @@ "main": "lib/LiveMysql.js", | ||
"dependencies": { | ||
"mysql": "^2.6.1", | ||
"mysql": "^2.8.0", | ||
"zongji": "^0.3.2" | ||
@@ -23,0 +23,0 @@ }, |
@@ -268,3 +268,4 @@ /* mysql-live-select, MIT License ben@latenightsketches.com | ||
// When all instances of query removed, resultsBuffer removed too | ||
test.equal(typeof conn._resultsBuffer[query], 'undefined'); | ||
// TODO: Update for queryCache | ||
test.equal(typeof conn._queryCache[query], 'undefined'); | ||
@@ -271,0 +272,0 @@ test.ok(!this.active()); |
Sorry, the diff of this file is not supported yet
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
41815
19
818
Updatedmysql@^2.8.0