wbyoung/azul-tracker

View on GitHub
index.js

Summary

Maintainability
A
2 hrs
Test Coverage
'use strict';

var _ = require('lodash');
var chalk = require('chalk');

/**
 * Setup the BaseQuery class.
 *
 * @param {Class} BaseQuery
 * @param {Object} globalOptions
 */
var setup = function(BaseQuery, globalOptions) {
  BaseQuery.reopen({
    track: function(options) {
      var stack = new Error().stack.split('\n').slice(1);
      var opts = _.defaults({}, globalOptions, options, {
        fullTrace: false,
        log: console.log,
      });
      var log = opts.log;

      this.on('dup', this.pin);
      this.on('spawn', this.pin);
      this.on('execute', this.pin);
      this.on('dup', function(q) { q.track(options); });
      this.on('spawn', function(q) { q.track(options); });

      clearImmediate(this._tracker);

      this._tracker = setImmediate(function() {
        var message = chalk.red('Unexecuted Query: ');
        var sql;
        try { sql = this.sql; }
        catch (e) {
          message = chalk.red('Unexecuted Invalid Query: ');
          sql = chalk.yellow(e.message);
        }
        var filter = function(line) {
          return !opts.fullTrace &&
            line.match(/azul-tracker\/index|(azul|corazon)\/lib|\(events.js:\d+:\d+\)/);
        };
        var filteredStack = _.dropWhile(stack, filter).join('\n');

        log(message + chalk.cyan('%s\n') + chalk.gray('%s'),
          sql, filteredStack);
      }.bind(this));

      return this;
    },

    pin: function() {
      clearImmediate(this._tracker);
      return this;
    }
  });
};

/**
 * Get the BaseQuery class from a query instance.
 *
 * @param {BaseQuery} query
 * @return {Class}
 */
var baseQueryClass = function(query) {
  var classes = [];
  var cls = query.__identity__;
  while (cls) {
    classes.push(cls);
    cls = cls.__super__;
  }
  return classes.splice(-2)[0];
};

/**
 * Enabling tracking for an Azul.js query & all derived queries.
 *
 * @param {Query} query
 * @param {Object} options
 * @param {Boolean} options.start
 * @param {Boolean} options.fullTrace Enable full backtraces which will allow
 * tracking down potentially unexecuted queries from within Azul.js.
 * @param {Function} options.log A logging function which defaults to
 * console.log.
 */
module.exports = function(query, options) {
  var env = process.env.NODE_ENV || 'development';
  var opts = _.defaults({}, options, {
    start: (env === 'development' || env === 'test')
  });
  if (!query.track) {
    setup(baseQueryClass(query), options);
  }
  if (opts.start) {
    query.track(options);
  }
};