neo4jmapper src/cypherquery.js

    Source

    if (typeof window === 'object') {
      var _ = window._;
      var helpers = window.Neo4jMapper.helpers;
    } else {
      var _ = require('underscore');
      var helpers = require('./helpers');
    }
    
    var CypherQuery = function CypherQuery(query, parameters) {
      this.statements = [];
      if (typeof query === 'string')
        this.query = query;
      else if (typeof query === 'object')
        this.statements = query;
      if (parameters)
        this.parameters = parameters;
      this.cypher = _.extend(CypherQuery.prototype.cypher);
    }
    
    CypherQuery.prototype.statementsToString = function(options) {
      var s = '';
      var chopLength = 15;
      var defaultOptions = {
        niceFormat: true
      };
      if (this.statements) {
        if (typeof options !== 'object')
          options = {};
        else
          _.defaults(options, defaultOptions);
        for (var i=0; i < this.statements.length; i++) {
          var queryFragment = this.statements[i];
          if (typeof queryFragment === 'string') {
            // if we have just a string, we add the string to final query, no manipulation
            s += queryFragment;
            continue;
          }
          var attribute = Object.keys(this.statements[i])[0];
          if ((typeof queryFragment === 'object') && (typeof queryFragment.toQueryString === 'function')) {
            queryFragment = queryFragment.toQueryString();
            s += queryFragment;
            continue;
          }
          var forQuery = this.statements[i][attribute];
          // do we have an object with a .toQueryString() method?
    
          // remove underscore from attribute, e.g. ORDER_BY -> ORDER BY
          attribute = attribute.replace(/([A-Z]{1})\_([A-Z]{1})/g, '$1 $2');
          if (options.niceFormat) {
            // extend attribute-string with whitespace
            attribute = attribute + Array(chopLength - attribute.length).join(' ');
          }
          if (forQuery !== null) {
            if (typeof forQuery === 'string') {
              // remove dupliacted statement fragment identifier, e.g. START START … -> START …
              forQuery = forQuery.trim().replace(new RegExp('^'+attribute+'\\s+', 'i'), '');
              // remove trailing semicolon
              forQuery = forQuery.replace(/\;$/, '');
            } else {
              forQuery = String(forQuery);
            }
            s += '\n'+attribute+' '+forQuery+' ';
          }
        }
        s = s.trim().replace(/;+$/,'');
      }
      return s + ';';
    }
    
    CypherQuery.prototype.query = '';         // the cypher query string
    CypherQuery.prototype.parameters = null;
    CypherQuery.prototype.statements = null;
    CypherQuery.prototype.cypher = {};
    CypherQuery.prototype.useParameters = true;
    
    CypherQuery.prototype.hasParameters = function() {
      return ((this.parameters) && (typeof this.parameters === 'object') && (Object.keys(this.parameters).length > 0));
    }
    
    CypherQuery.prototype.toCypher = function(options) {
      var s = '';
      if (this.query)
        s = this.query;
      else if (this.statements.length > 0)
        s = this.statementsToString(options);
      return s;
    }
    
    CypherQuery.prototype.toString = function(options) {
      var s = this.toCypher(options);
      if ((s)&&(this.hasParameters())) {
        // replace identifiers with values to present a good equivalent
        for (var key in this.parameters) {
          var value = this.parameters[key];
          // TODO: better check that we detect placeholders
          s = s.replace('{'+key+'}', helpers.valueToStringForCypherQuery(value, "'"));
        };
      }
      return s;
    }
    
    CypherQuery.prototype.addParameters = function(parameters) {
      if (typeof parameters !== 'object')
        throw Error('parameter(s) as argument must be an object, e.g. { key: "value" }')
      if (this.useParameters === null)
        this.useParameters = true;
      // reset parameters
      if ((!this.hasParameters()) || ((parameters !== null) && (Object.keys(parameters).length === 0)))
        this.parameters = {};
      for (var attr in parameters) {
        // replace undefined values with null because we can't work with undefined values in neo4j
        this.parameters[attr] = (parameters[attr] === undefined) ? null : parameters[attr];
      }
      return this;
    }
    
    CypherQuery.prototype.addParameter = CypherQuery.prototype.addParameters;
    
    if (typeof window === 'object') {
      window.Neo4jMapper.CypherQuery = CypherQuery;
    } else {
      module.exports = exports = CypherQuery;
    }