Demo for query storing

Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/vinyl-fs/lib/file-operations.js b/node_modules/vinyl-fs/lib/file-operations.js
new file mode 100644
index 0000000..b0aa31b
--- /dev/null
+++ b/node_modules/vinyl-fs/lib/file-operations.js
@@ -0,0 +1,496 @@
+'use strict';
+
+var util = require('util');
+
+var fs = require('graceful-fs');
+var assign = require('object.assign');
+var date = require('value-or-function').date;
+var Writable = require('readable-stream').Writable;
+
+var constants = require('./constants');
+
+var APPEND_MODE_REGEXP = /a/;
+
+function closeFd(propagatedErr, fd, callback) {
+  if (typeof fd !== 'number') {
+    return callback(propagatedErr);
+  }
+
+  fs.close(fd, onClosed);
+
+  function onClosed(closeErr) {
+    if (propagatedErr || closeErr) {
+      return callback(propagatedErr || closeErr);
+    }
+
+    callback();
+  }
+}
+
+function isValidUnixId(id) {
+  if (typeof id !== 'number') {
+    return false;
+  }
+
+  if (id < 0) {
+    return false;
+  }
+
+  return true;
+}
+
+function getFlags(options) {
+  var flags = !options.append ? 'w' : 'a';
+  if (!options.overwrite) {
+    flags += 'x';
+  }
+  return flags;
+}
+
+function isFatalOverwriteError(err, flags) {
+  if (!err) {
+    return false;
+  }
+
+  if (err.code === 'EEXIST' && flags[1] === 'x') {
+    // Handle scenario for file overwrite failures.
+    return false;
+  }
+
+  // Otherwise, this is a fatal error
+  return true;
+}
+
+function isFatalUnlinkError(err) {
+  if (!err || err.code === 'ENOENT') {
+    return false;
+  }
+
+  return true;
+}
+
+function getModeDiff(fsMode, vinylMode) {
+  var modeDiff = 0;
+
+  if (typeof vinylMode === 'number') {
+    modeDiff = (vinylMode ^ fsMode) & constants.MASK_MODE;
+  }
+
+  return modeDiff;
+}
+
+function getTimesDiff(fsStat, vinylStat) {
+
+  var mtime = date(vinylStat.mtime) || 0;
+  if (!mtime) {
+    return;
+  }
+
+  var atime = date(vinylStat.atime) || 0;
+  if (+mtime === +fsStat.mtime &&
+      +atime === +fsStat.atime) {
+    return;
+  }
+
+  if (!atime) {
+    atime = date(fsStat.atime) || undefined;
+  }
+
+  var timesDiff = {
+    mtime: vinylStat.mtime,
+    atime: atime,
+  };
+
+  return timesDiff;
+}
+
+function getOwnerDiff(fsStat, vinylStat) {
+  if (!isValidUnixId(vinylStat.uid) &&
+      !isValidUnixId(vinylStat.gid)) {
+    return;
+  }
+
+  if ((!isValidUnixId(fsStat.uid) && !isValidUnixId(vinylStat.uid)) ||
+      (!isValidUnixId(fsStat.gid) && !isValidUnixId(vinylStat.gid))) {
+    return;
+  }
+
+  var uid = fsStat.uid; // Default to current uid.
+  if (isValidUnixId(vinylStat.uid)) {
+    uid = vinylStat.uid;
+  }
+
+  var gid = fsStat.gid; // Default to current gid.
+  if (isValidUnixId(vinylStat.gid)) {
+    gid = vinylStat.gid;
+  }
+
+  if (uid === fsStat.uid &&
+      gid === fsStat.gid) {
+    return;
+  }
+
+  var ownerDiff = {
+    uid: uid,
+    gid: gid,
+  };
+
+  return ownerDiff;
+}
+
+function isOwner(fsStat) {
+  var hasGetuid = (typeof process.getuid === 'function');
+  var hasGeteuid = (typeof process.geteuid === 'function');
+
+  // If we don't have either, assume we don't have permissions.
+  // This should only happen on Windows.
+  // Windows basically noops fchmod and errors on futimes called on directories.
+  if (!hasGeteuid && !hasGetuid) {
+    return false;
+  }
+
+  var uid;
+  if (hasGeteuid) {
+    uid = process.geteuid();
+  } else {
+    uid = process.getuid();
+  }
+
+  if (fsStat.uid !== uid && uid !== 0) {
+    return false;
+  }
+
+  return true;
+}
+
+function reflectStat(path, file, callback) {
+  // Set file.stat to the reflect current state on disk
+  fs.stat(path, onStat);
+
+  function onStat(statErr, stat) {
+    if (statErr) {
+      return callback(statErr);
+    }
+
+    file.stat = stat;
+    callback();
+  }
+}
+
+function reflectLinkStat(path, file, callback) {
+  // Set file.stat to the reflect current state on disk
+  fs.lstat(path, onLstat);
+
+  function onLstat(lstatErr, stat) {
+    if (lstatErr) {
+      return callback(lstatErr);
+    }
+
+    file.stat = stat;
+    callback();
+  }
+}
+
+function updateMetadata(fd, file, callback) {
+
+  fs.fstat(fd, onStat);
+
+  function onStat(statErr, stat) {
+    if (statErr) {
+      return callback(statErr);
+    }
+
+    // Check if mode needs to be updated
+    var modeDiff = getModeDiff(stat.mode, file.stat.mode);
+
+    // Check if atime/mtime need to be updated
+    var timesDiff = getTimesDiff(stat, file.stat);
+
+    // Check if uid/gid need to be updated
+    var ownerDiff = getOwnerDiff(stat, file.stat);
+
+    // Set file.stat to the reflect current state on disk
+    assign(file.stat, stat);
+
+    // Nothing to do
+    if (!modeDiff && !timesDiff && !ownerDiff) {
+      return callback();
+    }
+
+    // Check access, `futimes`, `fchmod` & `fchown` only work if we own
+    // the file, or if we are effectively root (`fchown` only when root).
+    if (!isOwner(stat)) {
+      return callback();
+    }
+
+    if (modeDiff) {
+      return mode();
+    }
+    if (timesDiff) {
+      return times();
+    }
+    owner();
+
+    function mode() {
+      var mode = stat.mode ^ modeDiff;
+
+      fs.fchmod(fd, mode, onFchmod);
+
+      function onFchmod(fchmodErr) {
+        if (!fchmodErr) {
+          file.stat.mode = mode;
+        }
+        if (timesDiff) {
+          return times(fchmodErr);
+        }
+        if (ownerDiff) {
+          return owner(fchmodErr);
+        }
+        callback(fchmodErr);
+      }
+    }
+
+    function times(propagatedErr) {
+      fs.futimes(fd, timesDiff.atime, timesDiff.mtime, onFutimes);
+
+      function onFutimes(futimesErr) {
+        if (!futimesErr) {
+          file.stat.atime = timesDiff.atime;
+          file.stat.mtime = timesDiff.mtime;
+        }
+        if (ownerDiff) {
+          return owner(propagatedErr || futimesErr);
+        }
+        callback(propagatedErr || futimesErr);
+      }
+    }
+
+    function owner(propagatedErr) {
+      fs.fchown(fd, ownerDiff.uid, ownerDiff.gid, onFchown);
+
+      function onFchown(fchownErr) {
+        if (!fchownErr) {
+          file.stat.uid = ownerDiff.uid;
+          file.stat.gid = ownerDiff.gid;
+        }
+        callback(propagatedErr || fchownErr);
+      }
+    }
+  }
+}
+
+function symlink(srcPath, destPath, opts, callback) {
+  // Because fs.symlink does not allow atomic overwrite option with flags, we
+  // delete and recreate if the link already exists and overwrite is true.
+  if (opts.flags === 'w') {
+    // TODO What happens when we call unlink with windows junctions?
+    fs.unlink(destPath, onUnlink);
+  } else {
+    fs.symlink(srcPath, destPath, opts.type, onSymlink);
+  }
+
+  function onUnlink(unlinkErr) {
+    if (isFatalUnlinkError(unlinkErr)) {
+      return callback(unlinkErr);
+    }
+    fs.symlink(srcPath, destPath, opts.type, onSymlink);
+  }
+
+  function onSymlink(symlinkErr) {
+    if (isFatalOverwriteError(symlinkErr, opts.flags)) {
+      return callback(symlinkErr);
+    }
+    callback();
+  }
+}
+
+/*
+  Custom writeFile implementation because we need access to the
+  file descriptor after the write is complete.
+  Most of the implementation taken from node core.
+ */
+function writeFile(filepath, data, options, callback) {
+  if (typeof options === 'function') {
+    callback = options;
+    options = {};
+  }
+
+  if (!Buffer.isBuffer(data)) {
+    return callback(new TypeError('Data must be a Buffer'));
+  }
+
+  if (!options) {
+    options = {};
+  }
+
+  // Default the same as node
+  var mode = options.mode || constants.DEFAULT_FILE_MODE;
+  var flags = options.flags || 'w';
+  var position = APPEND_MODE_REGEXP.test(flags) ? null : 0;
+
+  fs.open(filepath, flags, mode, onOpen);
+
+  function onOpen(openErr, fd) {
+    if (openErr) {
+      return onComplete(openErr);
+    }
+
+    fs.write(fd, data, 0, data.length, position, onComplete);
+
+    function onComplete(writeErr) {
+      callback(writeErr, fd);
+    }
+  }
+}
+
+function createWriteStream(path, options, flush) {
+  return new WriteStream(path, options, flush);
+}
+
+// Taken from node core and altered to receive a flush function and simplified
+// To be used for cleanup (like updating times/mode/etc)
+function WriteStream(path, options, flush) {
+  // Not exposed so we can avoid the case where someone doesn't use `new`
+
+  if (typeof options === 'function') {
+    flush = options;
+    options = null;
+  }
+
+  options = options || {};
+
+  Writable.call(this, options);
+
+  this.flush = flush;
+  this.path = path;
+
+  this.mode = options.mode || constants.DEFAULT_FILE_MODE;
+  this.flags = options.flags || 'w';
+
+  // Used by node's `fs.WriteStream`
+  this.fd = null;
+  this.start = null;
+
+  this.open();
+
+  // Dispose on finish.
+  this.once('finish', this.close);
+}
+
+util.inherits(WriteStream, Writable);
+
+WriteStream.prototype.open = function() {
+  var self = this;
+
+  fs.open(this.path, this.flags, this.mode, onOpen);
+
+  function onOpen(openErr, fd) {
+    if (openErr) {
+      self.destroy();
+      self.emit('error', openErr);
+      return;
+    }
+
+    self.fd = fd;
+    self.emit('open', fd);
+  }
+};
+
+// Use our `end` method since it is patched for flush
+WriteStream.prototype.destroySoon = WriteStream.prototype.end;
+
+WriteStream.prototype._destroy = function(err, cb) {
+  this.close(function(err2) {
+    cb(err || err2);
+  });
+};
+
+WriteStream.prototype.close = function(cb) {
+  var that = this;
+
+  if (cb) {
+    this.once('close', cb);
+  }
+
+  if (this.closed || typeof this.fd !== 'number') {
+    if (typeof this.fd !== 'number') {
+      this.once('open', closeOnOpen);
+      return;
+    }
+
+    return process.nextTick(function() {
+      that.emit('close');
+    });
+  }
+
+  this.closed = true;
+
+  fs.close(this.fd, function(er) {
+    if (er) {
+      that.emit('error', er);
+    } else {
+      that.emit('close');
+    }
+  });
+
+  this.fd = null;
+};
+
+WriteStream.prototype._final = function(callback) {
+  if (typeof this.flush !== 'function') {
+    return callback();
+  }
+
+  this.flush(this.fd, callback);
+};
+
+function closeOnOpen() {
+  this.close();
+}
+
+WriteStream.prototype._write = function(data, encoding, callback) {
+  var self = this;
+
+  // This is from node core but I have no idea how to get code coverage on it
+  if (!Buffer.isBuffer(data)) {
+    return this.emit('error', new Error('Invalid data'));
+  }
+
+  if (typeof this.fd !== 'number') {
+    return this.once('open', onOpen);
+  }
+
+  fs.write(this.fd, data, 0, data.length, null, onWrite);
+
+  function onOpen() {
+    self._write(data, encoding, callback);
+  }
+
+  function onWrite(writeErr) {
+    if (writeErr) {
+      self.destroy();
+      callback(writeErr);
+      return;
+    }
+
+    callback();
+  }
+};
+
+module.exports = {
+  closeFd: closeFd,
+  isValidUnixId: isValidUnixId,
+  getFlags: getFlags,
+  isFatalOverwriteError: isFatalOverwriteError,
+  isFatalUnlinkError: isFatalUnlinkError,
+  getModeDiff: getModeDiff,
+  getTimesDiff: getTimesDiff,
+  getOwnerDiff: getOwnerDiff,
+  isOwner: isOwner,
+  reflectStat: reflectStat,
+  reflectLinkStat: reflectLinkStat,
+  updateMetadata: updateMetadata,
+  symlink: symlink,
+  writeFile: writeFile,
+  createWriteStream: createWriteStream,
+};