/* mysql-live-select, MIT License ben@latenightsketches.com, wj32.64@gmail.com
   lib/QueryCache.js - Query results cache class

   Many LiveMysqlSelect objects can share the same query cache if they have the
   same query string.
*/

var _ = require('lodash');
var differ = require('./differ');
var LiveMysqlKeySelector = require('./LiveMysqlKeySelector');

function QueryCache(query, values, queryCacheKey, keySelector, base) {
  if (!query)
    throw new Error('query required');
  if (!(keySelector instanceof Function))
    throw new Error('keySelector required');

  var self = this;
  self.base = base;
  self.query = query;
  self.values = values;
  self.queryCacheKey = queryCacheKey;
  self.needUpdate = false;
  self.updating = false;
  self.lastUpdate = 0;
  self.data = {};
  self.selects = [];
  self.initialized = false;
  self.updateTimeout = null;
  self.keyFunc = LiveMysqlKeySelector.toKeyFunc(keySelector);
}

QueryCache.prototype.setData = function(data) {
  var self = this;
  self.data = data;
  for (var i = 0; i < self.selects.length; i++) {
    self.selects[i].data = self.data;
  }
};

QueryCache.prototype._emitOnSelects = function(/* arguments */) {
  var self = this;
  for (var i = 0; i < self.selects.length; i++) {
    var select = self.selects[i];
    select.emit.apply(select, arguments);
  }
};

QueryCache.prototype.matchRowEvent = function(event) {
  var self = this;
  for (var i = 0; i < self.selects.length; i++) {
    if (self.selects[i].matchRowEvent(event))
      return true;
  }
  return false;
};

QueryCache.prototype.invalidate = function() {
  var self = this;

  function update() {
    // Refuse to send more than one query out at a time. Note that the code
    // below always sets needUpdate to false; when the current query finishes
    // running we will check needUpdate again and re-run the query if necessary.
    if (self.updating) {
      self.needUpdate = true;
      return;
    }

    self.updating = true;
    self.needUpdate = false;

    // Perform the update
    self.base.possiblyPooledQuery(self.query, self.values, function(error, rows) {
      self.updating = false;

      if (error)
        return self._emitOnSelects('error', error);

      var newData = {};
      rows.forEach(function(row, index) {
        newData[self.keyFunc(row, index)] = row;
      });

      if (rows.length === 0 && self.initialized === false) {
        // If the result set initializes to 0 rows, it still needs to output an
        // update event.
        self._emitOnSelects('update',
          { added: {}, changed: null, removed: null },
          {});
      } else {
        // Perform a diff and notify the select objects.
        var diff = differ.makeDiff(self.data, newData);
        self._emitOnSelects('update', diff, newData);
      }

      self.setData(newData);

      self.initialized = true;
      self.lastUpdate = Date.now();

      if (self.needUpdate === true) update();
    });
  }

  if (typeof self.base.settings.minInterval !== 'number') {
    update();
  } else if (self.lastUpdate + self.base.settings.minInterval < Date.now()) {
    update();
  } else { // Before minInterval
    if (self.updateTimeout === null) {
      self.updateTimeout = setTimeout(function() {
        self.updateTimeout = null;
        update();
      }, self.lastUpdate + self.base.settings.minInterval - Date.now());
    }
  }
};

module.exports = QueryCache;

@@ -1631,243 +1631,8 @@
 ) %7B%0A
-    // Refuse to send more than one query out at a time. Note that the code%0A    // below always sets needUpdate to false; when the current query finishes%0A    // running we will check needUpdate again and re-run the query if necessary.%0A
     
@@ -1648,24 +1648,24 @@
 updating) %7B%0A
+
       self.n
@@ -1699,24 +1699,58 @@
 urn;%0A    %7D%0A%0A
+    self.lastUpdate = Date.now();%0A
     self.upd
@@ -2622,17 +2622,16 @@
 wData);%0A
-%0A
       se
@@ -2657,91 +2657,66 @@
 ue;%0A
+%0A
       
+if (
 self.
-last
+need
 Update
- = Date.now();%0A%0A      if (self.needUpdate === true) updat
+) %7B%0A        schedul
 e();%0A
+      %7D%0A
     
@@ -2724,16 +2724,42 @@
 );%0A  %7D%0A%0A
+  function schedule() %7B%0A  
   if (ty
@@ -2806,32 +2806,34 @@
 'number') %7B%0A    
+  
 update();%0A  %7D el
@@ -2824,24 +2824,26 @@
 update();%0A  
+ 
+ 
 %7D else if (s
@@ -2906,24 +2906,26 @@
 ow()) %7B%0A    
+  
 update();%0A  
@@ -2924,16 +2924,18 @@
 te();%0A  
+ 
+ 
 %7D else %7B
@@ -2957,16 +2957,18 @@
 nterval%0A
+  
     if (
@@ -2994,24 +2994,26 @@
 === null) %7B%0A
+  
       self.u
@@ -3051,32 +3051,34 @@
 ion() %7B%0A        
+  
 self.updateTimeo
@@ -3088,16 +3088,18 @@
 = null;%0A
+  
         
@@ -3114,16 +3114,18 @@
 ;%0A      
+  
 %7D, self.
@@ -3191,13 +3191,36 @@
     
+  
 %7D%0A  
+ 
-%7D
+ %7D%0A  %7D%0A%0A  schedule();
 %0A%7D;%0A

Fix invalidation scheduling logic