From a8eb67be6fbe805aa5012dce366f4ed6fdfaea7c Mon Sep 17 00:00:00 2001
From: Tristan Cavelier <tristan.cavelier@tiolive.com>
Date: Wed, 3 Jul 2013 12:17:17 +0200
Subject: [PATCH] complex queries module redesigned to moved methods

---
 complex_queries.js          | 979 ++++++++++++++++++------------------
 src/queries/complexquery.js | 166 +++---
 src/queries/parser-begin.js |   6 +
 src/queries/parser-end.js   |   2 +
 src/queries/query.js        | 320 ++++--------
 src/queries/queryfactory.js |  55 +-
 src/queries/simplequery.js  | 217 ++++----
 src/queries/tool.js         | 206 ++++----
 8 files changed, 931 insertions(+), 1020 deletions(-)

diff --git a/complex_queries.js b/complex_queries.js
index 8ea969e..5f1e367 100644
--- a/complex_queries.js
+++ b/complex_queries.js
@@ -28,6 +28,14 @@ var complex_queries;
       "value": value
     });
   }
+/**
+ * Parse a text request to a json query object tree
+ *
+ * @method parseStringToObject
+ * @static
+ * @param  {String} string The string to parse
+ * @return {Object} The json query tree
+ */
 function parseStringToObject(string) {
 
 /*
@@ -714,105 +722,11 @@ if ((error_count = __NODEJS_parse(string, error_offsets, error_lookaheads)) > 0)
 
   return result;
 } // parseStringToObject
+
+_export('parseStringToObject', parseStringToObject);
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
 /*global _export: true */
 
-/**
- * Create a class, manage inheritance, static methods,
- * protected attributes and can hide methods or/and secure methods
- *
- * @param  {Class} Class Classes to inherit from (0..n). The last class
- *                       parameter will inherit from the previous one, and so on
- * @param  {Object} option Class option (0..n)
- * @param  {Boolean} [option.secure_methods=false] Make methods not configurable
- *                                                 and not writable
- * @param  {Boolean} [option.hide_methods=false] Make methods not enumerable
- * @param  {Boolean} [option.secure_static_methods=true] Make static methods not
- *                                                       configurable and not
- *                                                       writable
- * @param  {Boolean} [option.hide_static_methods=false] Make static methods not
- *                                                      enumerable
- * @param  {Object} [option.static_methods={}] Object of static methods
- * @param  {Function} constructor The new class constructor
- * @return {Class} The new class
- */
-function newClass() {
-  var j, k, constructors = [], option, new_class;
-
-  for (j = 0; j < arguments.length; j += 1) {
-    if (typeof arguments[j] === "function") {
-      constructors.push(arguments[j]);
-    } else if (typeof arguments[j] === "object") {
-      option = option || {};
-      for (k in arguments[j]) {
-        if (arguments[j].hasOwnProperty(k)) {
-          option[k] = arguments[j][k];
-        }
-      }
-    }
-  }
-
-  function postObjectCreation(that) {
-    // modify the object according to 'option'
-    var key;
-    if (option) {
-      for (key in that) {
-        if (that.hasOwnProperty(key)) {
-          if (typeof that[key] === "function") {
-            Object.defineProperty(that, key, {
-              "configurable": option.secure_methods ? false : true,
-              "enumerable": option.hide_methods ? false : true,
-              "writable": option.secure_methods ? false : true,
-              "value": that[key]
-            });
-          }
-        }
-      }
-    }
-  }
-
-  function postClassCreation(that) {
-    // modify the object according to 'option'
-    var key;
-    if (option) {
-      for (key in that) {
-        if (that.hasOwnProperty(key)) {
-          if (typeof that[key] === "function") {
-            Object.defineProperty(that, key, {
-              "configurable": option.secure_static_methods ===
-                false ? true : false,
-              "enumerable": option.hide_static_methods ? false : true,
-              "writable": option.secure_static_methods === false ? true : false,
-              "value": that[key]
-            });
-          }
-        }
-      }
-    }
-  }
-
-  new_class = function (spec, my) {
-    var i;
-    spec = spec || {};
-    my = my || {};
-    // don't use forEach !
-    for (i = 0; i < constructors.length; i += 1) {
-      constructors[i].apply(this, [spec, my]);
-    }
-    postObjectCreation(this);
-    return this;
-  };
-  option = option || {};
-  option.static_methods = option.static_methods || {};
-  for (j in option.static_methods) {
-    if (option.static_methods.hasOwnProperty(j)) {
-      new_class[j] = option.static_methods[j];
-    }
-  }
-  postClassCreation(new_class);
-  return new_class;
-}
-
 /**
  * Escapes regexp special chars from a string.
  *
@@ -844,51 +758,195 @@ function sortFunction(key, way) {
     return a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0;
   };
 }
+
+/**
+ * Clones all native object in deep. Managed types: Object, Array, String,
+ * Number, Boolean, null.
+ *
+ * @param  {A} object The object to clone
+ * @return {A} The cloned object
+ */
+function deepClone(object) {
+  var i, cloned;
+  if (Object.prototype.toString.call(object) === "[object Array]") {
+    cloned = [];
+    for (i = 0; i < object.length; i += 1) {
+      cloned[i] = deepClone(object[i]);
+    }
+    return cloned;
+  }
+  if (typeof object === "object") {
+    cloned = {};
+    for (i in object) {
+      if (object.hasOwnProperty(i)) {
+        cloned[i] = deepClone(object[i]);
+      }
+    }
+    return cloned;
+  }
+  return object;
+}
+
+/**
+ * Inherits the prototype methods from one constructor into another. The
+ * prototype of `constructor` will be set to a new object created from
+ * `superConstructor`.
+ */
+function inherits(constructor, superConstructor) {
+  constructor.super_ = superConstructor;
+  constructor.prototype = Object.create(superConstructor.prototype, {});
+}
+
+/**
+ * Does nothing
+ */
+function emptyFunction() {}
+
+/**
+ * Filter a list of items, modifying them to select only wanted keys. If
+ * `clone` is true, then the method will act on a cloned list.
+ *
+ * @method select
+ * @static
+ * @param  {Array} select_option Key list to keep
+ * @param  {Array} list The item list to filter
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function select(select_option, list, clone) {
+  var i, j, new_item;
+  if (clone) {
+    list = deepClone(list);
+  }
+  for (i = 0; i < list.length; i += 1) {
+    new_item = {};
+    for (j = 0; j < select_option.length; j += 1) {
+      new_item[select_option[j]] = list[i][select_option[j]];
+    }
+    for (j in new_item) {
+      if (new_item.hasOwnProperty(j)) {
+        list[i] = new_item;
+        break;
+      }
+    }
+  }
+  return list;
+}
+
+_export('select', select);
+
+/**
+ * Sort a list of items, according to keys and directions. If `clone` is true,
+ * then the method will act on a cloned list.
+ *
+ * @method sortOn
+ * @static
+ * @param  {Array} sort_on_option List of couples [key, direction]
+ * @param  {Array} list The item list to sort
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function sortOn(sort_on_option, list, clone) {
+  var sort_index;
+  if (clone) {
+    list = deepClone(list);
+  }
+  for (sort_index = sort_on_option.length - 1; sort_index >= 0;
+       sort_index -= 1) {
+    list.sort(sortFunction(
+      sort_on_option[sort_index][0],
+      sort_on_option[sort_index][1]
+    ));
+  }
+  return list;
+}
+
+_export('sortOn', sortOn);
+
+/**
+ * Limit a list of items, according to index and length. If `clone` is true,
+ * then the method will act on a cloned list.
+ *
+ * @method limit
+ * @static
+ * @param  {Array} limit_option A couple [from, length]
+ * @param  {Array} list The item list to limit
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function limit(limit_option, list, clone) {
+  if (clone) {
+    list = deepClone(list);
+  }
+  list.splice(0, limit_option[0]);
+  if (limit_option[1]) {
+    list.splice(limit_option[1]);
+  }
+  return list;
+}
+
+_export('limit', limit);
+
+/**
+ * Convert a search text to a regexp.
+ *
+ * @method convertStringToRegExp
+ * @static
+ * @param  {String} string The string to convert
+ * @param  {String} [wildcard_character=undefined] The wildcard chararter
+ * @return {RegExp} The search text regexp
+ */
+function convertStringToRegExp(string, wildcard_character) {
+  return new RegExp("^" + stringEscapeRegexpCharacters(string).replace(
+    stringEscapeRegexpCharacters(wildcard_character),
+    '.*'
+  ) + "$");
+}
+
+_export('convertStringToRegExp', convertStringToRegExp);
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global _export: true, ComplexQuery: true, SimpleQuery: true,
-         newClass: true, Query: true */
+/*global _export: true, ComplexQuery: true, SimpleQuery: true, Query: true,
+  parseStringToObject: true */
 
 
-var query_class_dict = {}, QueryFactory;
+var query_class_dict = {};
 
 /**
  * Provides static methods to create Query object
  *
  * @class QueryFactory
  */
-QueryFactory = newClass({
-  "static_methods": {
-
-    /**
-     * Creates Query object from a search text string or a serialized version
-     * of a Query.
-     *
-     * @method create
-     * @static
-     * @param  {Object,String} object The search text or the serialized version
-     *         of a Query
-     * @return {Query} A Query object
-     */
-    "create": function (object) {
-      if (object === "") {
-        return new Query();
-      }
-      if (typeof object === "string") {
-        object = Query.parseStringToObject(object);
-      }
-      if (typeof (object || {}).type === "string" &&
-          query_class_dict[object.type]) {
-        return new query_class_dict[object.type](object);
-      }
-      return null;
-    }
+function QueryFactory() {}
+
+/**
+ * Creates Query object from a search text string or a serialized version
+ * of a Query.
+ *
+ * @method create
+ * @static
+ * @param  {Object,String} object The search text or the serialized version
+ *         of a Query
+ * @return {Query} A Query object
+ */
+QueryFactory.create = function (object) {
+  if (object === "") {
+    return new Query();
+  }
+  if (typeof object === "string") {
+    object = parseStringToObject(object);
+  }
+  if (typeof (object || {}).type === "string" &&
+      query_class_dict[object.type]) {
+    return new query_class_dict[object.type](object);
   }
-}, function () {});
+  return null;
+};
 
 _export("QueryFactory", QueryFactory);
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, sortFunction: true, parseStringToObject: true,
-         _export: true, stringEscapeRegexpCharacters: true */
+/*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit:
+  true, select: true, _export: true, stringEscapeRegexpCharacters: true,
+  deepClone: true */
 
 /**
  * The query to use to filter a list of objects.
@@ -897,99 +955,7 @@ _export("QueryFactory", QueryFactory);
  * @class Query
  * @constructor
  */
-var Query = newClass(function () {
-
-  var that = this, emptyFunction = function () {};
-
-  /**
-   * Filter the item list with matching item only
-   *
-   * @method exec
-   * @param  {Array} item_list The list of object
-   * @param  {Object} [option] Some operation option
-   * @param  {String} [option.wildcard_character="%"] The wildcard character
-   * @param  {Array} [option.select_list] A object keys to retrieve
-   * @param  {Array} [option.sort_on] Couples of object keys and "ascending"
-   *                 or "descending"
-   * @param  {Array} [option.limit] Couple of integer, first is an index and
-   *                 second is the length.
-   */
-  that.exec = function (item_list, option) {
-    var i = 0;
-    while (i < item_list.length) {
-      if (!that.match(item_list[i], option.wildcard_character)) {
-        item_list.splice(i, 1);
-      } else {
-        i += 1;
-      }
-    }
-    if (option.sort_on) {
-      Query.sortOn(option.sort_on, item_list);
-    }
-    if (option.limit) {
-      item_list.splice(0, option.limit[0]);
-      if (option.limit[1]) {
-        item_list.splice(option.limit[1]);
-      }
-    }
-    Query.filterListSelect(option.select_list || [], item_list);
-  };
-
-  /**
-   * Test if an item matches this query
-   *
-   * @method match
-   * @param  {Object} item The object to test
-   * @return {Boolean} true if match, false otherwise
-   */
-  that.match = function (item, wildcard_character) {
-    return true;
-  };
-
-  /**
-   * The recursive parser.
-   *
-   * @method recParse
-   * @private
-   * @param  {Object} object The object shared in the parse process
-   * @param  {Object} options Some options usable in the parseMethods
-   * @return {Any} The parser result
-   */
-  function recParse(object, option) {
-    var i, query = object.parsed;
-    if (query.type === "complex") {
-      for (i = 0; i < query.query_list.length; i += 1) {
-        object.parsed = query.query_list[i];
-        recParse(object, option);
-        query.query_list[i] = object.parsed;
-      }
-      object.parsed = query;
-      that.onParseComplexQuery(object, option);
-    } else if (query.type === "simple") {
-      that.onParseSimpleQuery(object, option);
-    }
-  }
-
-  /**
-   * Browse the Query in deep calling parser method in each step.
-   *
-   * `onParseStart` is called first, on end `onParseEnd` is called.
-   * It starts from the simple queries at the bottom of the tree calling the
-   * parser method `onParseSimpleQuery`, and go up calling the
-   * `onParseComplexQuery` method.
-   *
-   * @method parse
-   * @param  {Object} option Any options you want (except 'parsed')
-   * @return {Any} The parse result
-   */
-  that.parse = function (option) {
-    var object;
-    object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
-    that.onParseStart(object, option);
-    recParse(object, option);
-    that.onParseEnd(object, option);
-    return object.parsed;
-  };
+function Query() {
 
   /**
    * Called before parsing the query. Must be overridden!
@@ -998,7 +964,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseStart = emptyFunction;
+  this.onParseStart = emptyFunction;
 
   /**
    * Called when parsing a simple query. Must be overridden!
@@ -1007,7 +973,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseSimpleQuery = emptyFunction;
+  this.onParseSimpleQuery = emptyFunction;
 
   /**
    * Called when parsing a complex query. Must be overridden!
@@ -1016,7 +982,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseComplexQuery = emptyFunction;
+  this.onParseComplexQuery = emptyFunction;
 
   /**
    * Called after parsing the query. Must be overridden!
@@ -1025,105 +991,121 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseEnd = emptyFunction;
+  this.onParseEnd = emptyFunction;
 
-  /**
-   * Convert this query to a parsable string.
-   *
-   * @method toString
-   * @return {String} The string version of this query
-   */
-  that.toString = function () {
-    return "";
-  };
+}
+Query.prototype.constructor = Query;
 
-  /**
-   * Convert this query to an jsonable object in order to be remake thanks to
-   * QueryFactory class.
-   *
-   * @method serialized
-   * @return {Object} The jsonable object
-   */
-  that.serialized = function () {
-    return undefined;
-  };
+/**
+ * Filter the item list with matching item only
+ *
+ * @method exec
+ * @param  {Array} item_list The list of object
+ * @param  {Object} [option] Some operation option
+ * @param  {String} [option.wildcard_character="%"] The wildcard character
+ * @param  {Array} [option.select_list] A object keys to retrieve
+ * @param  {Array} [option.sort_on] Couples of object keys and "ascending"
+ *                 or "descending"
+ * @param  {Array} [option.limit] Couple of integer, first is an index and
+ *                 second is the length.
+ */
+Query.prototype.exec = function (item_list, option) {
+  var i = 0;
+  while (i < item_list.length) {
+    if (!this.match(item_list[i], option.wildcard_character)) {
+      item_list.splice(i, 1);
+    } else {
+      i += 1;
+    }
+  }
+  if (option.sort_on) {
+    sortOn(option.sort_on, item_list);
+  }
+  if (option.limit) {
+    limit(option.limit, item_list);
+  }
+  select(option.select_list || [], item_list);
+};
 
-}, {"static_methods": {
+/**
+ * Test if an item matches this query
+ *
+ * @method match
+ * @param  {Object} item The object to test
+ * @return {Boolean} true if match, false otherwise
+ */
+Query.prototype.match = function (item, wildcard_character) {
+  return true;
+};
 
-  /**
-   * Filter a list of items, modifying them to select only wanted keys.
-   *
-   * @method filterListSelect
-   * @static
-   * @param  {Array} select_option Key list to keep
-   * @param  {Array} list The item list to filter
-   */
-  "filterListSelect": function (select_option, list) {
-    var i, j, new_item;
-    for (i = 0; i < list.length; i += 1) {
-      new_item = {};
-      for (j = 0; j < select_option.length; j += 1) {
-        new_item[select_option[j]] = list[i][select_option[j]];
-      }
-      for (j in new_item) {
-        if (new_item.hasOwnProperty(j)) {
-          list[i] = new_item;
-          break;
-        }
-      }
-    }
-  },
 
+/**
+ * Browse the Query in deep calling parser method in each step.
+ *
+ * `onParseStart` is called first, on end `onParseEnd` is called.
+ * It starts from the simple queries at the bottom of the tree calling the
+ * parser method `onParseSimpleQuery`, and go up calling the
+ * `onParseComplexQuery` method.
+ *
+ * @method parse
+ * @param  {Object} option Any options you want (except 'parsed')
+ * @return {Any} The parse result
+ */
+Query.prototype.parse = function (option) {
+  var that = this, object;
   /**
-   * Sort a list of items, according to keys and directions.
+   * The recursive parser.
    *
-   * @method sortOn
-   * @static
-   * @param  {Array} sort_on_option List of couples [key, direction]
-   * @param  {Array} list The item list to sort
+   * @param  {Object} object The object shared in the parse process
+   * @param  {Object} options Some options usable in the parseMethods
+   * @return {Any} The parser result
    */
-  "sortOn": function (sort_on_option, list) {
-    var sort_index;
-    for (sort_index = sort_on_option.length - 1; sort_index >= 0;
-         sort_index -= 1) {
-      list.sort(sortFunction(
-        sort_on_option[sort_index][0],
-        sort_on_option[sort_index][1]
-      ));
+  function recParse(object, option) {
+    var i, query = object.parsed;
+    if (query.type === "complex") {
+      for (i = 0; i < query.query_list.length; i += 1) {
+        object.parsed = query.query_list[i];
+        recParse(object, option);
+        query.query_list[i] = object.parsed;
+      }
+      object.parsed = query;
+      that.onParseComplexQuery(object, option);
+    } else if (query.type === "simple") {
+      that.onParseSimpleQuery(object, option);
     }
-  },
+  }
+  object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
+  that.onParseStart(object, option);
+  recParse(object, option);
+  that.onParseEnd(object, option);
+  return object.parsed;
+};
 
-  /**
-   * Parse a text request to a json query object tree
-   *
-   * @method parseStringToObject
-   * @static
-   * @param  {String} string The string to parse
-   * @return {Object} The json query tree
-   */
-  "parseStringToObject": parseStringToObject,
+/**
+ * Convert this query to a parsable string.
+ *
+ * @method toString
+ * @return {String} The string version of this query
+ */
+Query.prototype.toString = function () {
+  return "";
+};
 
-  /**
-   * Convert a search text to a regexp.
-   *
-   * @method convertStringToRegExp
-   * @static
-   * @param  {String} string The string to convert
-   * @param  {String} [wildcard_character=undefined] The wildcard chararter
-   * @return {RegExp} The search text regexp
-   */
-  "convertStringToRegExp": function (string, wildcard_character) {
-    return new RegExp("^" + stringEscapeRegexpCharacters(string).replace(
-      stringEscapeRegexpCharacters(wildcard_character),
-      '.*'
-    ) + "$");
-  }
-}});
+/**
+ * Convert this query to an jsonable object in order to be remake thanks to
+ * QueryFactory class.
+ *
+ * @method serialized
+ * @return {Object} The jsonable object
+ */
+Query.prototype.serialized = function () {
+  return undefined;
+};
 
 _export("Query", Query);
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, Query: true,
-         query_class_dict: true, _export: true */
+/*global Query: true, inherits: true, query_class_dict: true, _export: true,
+  convertStringToRegExp: true */
 
 /**
  * The SimpleQuery inherits from Query, and compares one metadata value
@@ -1135,7 +1117,9 @@ _export("Query", Query);
  * @param  {String} spec.key The metadata key
  * @param  {String} spec.value The value of the metadata to compare
  */
-var SimpleQuery = newClass(Query, function (spec) {
+function SimpleQuery(spec) {
+  Query.call(this);
+
   /**
    * Operator to use to compare object values
    *
@@ -1162,124 +1146,127 @@ var SimpleQuery = newClass(Query, function (spec) {
    */
   this.value = spec.value;
 
-  /**
-   * #crossLink "Query/match:method"
-   */
-  this.match = function (item, wildcard_character) {
-    return this[this.operator](item[this.key], this.value, wildcard_character);
-  };
+}
+inherits(SimpleQuery, Query);
+SimpleQuery.prototype.constructor = SimpleQuery;
 
-  /**
-   * #crossLink "Query/toString:method"
-   */
-  this.toString = function () {
-    return (this.key ? this.key + ": " : "") + (this.operator || "=") + ' "' +
-      this.value + '"';
-  };
+/**
+ * #crossLink "Query/match:method"
+ */
+SimpleQuery.prototype.match = function (item, wildcard_character) {
+  return this[this.operator](item[this.key], this.value, wildcard_character);
+};
 
-  /**
-   * #crossLink "Query/serialized:method"
-   */
-  this.serialized = function () {
-    return {
-      "type": "simple",
-      "operator": this.operator,
-      "key": this.key,
-      "value": this.value
-    };
-  };
+/**
+ * #crossLink "Query/toString:method"
+ */
+SimpleQuery.prototype.toString = function () {
+  return (this.key ? this.key + ": " : "") + (this.operator || "=") + ' "' +
+    this.value + '"';
+};
 
-  /**
-   * Comparison operator, test if this query value matches the item value
-   *
-   * @method =
-   * @param  {String} object_value The value to compare
-   * @param  {String} comparison_value The comparison value
-   * @param  {String} wildcard_character The wildcard_character
-   * @return {Boolean} true if match, false otherwise
-   */
-  this["="] = function (object_value, comparison_value,
-                        wildcard_character) {
-    return Query.convertStringToRegExp(
-      comparison_value.toString(),
-      wildcard_character || "%"
-    ).test(object_value.toString());
+/**
+ * #crossLink "Query/serialized:method"
+ */
+SimpleQuery.prototype.serialized = function () {
+  return {
+    "type": "simple",
+    "operator": this.operator,
+    "key": this.key,
+    "value": this.value
   };
+};
 
-  /**
-   * Comparison operator, test if this query value does not match the item value
-   *
-   * @method !=
-   * @param  {String} object_value The value to compare
-   * @param  {String} comparison_value The comparison value
-   * @param  {String} wildcard_character The wildcard_character
-   * @return {Boolean} true if not match, false otherwise
-   */
-  this["!="] = function (object_value, comparison_value,
-                         wildcard_character) {
-    return !Query.convertStringTextToRegExp(
-      comparison_value.toString(),
-      wildcard_character || "%"
-    ).test(object_value.toString());
-  };
+/**
+ * Comparison operator, test if this query value matches the item value
+ *
+ * @method =
+ * @param  {String} object_value The value to compare
+ * @param  {String} comparison_value The comparison value
+ * @param  {String} wildcard_character The wildcard_character
+ * @return {Boolean} true if match, false otherwise
+ */
+SimpleQuery.prototype["="] = function (object_value, comparison_value,
+                      wildcard_character) {
+  return convertStringToRegExp(
+    comparison_value.toString(),
+    wildcard_character || "%"
+  ).test(object_value.toString());
+};
 
-  /**
-   * Comparison operator, test if this query value is lower than the item value
-   *
-   * @method <
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if lower, false otherwise
-   */
-  this["<"] = function (object_value, comparison_value) {
-    return object_value < comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value does not match the item value
+ *
+ * @method !=
+ * @param  {String} object_value The value to compare
+ * @param  {String} comparison_value The comparison value
+ * @param  {String} wildcard_character The wildcard_character
+ * @return {Boolean} true if not match, false otherwise
+ */
+SimpleQuery.prototype["!="] = function (object_value, comparison_value,
+                       wildcard_character) {
+  return !convertStringToRegExp(
+    comparison_value.toString(),
+    wildcard_character || "%"
+  ).test(object_value.toString());
+};
 
-  /**
-   * Comparison operator, test if this query value is equal or lower than the
-   * item value
-   *
-   * @method <=
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if equal or lower, false otherwise
-   */
-  this["<="] = function (object_value, comparison_value) {
-    return object_value <= comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value is lower than the item value
+ *
+ * @method <
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if lower, false otherwise
+ */
+SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
+  return object_value < comparison_value;
+};
 
-  /**
-   * Comparison operator, test if this query value is greater than the item
-   * value
-   *
-   * @method >
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if greater, false otherwise
-   */
-  this[">"] = function (object_value, comparison_value) {
-    return object_value > comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value is equal or lower than the
+ * item value
+ *
+ * @method <=
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if equal or lower, false otherwise
+ */
+SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
+  return object_value <= comparison_value;
+};
 
-  /**
-   * Comparison operator, test if this query value is equal or greater than the
-   * item value
-   *
-   * @method >=
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if equal or greater, false otherwise
-   */
-  this[">="] = function (object_value, comparison_value) {
-    return object_value >= comparison_value;
-  };
-});
+/**
+ * Comparison operator, test if this query value is greater than the item
+ * value
+ *
+ * @method >
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if greater, false otherwise
+ */
+SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
+  return object_value > comparison_value;
+};
+
+/**
+ * Comparison operator, test if this query value is equal or greater than the
+ * item value
+ *
+ * @method >=
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if equal or greater, false otherwise
+ */
+SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
+  return object_value >= comparison_value;
+};
 
 query_class_dict.simple = SimpleQuery;
 
 _export("SimpleQuery", SimpleQuery);
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, Query: true, query_class_dict: true,
+/*global Query: true, query_class_dict: true, inherits: true,
          _export: true, QueryFactory: true */
 
 /**
@@ -1293,7 +1280,8 @@ _export("SimpleQuery", SimpleQuery);
  * @param  {String} spec.key The metadata key
  * @param  {String} spec.value The value of the metadata to compare
  */
-var ComplexQuery = newClass(Query, function (spec) {
+function ComplexQuery(spec) {
+  Query.call(this);
 
   /**
    * Logical operator to use to compare object values
@@ -1316,93 +1304,96 @@ var ComplexQuery = newClass(Query, function (spec) {
   this.query_list = spec.query_list || [];
   this.query_list = this.query_list.map(QueryFactory.create);
 
-  /**
-   * #crossLink "Query/match:method"
-   */
-  this.match = function (item, wildcard_character) {
-    return this[this.operator](item, wildcard_character);
-  };
+}
+inherits(ComplexQuery, Query);
+ComplexQuery.prototype.constructor = ComplexQuery;
 
-  /**
-   * #crossLink "Query/toString:method"
-   */
-  this.toString = function () {
-    var str_list = ["("], this_operator = this.operator;
-    this.query_list.forEach(function (query) {
-      str_list.push(query.toString());
-      str_list.push(this_operator);
-    });
-    str_list.pop(); // remove last operator
-    str_list.push(")");
-    return str_list.join(" ");
-  };
+/**
+ * #crossLink "Query/match:method"
+ */
+ComplexQuery.prototype.match = function (item, wildcard_character) {
+  return this[this.operator](item, wildcard_character);
+};
 
-  /**
-   * #crossLink "Query/serialized:method"
-   */
-  this.serialized = function () {
-    var s = {
-      "type": "complex",
-      "operator": this.operator,
-      "query_list": []
-    };
-    this.query_list.forEach(function (query) {
-      s.query_list.push(query.serialized());
-    });
-    return s;
+/**
+ * #crossLink "Query/toString:method"
+ */
+ComplexQuery.prototype.toString = function () {
+  var str_list = ["("], this_operator = this.operator;
+  this.query_list.forEach(function (query) {
+    str_list.push(query.toString());
+    str_list.push(this_operator);
+  });
+  str_list.pop(); // remove last operator
+  str_list.push(")");
+  return str_list.join(" ");
+};
+
+/**
+ * #crossLink "Query/serialized:method"
+ */
+ComplexQuery.prototype.serialized = function () {
+  var s = {
+    "type": "complex",
+    "operator": this.operator,
+    "query_list": []
   };
+  this.query_list.forEach(function (query) {
+    s.query_list.push(query.serialized());
+  });
+  return s;
+};
 
-  /**
-   * Comparison operator, test if all sub queries match the
-   * item value
-   *
-   * @method AND
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if all match, false otherwise
-   */
-  this.AND = function (item, wildcard_character) {
-    var i;
-    for (i = 0; i < this.query_list.length; i += 1) {
-      if (!this.query_list[i].match(item, wildcard_character)) {
-        return false;
-      }
+/**
+ * Comparison operator, test if all sub queries match the
+ * item value
+ *
+ * @method AND
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if all match, false otherwise
+ */
+ComplexQuery.prototype.AND = function (item, wildcard_character) {
+  var i;
+  for (i = 0; i < this.query_list.length; i += 1) {
+    if (!this.query_list[i].match(item, wildcard_character)) {
+      return false;
     }
-    return true;
-  };
+  }
+  return true;
+};
 
-  /**
-   * Comparison operator, test if one of the sub queries matches the
-   * item value
-   *
-   * @method OR
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if one match, false otherwise
-   */
-  this.OR =  function (item, wildcard_character) {
-    var i;
-    for (i = 0; i < this.query_list.length; i += 1) {
-      if (this.query_list[i].match(item, wildcard_character)) {
-        return true;
-      }
+/**
+ * Comparison operator, test if one of the sub queries matches the
+ * item value
+ *
+ * @method OR
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if one match, false otherwise
+ */
+ComplexQuery.prototype.OR =  function (item, wildcard_character) {
+  var i;
+  for (i = 0; i < this.query_list.length; i += 1) {
+    if (this.query_list[i].match(item, wildcard_character)) {
+      return true;
     }
-    return false;
-  };
+  }
+  return false;
+};
 
-  /**
-   * Comparison operator, test if the sub query does not match the
-   * item value
-   *
-   * @method NOT
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if one match, false otherwise
-   */
-  this.NOT = function (item, wildcard_character) {
-    return !this.query_list[0].match(item, wildcard_character);
-  };
-});
+/**
+ * Comparison operator, test if the sub query does not match the
+ * item value
+ *
+ * @method NOT
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if one match, false otherwise
+ */
+ComplexQuery.prototype.NOT = function (item, wildcard_character) {
+  return !this.query_list[0].match(item, wildcard_character);
+};
 
 query_class_dict.complex = ComplexQuery;
 
diff --git a/src/queries/complexquery.js b/src/queries/complexquery.js
index 264d596..699abb0 100644
--- a/src/queries/complexquery.js
+++ b/src/queries/complexquery.js
@@ -1,5 +1,5 @@
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, Query: true, query_class_dict: true,
+/*global Query: true, query_class_dict: true, inherits: true,
          _export: true, QueryFactory: true */
 
 /**
@@ -13,7 +13,8 @@
  * @param  {String} spec.key The metadata key
  * @param  {String} spec.value The value of the metadata to compare
  */
-var ComplexQuery = newClass(Query, function (spec) {
+function ComplexQuery(spec) {
+  Query.call(this);
 
   /**
    * Logical operator to use to compare object values
@@ -36,93 +37,96 @@ var ComplexQuery = newClass(Query, function (spec) {
   this.query_list = spec.query_list || [];
   this.query_list = this.query_list.map(QueryFactory.create);
 
-  /**
-   * #crossLink "Query/match:method"
-   */
-  this.match = function (item, wildcard_character) {
-    return this[this.operator](item, wildcard_character);
-  };
+}
+inherits(ComplexQuery, Query);
+ComplexQuery.prototype.constructor = ComplexQuery;
 
-  /**
-   * #crossLink "Query/toString:method"
-   */
-  this.toString = function () {
-    var str_list = ["("], this_operator = this.operator;
-    this.query_list.forEach(function (query) {
-      str_list.push(query.toString());
-      str_list.push(this_operator);
-    });
-    str_list.pop(); // remove last operator
-    str_list.push(")");
-    return str_list.join(" ");
-  };
+/**
+ * #crossLink "Query/match:method"
+ */
+ComplexQuery.prototype.match = function (item, wildcard_character) {
+  return this[this.operator](item, wildcard_character);
+};
 
-  /**
-   * #crossLink "Query/serialized:method"
-   */
-  this.serialized = function () {
-    var s = {
-      "type": "complex",
-      "operator": this.operator,
-      "query_list": []
-    };
-    this.query_list.forEach(function (query) {
-      s.query_list.push(query.serialized());
-    });
-    return s;
+/**
+ * #crossLink "Query/toString:method"
+ */
+ComplexQuery.prototype.toString = function () {
+  var str_list = ["("], this_operator = this.operator;
+  this.query_list.forEach(function (query) {
+    str_list.push(query.toString());
+    str_list.push(this_operator);
+  });
+  str_list.pop(); // remove last operator
+  str_list.push(")");
+  return str_list.join(" ");
+};
+
+/**
+ * #crossLink "Query/serialized:method"
+ */
+ComplexQuery.prototype.serialized = function () {
+  var s = {
+    "type": "complex",
+    "operator": this.operator,
+    "query_list": []
   };
+  this.query_list.forEach(function (query) {
+    s.query_list.push(query.serialized());
+  });
+  return s;
+};
 
-  /**
-   * Comparison operator, test if all sub queries match the
-   * item value
-   *
-   * @method AND
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if all match, false otherwise
-   */
-  this.AND = function (item, wildcard_character) {
-    var i;
-    for (i = 0; i < this.query_list.length; i += 1) {
-      if (!this.query_list[i].match(item, wildcard_character)) {
-        return false;
-      }
+/**
+ * Comparison operator, test if all sub queries match the
+ * item value
+ *
+ * @method AND
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if all match, false otherwise
+ */
+ComplexQuery.prototype.AND = function (item, wildcard_character) {
+  var i;
+  for (i = 0; i < this.query_list.length; i += 1) {
+    if (!this.query_list[i].match(item, wildcard_character)) {
+      return false;
     }
-    return true;
-  };
+  }
+  return true;
+};
 
-  /**
-   * Comparison operator, test if one of the sub queries matches the
-   * item value
-   *
-   * @method OR
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if one match, false otherwise
-   */
-  this.OR =  function (item, wildcard_character) {
-    var i;
-    for (i = 0; i < this.query_list.length; i += 1) {
-      if (this.query_list[i].match(item, wildcard_character)) {
-        return true;
-      }
+/**
+ * Comparison operator, test if one of the sub queries matches the
+ * item value
+ *
+ * @method OR
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if one match, false otherwise
+ */
+ComplexQuery.prototype.OR =  function (item, wildcard_character) {
+  var i;
+  for (i = 0; i < this.query_list.length; i += 1) {
+    if (this.query_list[i].match(item, wildcard_character)) {
+      return true;
     }
-    return false;
-  };
+  }
+  return false;
+};
 
-  /**
-   * Comparison operator, test if the sub query does not match the
-   * item value
-   *
-   * @method NOT
-   * @param  {Object} item The item to match
-   * @param  {String} wildcard_character The wildcard character
-   * @return {Boolean} true if one match, false otherwise
-   */
-  this.NOT = function (item, wildcard_character) {
-    return !this.query_list[0].match(item, wildcard_character);
-  };
-});
+/**
+ * Comparison operator, test if the sub query does not match the
+ * item value
+ *
+ * @method NOT
+ * @param  {Object} item The item to match
+ * @param  {String} wildcard_character The wildcard character
+ * @return {Boolean} true if one match, false otherwise
+ */
+ComplexQuery.prototype.NOT = function (item, wildcard_character) {
+  return !this.query_list[0].match(item, wildcard_character);
+};
 
 query_class_dict.complex = ComplexQuery;
 
diff --git a/src/queries/parser-begin.js b/src/queries/parser-begin.js
index fe25baa..ac2dfd4 100644
--- a/src/queries/parser-begin.js
+++ b/src/queries/parser-begin.js
@@ -1 +1,7 @@
+/**
+ * Parse a text request to a json query object tree
+ *
+ * @param  {String} string The string to parse
+ * @return {Object} The json query tree
+ */
 function parseStringToObject(string) {
diff --git a/src/queries/parser-end.js b/src/queries/parser-end.js
index 94ae194..cb76bfa 100644
--- a/src/queries/parser-end.js
+++ b/src/queries/parser-end.js
@@ -1,2 +1,4 @@
   return result;
 } // parseStringToObject
+
+_export('parseStringToObject', parseStringToObject);
diff --git a/src/queries/query.js b/src/queries/query.js
index d1c37f4..9836bde 100644
--- a/src/queries/query.js
+++ b/src/queries/query.js
@@ -1,6 +1,7 @@
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, sortFunction: true, parseStringToObject: true,
-         _export: true, stringEscapeRegexpCharacters: true, deepClone: true */
+/*global parseStringToObject: true, emptyFunction: true, sortOn: true, limit:
+  true, select: true, _export: true, stringEscapeRegexpCharacters: true,
+  deepClone: true */
 
 /**
  * The query to use to filter a list of objects.
@@ -9,96 +10,7 @@
  * @class Query
  * @constructor
  */
-var Query = newClass(function () {
-
-  var that = this, emptyFunction = function () {};
-
-  /**
-   * Filter the item list with matching item only
-   *
-   * @method exec
-   * @param  {Array} item_list The list of object
-   * @param  {Object} [option] Some operation option
-   * @param  {String} [option.wildcard_character="%"] The wildcard character
-   * @param  {Array} [option.select_list] A object keys to retrieve
-   * @param  {Array} [option.sort_on] Couples of object keys and "ascending"
-   *                 or "descending"
-   * @param  {Array} [option.limit] Couple of integer, first is an index and
-   *                 second is the length.
-   */
-  that.exec = function (item_list, option) {
-    var i = 0;
-    while (i < item_list.length) {
-      if (!that.match(item_list[i], option.wildcard_character)) {
-        item_list.splice(i, 1);
-      } else {
-        i += 1;
-      }
-    }
-    if (option.sort_on) {
-      Query.sortOn(option.sort_on, item_list);
-    }
-    if (option.limit) {
-      Query.limit(option.limit, item_list);
-    }
-    Query.select(option.select_list || [], item_list);
-  };
-
-  /**
-   * Test if an item matches this query
-   *
-   * @method match
-   * @param  {Object} item The object to test
-   * @return {Boolean} true if match, false otherwise
-   */
-  that.match = function (item, wildcard_character) {
-    return true;
-  };
-
-  /**
-   * The recursive parser.
-   *
-   * @method recParse
-   * @private
-   * @param  {Object} object The object shared in the parse process
-   * @param  {Object} options Some options usable in the parseMethods
-   * @return {Any} The parser result
-   */
-  function recParse(object, option) {
-    var i, query = object.parsed;
-    if (query.type === "complex") {
-      for (i = 0; i < query.query_list.length; i += 1) {
-        object.parsed = query.query_list[i];
-        recParse(object, option);
-        query.query_list[i] = object.parsed;
-      }
-      object.parsed = query;
-      that.onParseComplexQuery(object, option);
-    } else if (query.type === "simple") {
-      that.onParseSimpleQuery(object, option);
-    }
-  }
-
-  /**
-   * Browse the Query in deep calling parser method in each step.
-   *
-   * `onParseStart` is called first, on end `onParseEnd` is called.
-   * It starts from the simple queries at the bottom of the tree calling the
-   * parser method `onParseSimpleQuery`, and go up calling the
-   * `onParseComplexQuery` method.
-   *
-   * @method parse
-   * @param  {Object} option Any options you want (except 'parsed')
-   * @return {Any} The parse result
-   */
-  that.parse = function (option) {
-    var object;
-    object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
-    that.onParseStart(object, option);
-    recParse(object, option);
-    that.onParseEnd(object, option);
-    return object.parsed;
-  };
+function Query() {
 
   /**
    * Called before parsing the query. Must be overridden!
@@ -107,7 +19,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseStart = emptyFunction;
+  this.onParseStart = emptyFunction;
 
   /**
    * Called when parsing a simple query. Must be overridden!
@@ -116,7 +28,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseSimpleQuery = emptyFunction;
+  this.onParseSimpleQuery = emptyFunction;
 
   /**
    * Called when parsing a complex query. Must be overridden!
@@ -125,7 +37,7 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseComplexQuery = emptyFunction;
+  this.onParseComplexQuery = emptyFunction;
 
   /**
    * Called after parsing the query. Must be overridden!
@@ -134,135 +46,115 @@ var Query = newClass(function () {
    * @param  {Object} object The object shared in the parse process
    * @param  {Object} option Some option gave in parse()
    */
-  that.onParseEnd = emptyFunction;
+  this.onParseEnd = emptyFunction;
 
-  /**
-   * Convert this query to a parsable string.
-   *
-   * @method toString
-   * @return {String} The string version of this query
-   */
-  that.toString = function () {
-    return "";
-  };
+}
+Query.prototype.constructor = Query;
 
-  /**
-   * Convert this query to an jsonable object in order to be remake thanks to
-   * QueryFactory class.
-   *
-   * @method serialized
-   * @return {Object} The jsonable object
-   */
-  that.serialized = function () {
-    return undefined;
-  };
-
-}, {"static_methods": {
-
-  /**
-   * Filter a list of items, modifying them to select only wanted keys. If
-   * `clone` is true, then the method will act on a cloned list.
-   *
-   * @method select
-   * @static
-   * @param  {Array} select_option Key list to keep
-   * @param  {Array} list The item list to filter
-   * @param  {Boolean} [clone=false] If true, modifies a clone of the list
-   * @return {Array} The filtered list
-   */
-  "select": function (select_option, list, clone) {
-    var i, j, new_item;
-    if (clone) {
-      list = deepClone(list);
-    }
-    for (i = 0; i < list.length; i += 1) {
-      new_item = {};
-      for (j = 0; j < select_option.length; j += 1) {
-        new_item[select_option[j]] = list[i][select_option[j]];
-      }
-      for (j in new_item) {
-        if (new_item.hasOwnProperty(j)) {
-          list[i] = new_item;
-          break;
-        }
-      }
+/**
+ * Filter the item list with matching item only
+ *
+ * @method exec
+ * @param  {Array} item_list The list of object
+ * @param  {Object} [option] Some operation option
+ * @param  {String} [option.wildcard_character="%"] The wildcard character
+ * @param  {Array} [option.select_list] A object keys to retrieve
+ * @param  {Array} [option.sort_on] Couples of object keys and "ascending"
+ *                 or "descending"
+ * @param  {Array} [option.limit] Couple of integer, first is an index and
+ *                 second is the length.
+ */
+Query.prototype.exec = function (item_list, option) {
+  var i = 0;
+  while (i < item_list.length) {
+    if (!this.match(item_list[i], option.wildcard_character)) {
+      item_list.splice(i, 1);
+    } else {
+      i += 1;
     }
-    return list;
-  },
+  }
+  if (option.sort_on) {
+    sortOn(option.sort_on, item_list);
+  }
+  if (option.limit) {
+    limit(option.limit, item_list);
+  }
+  select(option.select_list || [], item_list);
+};
+
+/**
+ * Test if an item matches this query
+ *
+ * @method match
+ * @param  {Object} item The object to test
+ * @return {Boolean} true if match, false otherwise
+ */
+Query.prototype.match = function (item, wildcard_character) {
+  return true;
+};
 
-  /**
-   * Sort a list of items, according to keys and directions. If `clone` is true,
-   * then the method will act on a cloned list.
-   *
-   * @method sortOn
-   * @static
-   * @param  {Array} sort_on_option List of couples [key, direction]
-   * @param  {Array} list The item list to sort
-   * @param  {Boolean} [clone=false] If true, modifies a clone of the list
-   * @return {Array} The filtered list
-   */
-  "sortOn": function (sort_on_option, list, clone) {
-    var sort_index;
-    if (clone) {
-      list = deepClone(list);
-    }
-    for (sort_index = sort_on_option.length - 1; sort_index >= 0;
-         sort_index -= 1) {
-      list.sort(sortFunction(
-        sort_on_option[sort_index][0],
-        sort_on_option[sort_index][1]
-      ));
-    }
-    return list;
-  },
 
+/**
+ * Browse the Query in deep calling parser method in each step.
+ *
+ * `onParseStart` is called first, on end `onParseEnd` is called.
+ * It starts from the simple queries at the bottom of the tree calling the
+ * parser method `onParseSimpleQuery`, and go up calling the
+ * `onParseComplexQuery` method.
+ *
+ * @method parse
+ * @param  {Object} option Any options you want (except 'parsed')
+ * @return {Any} The parse result
+ */
+Query.prototype.parse = function (option) {
+  var that = this, object;
   /**
-   * Limit a list of items, according to index and length. If `clone` is true,
-   * then the method will act on a cloned list.
+   * The recursive parser.
    *
-   * @method limit
-   * @static
-   * @param  {Array} limit_option A couple [from, length]
-   * @param  {Array} list The item list to limit
-   * @param  {Boolean} [clone=false] If true, modifies a clone of the list
-   * @return {Array} The filtered list
+   * @param  {Object} object The object shared in the parse process
+   * @param  {Object} options Some options usable in the parseMethods
+   * @return {Any} The parser result
    */
-  "limit": function (limit_option, list, clone) {
-    if (clone) {
-      list = deepClone(list);
-    }
-    list.splice(0, limit_option[0]);
-    if (limit_option[1]) {
-      list.splice(limit_option[1]);
+  function recParse(object, option) {
+    var i, query = object.parsed;
+    if (query.type === "complex") {
+      for (i = 0; i < query.query_list.length; i += 1) {
+        object.parsed = query.query_list[i];
+        recParse(object, option);
+        query.query_list[i] = object.parsed;
+      }
+      object.parsed = query;
+      that.onParseComplexQuery(object, option);
+    } else if (query.type === "simple") {
+      that.onParseSimpleQuery(object, option);
     }
-    return list;
-  },
+  }
+  object = {"parsed": JSON.parse(JSON.stringify(that.serialized()))};
+  that.onParseStart(object, option);
+  recParse(object, option);
+  that.onParseEnd(object, option);
+  return object.parsed;
+};
 
-  /**
-   * Parse a text request to a json query object tree
-   *
-   * @method parseStringToObject
-   * @static
-   * @param  {String} string The string to parse
-   * @return {Object} The json query tree
-   */
-  "parseStringToObject": parseStringToObject,
+/**
+ * Convert this query to a parsable string.
+ *
+ * @method toString
+ * @return {String} The string version of this query
+ */
+Query.prototype.toString = function () {
+  return "";
+};
 
-  /**
-   * Convert a search text to a regexp.
-   *
-   * @method convertStringToRegExp
-   * @static
-   * @param  {String} string The string to convert
-   * @param  {String} [wildcard_character=undefined] The wildcard chararter
-   * @return {RegExp} The search text regexp
-   */
-  "convertStringToRegExp": function (string, wildcard_character) {
-    return new RegExp("^" + stringEscapeRegexpCharacters(string).replace(
-      stringEscapeRegexpCharacters(wildcard_character),
-      '.*'
-    ) + "$");
-  }
-}});
+/**
+ * Convert this query to an jsonable object in order to be remake thanks to
+ * QueryFactory class.
+ *
+ * @method serialized
+ * @return {Object} The jsonable object
+ */
+Query.prototype.serialized = function () {
+  return undefined;
+};
 
 _export("Query", Query);
diff --git a/src/queries/queryfactory.js b/src/queries/queryfactory.js
index 7bf8d6a..454358b 100644
--- a/src/queries/queryfactory.js
+++ b/src/queries/queryfactory.js
@@ -1,42 +1,39 @@
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global _export: true, ComplexQuery: true, SimpleQuery: true,
-         newClass: true, Query: true */
+/*global _export: true, ComplexQuery: true, SimpleQuery: true, Query: true,
+  parseStringToObject: true */
 
 
-var query_class_dict = {}, QueryFactory;
+var query_class_dict = {};
 
 /**
  * Provides static methods to create Query object
  *
  * @class QueryFactory
  */
-QueryFactory = newClass({
-  "static_methods": {
+function QueryFactory() {}
 
-    /**
-     * Creates Query object from a search text string or a serialized version
-     * of a Query.
-     *
-     * @method create
-     * @static
-     * @param  {Object,String} object The search text or the serialized version
-     *         of a Query
-     * @return {Query} A Query object
-     */
-    "create": function (object) {
-      if (object === "") {
-        return new Query();
-      }
-      if (typeof object === "string") {
-        object = Query.parseStringToObject(object);
-      }
-      if (typeof (object || {}).type === "string" &&
-          query_class_dict[object.type]) {
-        return new query_class_dict[object.type](object);
-      }
-      return null;
-    }
+/**
+ * Creates Query object from a search text string or a serialized version
+ * of a Query.
+ *
+ * @method create
+ * @static
+ * @param  {Object,String} object The search text or the serialized version
+ *         of a Query
+ * @return {Query} A Query object
+ */
+QueryFactory.create = function (object) {
+  if (object === "") {
+    return new Query();
+  }
+  if (typeof object === "string") {
+    object = parseStringToObject(object);
+  }
+  if (typeof (object || {}).type === "string" &&
+      query_class_dict[object.type]) {
+    return new query_class_dict[object.type](object);
   }
-}, function () {});
+  return null;
+};
 
 _export("QueryFactory", QueryFactory);
diff --git a/src/queries/simplequery.js b/src/queries/simplequery.js
index ef05099..6de1723 100644
--- a/src/queries/simplequery.js
+++ b/src/queries/simplequery.js
@@ -1,6 +1,6 @@
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
-/*global newClass: true, Query: true,
-         query_class_dict: true, _export: true */
+/*global Query: true, inherits: true, query_class_dict: true, _export: true,
+  convertStringToRegExp: true */
 
 /**
  * The SimpleQuery inherits from Query, and compares one metadata value
@@ -12,7 +12,9 @@
  * @param  {String} spec.key The metadata key
  * @param  {String} spec.value The value of the metadata to compare
  */
-var SimpleQuery = newClass(Query, function (spec) {
+function SimpleQuery(spec) {
+  Query.call(this);
+
   /**
    * Operator to use to compare object values
    *
@@ -39,118 +41,121 @@ var SimpleQuery = newClass(Query, function (spec) {
    */
   this.value = spec.value;
 
-  /**
-   * #crossLink "Query/match:method"
-   */
-  this.match = function (item, wildcard_character) {
-    return this[this.operator](item[this.key], this.value, wildcard_character);
-  };
+}
+inherits(SimpleQuery, Query);
+SimpleQuery.prototype.constructor = SimpleQuery;
 
-  /**
-   * #crossLink "Query/toString:method"
-   */
-  this.toString = function () {
-    return (this.key ? this.key + ": " : "") + (this.operator || "=") + ' "' +
-      this.value + '"';
-  };
+/**
+ * #crossLink "Query/match:method"
+ */
+SimpleQuery.prototype.match = function (item, wildcard_character) {
+  return this[this.operator](item[this.key], this.value, wildcard_character);
+};
 
-  /**
-   * #crossLink "Query/serialized:method"
-   */
-  this.serialized = function () {
-    return {
-      "type": "simple",
-      "operator": this.operator,
-      "key": this.key,
-      "value": this.value
-    };
-  };
+/**
+ * #crossLink "Query/toString:method"
+ */
+SimpleQuery.prototype.toString = function () {
+  return (this.key ? this.key + ": " : "") + (this.operator || "=") + ' "' +
+    this.value + '"';
+};
 
-  /**
-   * Comparison operator, test if this query value matches the item value
-   *
-   * @method =
-   * @param  {String} object_value The value to compare
-   * @param  {String} comparison_value The comparison value
-   * @param  {String} wildcard_character The wildcard_character
-   * @return {Boolean} true if match, false otherwise
-   */
-  this["="] = function (object_value, comparison_value,
-                        wildcard_character) {
-    return Query.convertStringToRegExp(
-      comparison_value.toString(),
-      wildcard_character || "%"
-    ).test(object_value.toString());
+/**
+ * #crossLink "Query/serialized:method"
+ */
+SimpleQuery.prototype.serialized = function () {
+  return {
+    "type": "simple",
+    "operator": this.operator,
+    "key": this.key,
+    "value": this.value
   };
+};
 
-  /**
-   * Comparison operator, test if this query value does not match the item value
-   *
-   * @method !=
-   * @param  {String} object_value The value to compare
-   * @param  {String} comparison_value The comparison value
-   * @param  {String} wildcard_character The wildcard_character
-   * @return {Boolean} true if not match, false otherwise
-   */
-  this["!="] = function (object_value, comparison_value,
-                         wildcard_character) {
-    return !Query.convertStringTextToRegExp(
-      comparison_value.toString(),
-      wildcard_character || "%"
-    ).test(object_value.toString());
-  };
+/**
+ * Comparison operator, test if this query value matches the item value
+ *
+ * @method =
+ * @param  {String} object_value The value to compare
+ * @param  {String} comparison_value The comparison value
+ * @param  {String} wildcard_character The wildcard_character
+ * @return {Boolean} true if match, false otherwise
+ */
+SimpleQuery.prototype["="] = function (object_value, comparison_value,
+                      wildcard_character) {
+  return convertStringToRegExp(
+    comparison_value.toString(),
+    wildcard_character || "%"
+  ).test(object_value.toString());
+};
 
-  /**
-   * Comparison operator, test if this query value is lower than the item value
-   *
-   * @method <
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if lower, false otherwise
-   */
-  this["<"] = function (object_value, comparison_value) {
-    return object_value < comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value does not match the item value
+ *
+ * @method !=
+ * @param  {String} object_value The value to compare
+ * @param  {String} comparison_value The comparison value
+ * @param  {String} wildcard_character The wildcard_character
+ * @return {Boolean} true if not match, false otherwise
+ */
+SimpleQuery.prototype["!="] = function (object_value, comparison_value,
+                       wildcard_character) {
+  return !convertStringToRegExp(
+    comparison_value.toString(),
+    wildcard_character || "%"
+  ).test(object_value.toString());
+};
 
-  /**
-   * Comparison operator, test if this query value is equal or lower than the
-   * item value
-   *
-   * @method <=
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if equal or lower, false otherwise
-   */
-  this["<="] = function (object_value, comparison_value) {
-    return object_value <= comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value is lower than the item value
+ *
+ * @method <
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if lower, false otherwise
+ */
+SimpleQuery.prototype["<"] = function (object_value, comparison_value) {
+  return object_value < comparison_value;
+};
 
-  /**
-   * Comparison operator, test if this query value is greater than the item
-   * value
-   *
-   * @method >
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if greater, false otherwise
-   */
-  this[">"] = function (object_value, comparison_value) {
-    return object_value > comparison_value;
-  };
+/**
+ * Comparison operator, test if this query value is equal or lower than the
+ * item value
+ *
+ * @method <=
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if equal or lower, false otherwise
+ */
+SimpleQuery.prototype["<="] = function (object_value, comparison_value) {
+  return object_value <= comparison_value;
+};
 
-  /**
-   * Comparison operator, test if this query value is equal or greater than the
-   * item value
-   *
-   * @method >=
-   * @param  {Number, String} object_value The value to compare
-   * @param  {Number, String} comparison_value The comparison value
-   * @return {Boolean} true if equal or greater, false otherwise
-   */
-  this[">="] = function (object_value, comparison_value) {
-    return object_value >= comparison_value;
-  };
-});
+/**
+ * Comparison operator, test if this query value is greater than the item
+ * value
+ *
+ * @method >
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if greater, false otherwise
+ */
+SimpleQuery.prototype[">"] = function (object_value, comparison_value) {
+  return object_value > comparison_value;
+};
+
+/**
+ * Comparison operator, test if this query value is equal or greater than the
+ * item value
+ *
+ * @method >=
+ * @param  {Number, String} object_value The value to compare
+ * @param  {Number, String} comparison_value The comparison value
+ * @return {Boolean} true if equal or greater, false otherwise
+ */
+SimpleQuery.prototype[">="] = function (object_value, comparison_value) {
+  return object_value >= comparison_value;
+};
 
 query_class_dict.simple = SimpleQuery;
 
diff --git a/src/queries/tool.js b/src/queries/tool.js
index bbda34a..be0e38f 100644
--- a/src/queries/tool.js
+++ b/src/queries/tool.js
@@ -1,102 +1,6 @@
 /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
 /*global _export: true */
 
-/**
- * Create a class, manage inheritance, static methods,
- * protected attributes and can hide methods or/and secure methods
- *
- * @param  {Class} Class Classes to inherit from (0..n). The last class
- *                       parameter will inherit from the previous one, and so on
- * @param  {Object} option Class option (0..n)
- * @param  {Boolean} [option.secure_methods=false] Make methods not configurable
- *                                                 and not writable
- * @param  {Boolean} [option.hide_methods=false] Make methods not enumerable
- * @param  {Boolean} [option.secure_static_methods=true] Make static methods not
- *                                                       configurable and not
- *                                                       writable
- * @param  {Boolean} [option.hide_static_methods=false] Make static methods not
- *                                                      enumerable
- * @param  {Object} [option.static_methods={}] Object of static methods
- * @param  {Function} constructor The new class constructor
- * @return {Class} The new class
- */
-function newClass() {
-  var j, k, constructors = [], option, new_class;
-
-  for (j = 0; j < arguments.length; j += 1) {
-    if (typeof arguments[j] === "function") {
-      constructors.push(arguments[j]);
-    } else if (typeof arguments[j] === "object") {
-      option = option || {};
-      for (k in arguments[j]) {
-        if (arguments[j].hasOwnProperty(k)) {
-          option[k] = arguments[j][k];
-        }
-      }
-    }
-  }
-
-  function postObjectCreation(that) {
-    // modify the object according to 'option'
-    var key;
-    if (option) {
-      for (key in that) {
-        if (that.hasOwnProperty(key)) {
-          if (typeof that[key] === "function") {
-            Object.defineProperty(that, key, {
-              "configurable": option.secure_methods ? false : true,
-              "enumerable": option.hide_methods ? false : true,
-              "writable": option.secure_methods ? false : true,
-              "value": that[key]
-            });
-          }
-        }
-      }
-    }
-  }
-
-  function postClassCreation(that) {
-    // modify the object according to 'option'
-    var key;
-    if (option) {
-      for (key in that) {
-        if (that.hasOwnProperty(key)) {
-          if (typeof that[key] === "function") {
-            Object.defineProperty(that, key, {
-              "configurable": option.secure_static_methods ===
-                false ? true : false,
-              "enumerable": option.hide_static_methods ? false : true,
-              "writable": option.secure_static_methods === false ? true : false,
-              "value": that[key]
-            });
-          }
-        }
-      }
-    }
-  }
-
-  new_class = function (spec, my) {
-    var i;
-    spec = spec || {};
-    my = my || {};
-    // don't use forEach !
-    for (i = 0; i < constructors.length; i += 1) {
-      constructors[i].apply(this, [spec, my]);
-    }
-    postObjectCreation(this);
-    return this;
-  };
-  option = option || {};
-  option.static_methods = option.static_methods || {};
-  for (j in option.static_methods) {
-    if (option.static_methods.hasOwnProperty(j)) {
-      new_class[j] = option.static_methods[j];
-    }
-  }
-  postClassCreation(new_class);
-  return new_class;
-}
-
 /**
  * Escapes regexp special chars from a string.
  *
@@ -156,3 +60,113 @@ function deepClone(object) {
   }
   return object;
 }
+
+/**
+ * Inherits the prototype methods from one constructor into another. The
+ * prototype of `constructor` will be set to a new object created from
+ * `superConstructor`.
+ */
+function inherits(constructor, superConstructor) {
+  constructor.super_ = superConstructor;
+  constructor.prototype = Object.create(superConstructor.prototype, {});
+}
+
+/**
+ * Does nothing
+ */
+function emptyFunction() {}
+
+/**
+ * Filter a list of items, modifying them to select only wanted keys. If
+ * `clone` is true, then the method will act on a cloned list.
+ *
+ * @param  {Array} select_option Key list to keep
+ * @param  {Array} list The item list to filter
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function select(select_option, list, clone) {
+  var i, j, new_item;
+  if (clone) {
+    list = deepClone(list);
+  }
+  for (i = 0; i < list.length; i += 1) {
+    new_item = {};
+    for (j = 0; j < select_option.length; j += 1) {
+      new_item[select_option[j]] = list[i][select_option[j]];
+    }
+    for (j in new_item) {
+      if (new_item.hasOwnProperty(j)) {
+        list[i] = new_item;
+        break;
+      }
+    }
+  }
+  return list;
+}
+
+_export('select', select);
+
+/**
+ * Sort a list of items, according to keys and directions. If `clone` is true,
+ * then the method will act on a cloned list.
+ *
+ * @param  {Array} sort_on_option List of couples [key, direction]
+ * @param  {Array} list The item list to sort
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function sortOn(sort_on_option, list, clone) {
+  var sort_index;
+  if (clone) {
+    list = deepClone(list);
+  }
+  for (sort_index = sort_on_option.length - 1; sort_index >= 0;
+       sort_index -= 1) {
+    list.sort(sortFunction(
+      sort_on_option[sort_index][0],
+      sort_on_option[sort_index][1]
+    ));
+  }
+  return list;
+}
+
+_export('sortOn', sortOn);
+
+/**
+ * Limit a list of items, according to index and length. If `clone` is true,
+ * then the method will act on a cloned list.
+ *
+ * @param  {Array} limit_option A couple [from, length]
+ * @param  {Array} list The item list to limit
+ * @param  {Boolean} [clone=false] If true, modifies a clone of the list
+ * @return {Array} The filtered list
+ */
+function limit(limit_option, list, clone) {
+  if (clone) {
+    list = deepClone(list);
+  }
+  list.splice(0, limit_option[0]);
+  if (limit_option[1]) {
+    list.splice(limit_option[1]);
+  }
+  return list;
+}
+
+_export('limit', limit);
+
+/**
+ * Convert a search text to a regexp.
+ *
+ * @param  {String} string The string to convert
+ * @param  {String} [wildcard_character=undefined] The wildcard chararter
+ * @return {RegExp} The search text regexp
+ */
+function convertStringToRegExp(string, wildcard_character) {
+  return new RegExp("^" + stringEscapeRegexpCharacters(string).replace(
+    stringEscapeRegexpCharacters(wildcard_character),
+    '.*'
+  ) + "$");
+}
+
+_export('convertStringToRegExp', convertStringToRegExp);
-- 
2.30.9