docs: function (expr, key, op) {
              /*jshint loopfunc:true*/
              var pairs = [], opts, newKey;
              var twoArityOperators = this.TWO_ARITY_OPERATORS;
              for (var k in expr) {
                  var v = expr[k];
                  if (isHash(v)) { //its a hash too filter it too!
                      pairs.push(this.__filterObject(v, k, op));
                  } else if (key && (twoArityOperators[k.toUpperCase()] || k.match(/between/i))) {
                      //its a two arrity operator (e.g. '=', '>')
                      newKey = isString(key) ? key.split(",") : [key];
                      if (newKey.length > 1) {
                          //this represents a hash where the key represents two columns
                          //(e.g. {"col1,col2" : 1}) => WHERE (col1 = 1 AND col2 = 1)
                          pairs = pairs.concat(newKey.map(function (k) {
                              //filter each column with the expression
                              return this.__filterObject(expr, k, op);
                          }, this));
                      } else {
                          newKey = [sql.stringToIdentifier(newKey[0])];
                          if (k.match(/^like$/)) {
                              //its a like clause {col : {like : "hello"}}
  
                              pairs.push(StringExpression.like.apply(StringExpression, (newKey.concat(isArray(v) ? v : [v]))));
                          } else if (k.match(/^iLike$/)) {
                              //its a like clause {col : {iLike : "hello"}}
                              pairs.push(StringExpression.like.apply(StringExpression, (newKey.concat(isArray(v) ? v : [v]).concat({caseInsensitive: true}))));
                          } else if (k.match(/between/i)) {
                              //its a like clause {col : {between : [1,10]}}
                              var between = sql.stringToIdentifier(newKey[0]).between(v);
                              k === "notBetween" && (between = between.not());
                              pairs.push(between);
                          } else {
                              //otherwise is just a boolean expressio
                              //it its not a valid operator then we
                              //BooleanExpression with throw an error
                              pairs.push(new BooleanExpression(k, newKey[0], v));
                          }
                      }
                  } else {
                      //we're not a twoarity operator
                      //so we create a boolean expression out of it
                      newKey = k.split(",");
                      if (newKey.length === 1) {
                          newKey = sql.stringToIdentifier(newKey[0]);
                      }
                      opts = [
                          [newKey, v]
                      ];
                      pairs.push(BooleanExpression.fromValuePairs(opts));
                  }
              }
              //if the total of pairs is one then we just return the first element
              //otherwise we join them all with an AND
              return pairs.length === 1 ? pairs[0] : BooleanExpression.fromArgs([op || "AND"].concat(pairs));
          }