From 490ec86bf7334d29b9f8b56393372e8a4129c447 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 23 Oct 2014 10:53:16 -0400 Subject: [PATCH] First basic working state --- Gruntfile.js | 7 +- README.md | 16 +- docs/adapter.js.html | 189 + docs/adapters_mysql.js.html | 190 + docs/adapters_mysql2.js.html | 190 + docs/driver.js.html | 217 +- docs/drivers_mysql.js.html | 203 + docs/drivers_pg.js.html | 188 + docs/es6-polyfill.js.html | 250 + docs/global.html | 598 +- docs/helpers.js.html | 278 +- docs/img/glyphicons-halflings-white.png | Bin 0 -> 8777 bytes docs/img/glyphicons-halflings.png | Bin 0 -> 12799 bytes docs/index.html | 240 +- docs/module-adapter.html | 437 ++ docs/module-adapters_mysql.html | 255 + docs/module-adapters_mysql2.html | 255 + docs/module-driver.html | 1210 +--- docs/module-helpers.html | 772 +-- docs/module-node-query.html | 441 ++ docs/module-query-builder.html | 6471 ++++++++++++++++-- docs/modules.list.html | 241 + docs/mysql.html | 261 + docs/mysql.js.html | 205 +- docs/mysql.js_.html | 193 + docs/mysql2.html | 259 + docs/mysql2.js.html | 201 + docs/node-query.js.html | 208 + docs/pg.html | 261 + docs/pg.js.html | 203 +- docs/query-builder.js.html | 953 ++- docs/scripts/URI.js | 1429 ++++ docs/scripts/bootstrap-dropdown.js | 169 + docs/scripts/bootstrap-tab.js | 144 + docs/scripts/docstrap.lib.js | 9 + docs/scripts/linenumber.js | 30 +- docs/scripts/prettify/Apache-License-2.0.txt | 404 +- docs/scripts/prettify/jquery.min.js | 6 + docs/scripts/prettify/lang-css.js | 23 +- docs/scripts/prettify/prettify.js | 524 +- docs/scripts/sunlight.js | 1157 ++++ docs/scripts/toc.js | 100 + docs/styles/darkstrap.css | 960 +++ docs/styles/jsdoc-default.css | 217 +- docs/styles/prettify-tomorrow.css | 264 +- docs/styles/site.amelia.css | 6369 +++++++++++++++++ docs/styles/site.cerulean.css | 5701 +++++++++++++++ docs/styles/site.cosmo.css | 5944 ++++++++++++++++ docs/styles/site.cyborg.css | 6151 +++++++++++++++++ docs/styles/site.darkstrap.css | 5638 +++++++++++++++ docs/styles/site.flatly.css | 5993 ++++++++++++++++ docs/styles/site.journal.css | 5745 ++++++++++++++++ docs/styles/site.readable.css | 5433 +++++++++++++++ docs/styles/site.simplex.css | 5758 ++++++++++++++++ docs/styles/site.slate.css | 6204 +++++++++++++++++ docs/styles/site.spacelab.css | 5796 ++++++++++++++++ docs/styles/site.spruce.css | 5938 ++++++++++++++++ docs/styles/site.superhero.css | 6106 +++++++++++++++++ docs/styles/site.united.css | 5545 +++++++++++++++ docs/styles/sunlight.dark.css | 345 + docs/styles/sunlight.default.css | 344 + lib/adapter.js | 17 + lib/adapters/mysql.js | 27 + lib/adapters/mysql2.js | 26 + lib/adapters/pg.js | 26 + lib/driver.js | 32 +- lib/drivers/mysql.js | 8 +- lib/drivers/pg.js | 6 +- lib/es6-polyfill.js | 78 + lib/helpers.js | 88 +- lib/node-query.js | 40 +- lib/query-builder.js | 764 ++- package.json | 5 +- tests/adapters/mysql2_test.js | 36 + tests/adapters/mysql_test.js | 35 + tests/adapters/pg_test.js | 37 + tests/base_test.js | 5 +- tests/config.json | 24 + tests/helpers_test.js | 17 + tests/query-builder-base.js | 57 + tests/query-builder_test.js | 10 - tests/sql/mysql.sql | 89 + tests/sql/pgsql.sql | 105 + tests/sql/sqlite.sql | 82 + 84 files changed, 101947 insertions(+), 3505 deletions(-) create mode 100644 docs/adapter.js.html create mode 100644 docs/adapters_mysql.js.html create mode 100644 docs/adapters_mysql2.js.html create mode 100644 docs/drivers_mysql.js.html create mode 100644 docs/drivers_pg.js.html create mode 100644 docs/es6-polyfill.js.html create mode 100644 docs/img/glyphicons-halflings-white.png create mode 100644 docs/img/glyphicons-halflings.png create mode 100644 docs/module-adapter.html create mode 100644 docs/module-adapters_mysql.html create mode 100644 docs/module-adapters_mysql2.html create mode 100644 docs/module-node-query.html create mode 100644 docs/modules.list.html create mode 100644 docs/mysql.html create mode 100644 docs/mysql.js_.html create mode 100644 docs/mysql2.html create mode 100644 docs/mysql2.js.html create mode 100644 docs/node-query.js.html create mode 100644 docs/pg.html create mode 100644 docs/scripts/URI.js create mode 100644 docs/scripts/bootstrap-dropdown.js create mode 100644 docs/scripts/bootstrap-tab.js create mode 100644 docs/scripts/docstrap.lib.js create mode 100644 docs/scripts/prettify/jquery.min.js create mode 100644 docs/scripts/sunlight.js create mode 100644 docs/scripts/toc.js create mode 100644 docs/styles/darkstrap.css create mode 100644 docs/styles/site.amelia.css create mode 100644 docs/styles/site.cerulean.css create mode 100644 docs/styles/site.cosmo.css create mode 100644 docs/styles/site.cyborg.css create mode 100644 docs/styles/site.darkstrap.css create mode 100644 docs/styles/site.flatly.css create mode 100644 docs/styles/site.journal.css create mode 100644 docs/styles/site.readable.css create mode 100644 docs/styles/site.simplex.css create mode 100644 docs/styles/site.slate.css create mode 100644 docs/styles/site.spacelab.css create mode 100644 docs/styles/site.spruce.css create mode 100644 docs/styles/site.superhero.css create mode 100644 docs/styles/site.united.css create mode 100644 docs/styles/sunlight.dark.css create mode 100644 docs/styles/sunlight.default.css create mode 100755 lib/adapter.js create mode 100644 lib/adapters/mysql.js create mode 100644 lib/adapters/mysql2.js create mode 100644 lib/adapters/pg.js create mode 100644 lib/es6-polyfill.js create mode 100644 tests/adapters/mysql2_test.js create mode 100644 tests/adapters/mysql_test.js create mode 100644 tests/adapters/pg_test.js create mode 100644 tests/config.json create mode 100644 tests/helpers_test.js create mode 100644 tests/query-builder-base.js delete mode 100644 tests/query-builder_test.js create mode 100644 tests/sql/mysql.sql create mode 100644 tests/sql/pgsql.sql create mode 100644 tests/sql/sqlite.sql diff --git a/Gruntfile.js b/Gruntfile.js index ec1027d..29655db 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,7 +6,7 @@ module.exports = function(grunt) { pkg: grunt.file.readJSON('package.json'), jsdoc: { dist: { - src: ['lib/*.js', 'lib/drivers/*.js', 'README.md'], + src: ['lib/*.js', 'README.md'], options: { template: 'node_modules/grunt-jsdoc/node_modules/ink-docstrap/template', configure: 'node_modules/grunt-jsdoc/node_modules/ink-docstrap/template/jsdoc.conf.json', @@ -15,7 +15,10 @@ module.exports = function(grunt) { } }, nodeunit: { - all: ['tests/**/*_test.js'] + all: ['tests/**/*_test.js'], + options: { + reporter: 'verbose' + } } }); diff --git a/README.md b/README.md index 61988c3..adbb120 100755 --- a/README.md +++ b/README.md @@ -2,16 +2,22 @@ A node query builder for various SQL databases, based on CodeIgniter's query builder. -### Probable use +### Basic use - var query = require('node-query'); + var nodeQuery = require('node-query'); + + var mysql = ... // Database module connection + + // Three arguments: database type, database connection, database connection library + var query = nodeQuery('mysql', mysql, 'mysql2'); - var res = query - .select('foo') + query.select('foo') .from('bar') .where('x', 3) .orWhere('y', 2) .orderBy('x') .limit(2, 3) - .get(); + .get(function(err, result) { + // Database module result handling + }); diff --git a/docs/adapter.js.html b/docs/adapter.js.html new file mode 100644 index 0000000..2ba1829 --- /dev/null +++ b/docs/adapter.js.html @@ -0,0 +1,189 @@ + + + + + + DocStrap Source: adapter.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: adapter.js

+ +
+
+
'use strict';
+
+/** @module adapter */
+module.exports = {
+
+	/**
+	 * Run the sql query as a prepared statement
+	 *
+	 * @param {String} sql - The sql with placeholders
+	 * @param {Array} params - The values to insert into the query
+	 * @param {Function} callback - Callback to run when a response is recieved
+	 * @return void
+	 */
+	execute: function(sql, params, callback) {
+		throw new Error("Correct adapter not defined for query execution");
+	}
+};
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/adapters_mysql.js.html b/docs/adapters_mysql.js.html new file mode 100644 index 0000000..a177740 --- /dev/null +++ b/docs/adapters_mysql.js.html @@ -0,0 +1,190 @@ + + + + + + DocStrap Source: adapters/mysql.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: adapters/mysql.js

+ +
+
+
/** @module adapters/mysql */
+
+'use strict';
+
+var adapter = require('../lib/adapter.js');
+
+module.exports = function(instance) {
+
+	adapter.execute = function(sql, params, callback) {
+		instance.query(sql, params, callback);
+	};
+
+	return adapter;
+}
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/adapters_mysql2.js.html b/docs/adapters_mysql2.js.html new file mode 100644 index 0000000..b064cd0 --- /dev/null +++ b/docs/adapters_mysql2.js.html @@ -0,0 +1,190 @@ + + + + + + DocStrap Source: adapters/mysql2.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: adapters/mysql2.js

+ +
+
+
/** @module adapters/mysql2 */
+
+'use strict';
+
+var adapter = require('../lib/adapter.js');
+
+module.exports = function(instance) {
+
+	adapter.execute = function(sql, params, callback) {
+		instance.execute(sql, params, callback);
+	};
+
+	return adapter;
+}
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/driver.js.html b/docs/driver.js.html index e4e3df2..e97621b 100644 --- a/docs/driver.js.html +++ b/docs/driver.js.html @@ -1,42 +1,84 @@ + - - JSDoc: Source: driver.js - - - - - - + + DocStrap Source: driver.js + + + + + + +
+ - -
-
-
/** @module driver */
+	
-"use strict"; + +
+ +
+ + + +

Source: driver.js

+ +
+
+
'use strict';
 
 var helpers = require('./helpers');
 
 /**
  * Base Database Driver
  *
- * @type {{identifierChar: string, quoteIdentifiers: quoteIdentifiers}}
+ * @module driver
  */
-module.exports = {
+var d = {
 	identifierChar: '"',
 	tablePrefix: null,
 
@@ -48,8 +90,8 @@ module.exports = {
 	 * @private
 	 */
 	_quote: function(str) {
-		return (helpers.isString(str) && ! (str.startsWith(this.identifierChar) || str.endsWith(this.identifierChar)))
-			? this.identifierChar + str + this.identifierChar
+		return (helpers.isString(str) && ! (str.startsWith(d.identifierChar) || str.endsWith(d.identifierChar)))
+			? d.identifierChar + str + d.identifierChar
 			: str;
 	},
 
@@ -61,12 +103,12 @@ module.exports = {
 	 * @private
 	 */
 	_prefix: function(str) {
-		if (str.startsWith(this.prefix))
+		if (str.startsWith(d.prefix))
 		{
 			return str;
 		}
 
-		return this.prefix + str;
+		return d.prefix + str;
 	},
 
 	/**
@@ -95,7 +137,7 @@ module.exports = {
 	 * @return {String}
 	 */
 	prefixTable: function(table) {
-		if (this.tablePrefix)
+		if (d.tablePrefix)
 		{
 			// Split identifier by period, will split into:
 			// database.schema.table OR
@@ -106,7 +148,7 @@ module.exports = {
 			var segments = idents.length;
 
 			// Add the database prefix
-			idents[segments - 1] = this._prefix(idents[segments - 1]);
+			idents[segments - 1] = d._prefix(idents[segments - 1]);
 
 			table = idents.join('.');
 		}
@@ -121,10 +163,10 @@ module.exports = {
 	 * @return {String}
 	 */
 	quoteTable: function(table) {
-		table = this.prefixTable(table);
+		table = d.prefixTable(table);
 
 		// Quote after prefix
-		return this.quoteIdentifiers(table);
+		return d.quoteIdentifiers(table);
 	},
 
 	/**
@@ -139,40 +181,121 @@ module.exports = {
 		// Recurse for arrays of identifiiers
 		if (Array.isArray(str))
 		{
-			return str.map(this.quoteIdentifiers);
+			return str.map(d.quoteIdentifiers);
 		}
 
 		// Handle commas
 		str = helpers.splitTrim(',', str);
 
 		// Split identifiers by period
-		hiers = str.split('.').map(String.trim).map(this._quote);
+		hiers = str.split('.').map(d._quote);
 		raw = hiers.join('.');
 
 		// TODO: fix functions
 
 		return raw;
 	}
-};
-
-
+}; + +module.exports = d;
+
+
+ + + + + +
+ +
+ + + + +
+ + + + + + + + + + + - - + + -
- - - - - diff --git a/docs/drivers_mysql.js.html b/docs/drivers_mysql.js.html new file mode 100644 index 0000000..7b12565 --- /dev/null +++ b/docs/drivers_mysql.js.html @@ -0,0 +1,203 @@ + + + + + + DocStrap Source: drivers/mysql.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: drivers/mysql.js

+ +
+
+
"use strict";
+
+/**
+ * Driver for MySQL databases
+ *
+ * @returns {driver}
+ */
+module.exports = function() {
+	var driver = require('../driver'),
+		helpers = require('../helpers');
+
+	driver.identifierChar = '`';
+
+	/**
+	 * Override default limit method because mysql likes to be different
+	 */
+	driver.limit = function(sql, limit, offset) {
+		if ( ! helpers.isNumber(offset))
+		{
+			return sql += " LIMIT " + limit;
+		}
+
+		return sql += " LIMIT " + offset + "," + limit;
+	};
+
+	return driver;
+};
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/drivers_pg.js.html b/docs/drivers_pg.js.html new file mode 100644 index 0000000..18f084d --- /dev/null +++ b/docs/drivers_pg.js.html @@ -0,0 +1,188 @@ + + + + + + DocStrap Source: drivers/pg.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: drivers/pg.js

+ +
+
+
"use strict";
+
+/**
+ * Driver for PostgreSQL databases
+ *
+ * @returns {driver}
+ */
+module.exports = function() {
+	var driver = require('../driver');
+
+	return driver;
+};
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/es6-polyfill.js.html b/docs/es6-polyfill.js.html new file mode 100644 index 0000000..e757bce --- /dev/null +++ b/docs/es6-polyfill.js.html @@ -0,0 +1,250 @@ + + + + + + DocStrap Source: es6-polyfill.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: es6-polyfill.js

+ +
+
+
/**
+ * Polyfills for very handy methods that are standardized, but not fully implemented in Javascript engines
+ */
+module.exports = (function() {
+	if (!Array.prototype.fill) {
+		Array.prototype.fill = function(value) {
+			// Steps 1-2.
+			if (this == null) {
+				throw new TypeError('this is null or not defined');
+			}
+
+			var O = Object(this);
+
+			// Steps 3-5.
+			var len = O.length >>> 0;
+
+			// Steps 6-7.
+			var start = arguments[1];
+			var relativeStart = start >> 0;
+
+			// Step 8.
+			var k = relativeStart < 0 ?
+				Math.max(len + relativeStart, 0) :
+				Math.min(relativeStart, len);
+
+			// Steps 9-10.
+			var end = arguments[2];
+			var relativeEnd = end === undefined ?
+				len : end >> 0;
+
+			// Step 11.
+			var final = relativeEnd < 0 ?
+				Math.max(len + relativeEnd, 0) :
+				Math.min(relativeEnd, len);
+
+			// Step 12.
+			while (k < final) {
+				O[k] = value;
+				k++;
+			}
+
+			// Step 13.
+			return O;
+		};
+	}
+
+	if ( !String.prototype.contains ) {
+		String.prototype.contains = function() {
+			return String.prototype.indexOf.apply( this, arguments ) !== -1;
+		};
+	}
+
+	if (!String.prototype.startsWith) {
+		Object.defineProperty(String.prototype, 'startsWith', {
+			enumerable: false,
+			configurable: false,
+			writable: false,
+			value: function (searchString, position) {
+				position = position || 0;
+				return this.lastIndexOf(searchString, position) === position;
+			}
+		});
+	}
+
+	if (!String.prototype.endsWith) {
+		Object.defineProperty(String.prototype, 'endsWith', {
+			value: function (searchString, position) {
+				var subjectString = this.toString();
+				if (position === undefined || position > subjectString.length) {
+					position = subjectString.length;
+				}
+				position -= searchString.length;
+				var lastIndex = subjectString.indexOf(searchString, position);
+				return lastIndex !== -1 && lastIndex === position;
+			}
+		});
+	}
+}());
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/global.html b/docs/global.html index d120339..0050eee 100644 --- a/docs/global.html +++ b/docs/global.html @@ -1,183 +1,445 @@ + - - JSDoc: Global - - - - - - + + DocStrap Global + + + + + + +
+ + +
+ + +
+ +
+ + + +

Global

+
+ +
+

+ +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

init(drivername, connObject, connLib) → {queryBuilder}

+ + +
+
+ + +
+

Create a query builder object

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
drivername + + +String + + + +

The name of the database type, eg. mysql or pg

connObject + + +Object + + + +

A connection object from the database library you are connecting with

connLib + + +String + + + +

The name of the db connection library you are using, eg. mysql or mysql2

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +queryBuilder + + +
+
+ + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + -
- -
-

- -

- -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - -

Members

- -
- -
-

module:driver :Object

- - -
-
- -
- Base Database Driver -
- - - -
Type:
-
    -
  • - -Object + + -
  • -
- + + - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - - - - - -
- -
- - - - - - - - -
- - - - - \ No newline at end of file diff --git a/docs/helpers.js.html b/docs/helpers.js.html index cdc439b..d659812 100644 --- a/docs/helpers.js.html +++ b/docs/helpers.js.html @@ -1,61 +1,90 @@ + - - JSDoc: Source: helpers.js - - - - - - + + DocStrap Source: helpers.js + + + + + + +
+ - -
-
-
/** @module helpers */
+	
+ + +
+ +
+ + + +

Source: helpers.js

+ +
+
+
/** @module helpers */
 
 "use strict";
 
-if (!String.prototype.startsWith) {
-	Object.defineProperty(String.prototype, 'startsWith', {
-		enumerable: false,
-		configurable: false,
-		writable: false,
-		value: function (searchString, position) {
-			position = position || 0;
-			return this.lastIndexOf(searchString, position) === position;
-		}
-	});
-}
+require('./es6-polyfill');
 
-if (!String.prototype.endsWith) {
-	Object.defineProperty(String.prototype, 'endsWith', {
-		value: function (searchString, position) {
-			var subjectString = this.toString();
-			if (position === undefined || position > subjectString.length) {
-				position = subjectString.length;
-			}
-			position -= searchString.length;
-			var lastIndex = subjectString.indexOf(searchString, position);
-			return lastIndex !== -1 && lastIndex === position;
-		}
-	});
-}
-
-module.exports = {
+var h = {
+	/**
+	 * Wrap String.prototype.trim in a way that is easily mappable
+	 *
+	 * @param {String} str - The string to trim
+	 * @return {String} - The trimmed string
+	 */
+	stringTrim: function(str) {
+		return str.trim();
+	},
 	/**
 	 * Split a string by a character, trim the string
 	 * and rejoin the string
@@ -65,45 +94,150 @@ module.exports = {
 	 * @return {String}
 	 */
 	splitTrim: function(char, string) {
-		return string.split(char).map(String.trim).join(char);
+		return string.split(char).map(h.stringTrim).join(char);
 	},
 	/**
-	 * Determine whether an object is a string
+	 * Get the type of the variable passed
+	 *
+	 * @see https://techblog.badoo.com/blog/2013/11/01/type-checking-in-javascript/
+	 * @see http://toddmotto.com/understanding-javascript-types-and-reliable-type-checking/
+	 * @param {mixed} o
+	 * @return {String}
+	 */
+	type: function (o) {
+	    var type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
+
+	    // handle NaN and Infinity
+	    if (type === 'number') {
+	        if (isNaN(o)) {
+	            return 'nan';
+	        }
+	        if (!isFinite(o)) {
+	            return 'infinity';
+	        }
+	    }
+
+	    return type;
+	},
+	/**
+	 * Determine whether an object is scalar
+	 *
 	 * @param {mixed} obj
 	 * @return {bool}
 	 */
-	isString: function(obj) {
-		return (typeof obj === 'string' || obj instanceof String);
-	},
-	/**
-	 * Determine whether an object is numeric
-	 * @param {mixed} obj
-	 * @return {bool}
-	 */
-	isNumber: function(obj) {
-		return ! isNaN(parseFloat(obj)) && isFinite(obj);
+	isScalar: function(obj) {
+		var scalar = ['string', 'number', 'boolean'];
+		return scalar.indexOf(h.type(obj)) !== -1;
 	}
 };
-
-
-
+ +// Define an 'is' method for each type +var types = ['Null','Undefined','Object','Array','String','Number','Boolean','Function','RegExp','NaN','Infinite']; +types.forEach(function (t) { + h['is' + t] = function (o) { + return h.type(o) === t.toLowerCase(); + }; +}); + +module.exports = h;
+
+
+ + + + + +
+ +
+ + + + +
+ + + + + + + + + + + - - + + -
- - - - - diff --git a/docs/img/glyphicons-halflings-white.png b/docs/img/glyphicons-halflings-white.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf6484a29d8da269f9bc874b25493a45fae3bae GIT binary patch literal 8777 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 B7G?kd literal 0 HcmV?d00001 diff --git a/docs/img/glyphicons-halflings.png b/docs/img/glyphicons-halflings.png new file mode 100644 index 0000000000000000000000000000000000000000..a9969993201f9cee63cf9f49217646347297b643 GIT binary patch literal 12799 zcma*OWmH^Ivn@*S;K3nSf_t!#;0f+&pm7Po8`nk}2q8f5;M%x$SdAkd9FAvlc$ zx660V9e3Ox@4WZ^?7jZ%QFGU-T~%||Ug4iK6bbQY@zBuF2$hxOw9wF=A)nUSxR_5@ zEX>HBryGrjyuOFFv$Y4<+|3H@gQfEqD<)+}a~mryD|1U9*I_FOG&F%+Ww{SJ-V2BR zjt<81Ek$}Yb*95D4RS0HCps|uLyovt;P05hchQb-u2bzLtmog&f2}1VlNhxXV);S9 zM2buBg~!q9PtF)&KGRgf3#z7B(hm5WlNClaCWFs!-P!4-u*u5+=+D|ZE9e`KvhTHT zJBnLwGM%!u&vlE%1ytJ=!xt~y_YkFLQb6bS!E+s8l7PiPGSt9xrmg?LV&&SL?J~cI zS(e9TF1?SGyh+M_p@o1dyWu7o7_6p;N6hO!;4~ z2B`I;y`;$ZdtBpvK5%oQ^p4eR2L)BH>B$FQeC*t)c`L71gXHPUa|vyu`Bnz)H$ZcXGve(}XvR!+*8a>BLV;+ryG1kt0=)ytl zNJxFUN{V7P?#|Cp85QTa@(*Q3%K-R(Pkv1N8YU*(d(Y}9?PQ(j;NzWoEVWRD-~H$=f>j9~PN^BM2okI(gY-&_&BCV6RP&I$FnSEM3d=0fCxbxA6~l>54-upTrw zYgX@%m>jsSGi`0cQt6b8cX~+02IghVlNblR7eI;0ps}mpWUcxty1yG56C5rh%ep(X z?)#2d?C<4t-KLc*EAn>>M8%HvC1TyBSoPNg(4id~H8JwO#I)Bf;N*y6ai6K9_bA`4 z_g9(-R;qyH&6I$`b42v|0V3Z8IXN*p*8g$gE98+JpXNY+jXxU0zsR^W$#V=KP z3AEFp@OL}WqwOfsV<)A^UTF4&HF1vQecz?LWE@p^Z2){=KEC_3Iopx_eS42>DeiDG zWMXGbYfG~W7C8s@@m<_?#Gqk;!&)_Key@^0xJxrJahv{B&{^!>TV7TEDZlP|$=ZCz zmX=ZWtt4QZKx**)lQQoW8y-XLiOQy#T`2t}p6l*S`68ojyH@UXJ-b~@tN`WpjF z%7%Yzv807gsO!v=!(2uR)16!&U5~VPrPHtGzUU?2w(b1Xchq}(5Ed^G|SD7IG+kvgyVksU) z(0R)SW1V(>&q2nM%Z!C9=;pTg!(8pPSc%H01urXmQI6Gi^dkYCYfu6b4^tW))b^U+ z$2K&iOgN_OU7n#GC2jgiXU{caO5hZt0(>k+c^(r><#m|#J^s?zA6pi;^#*rp&;aqL zRcZi0Q4HhVX3$ybclxo4FFJW*`IV`)Bj_L3rQe?5{wLJh168Ve1jZv+f1D}f0S$N= zm4i|9cEWz&C9~ZI3q*gwWH^<6sBWuphgy@S3Qy?MJiL>gwd|E<2h9-$3;gT9V~S6r z)cAcmE0KXOwDA5eJ02-75d~f?3;n7a9d_xPBJaO;Z)#@s7gk5$Qn(Fc^w@9c5W0zY z59is0?Mt^@Rolcn{4%)Ioat(kxQH6}hIykSA)zht=9F_W*D#<}N(k&&;k;&gKkWIL z0Of*sP=X(Uyu$Pw;?F@?j{}=>{aSHFcii#78FC^6JGrg-)!)MV4AKz>pXnhVgTgx8 z1&5Y=>|8RGA6++FrSy=__k_imx|z-EI@foKi>tK0Hq2LetjUotCgk2QFXaej!BWYL zJc{fv(&qA7UUJ|AXLc5z*_NW#yWzKtl(c8mEW{A>5Hj^gfZ^HC9lQNQ?RowXjmuCj4!!54Us1=hY z0{@-phvC}yls!PmA~_z>Y&n&IW9FQcj}9(OLO-t^NN$c0o}YksCUWt|DV(MJB%%Sr zdf}8!9ylU2TW!=T{?)g-ojAMKc>3pW;KiZ7f0;&g)k}K^#HBhE5ot)%oxq$*$W@b# zg4p<Ou`ME|Kd1WHK@8 zzLD+0(NHWa`B{em3Ye?@aVsEi>y#0XVZfaFuq#;X5C3{*ikRx7UY4FF{ZtNHNO?A_ z#Q?hwRv~D8fPEc%B5E-ZMI&TAmikl||EERumQCRh7p;)>fdZMxvKq;ky0}7IjhJph zW*uuu*(Y6)S;Od--8uR^R#sb$cmFCnPcj9PPCWhPN;n`i1Q#Qn>ii z{WR|0>8F`vf&#E(c2NsoH=I7Cd-FV|%(7a`i}gZw4N~QFFG2WtS^H%@c?%9UZ+kez z;PwGgg_r6V>Kn5n(nZ40P4qMyrCP3bDkJp@hp6&X3>gzC>=f@Hsen<%I~7W+x@}b> z0}Et*vx_50-q@PIV=(3&Tbm}}QRo*FP2@)A#XX-8jYspIhah`9ukPBr)$8>Tmtg&R z?JBoH17?+1@Y@r>anoKPQ}F8o9?vhcG79Cjv^V6ct709VOQwg{c0Q#rBSsSmK3Q;O zBpNihl3S0_IGVE)^`#94#j~$;7+u870yWiV$@={|GrBmuz4b)*bCOPkaN0{6$MvazOEBxFdKZDlbVvv{8_*kJ zfE6C`4&Kkz<5u%dEdStd85-5UHG5IOWbo8i9azgg#zw-(P1AA049hddAB*UdG3Vn0 zX`OgM+EM|<+KhJ<=k?z~WA5waVj?T9eBdfJGebVifBKS1u<$#vl^BvSg)xsnT5Aw_ZY#}v*LXO#htB>f}x3qDdDHoFeb zAq7;0CW;XJ`d&G*9V)@H&739DpfWYzdQt+Kx_E1K#Cg1EMtFa8eQRk_JuUdHD*2;W zR~XFnl!L2A?48O;_iqCVr1oxEXvOIiN_9CUVTZs3C~P+11}ebyTRLACiJuMIG#`xP zKlC|E(S@QvN+%pBc6vPiQS8KgQAUh75C0a2xcPQDD$}*bM&z~g8+=9ltmkT$;c;s z5_=8%i0H^fEAOQbHXf0;?DN5z-5+1 zDxj50yYkz4ox9p$HbZ|H?8ukAbLE^P$@h}L%i6QVcY>)i!w=hkv2zvrduut%!8>6b zcus3bh1w~L804EZ*s96?GB&F7c5?m?|t$-tp2rKMy>F*=4;w*jW}^;8v`st&8)c; z2Ct2{)?S(Z;@_mjAEjb8x=qAQvx=}S6l9?~H?PmP`-xu;ME*B8sm|!h@BX4>u(xg_ zIHmQzp4Tgf*J}Y=8STR5_s)GKcmgV!$JKTg@LO402{{Wrg>#D4-L%vjmtJ4r?p&$F!o-BOf7ej~ z6)BuK^^g1b#(E>$s`t3i13{6-mmSp7{;QkeG5v}GAN&lM2lQT$@(aQCcFP(%UyZbF z#$HLTqGT^@F#A29b0HqiJsRJAlh8kngU`BDI6 zJUE~&!cQ*&f95Ot$#mxU5+*^$qg_DWNdfu+1irglB7yDglzH()2!@#rpu)^3S8weW z_FE$=j^GTY*|5SH95O8o8W9FluYwB=2PwtbW|JG6kcV^dMVmX(wG+Otj;E$%gfu^K z!t~<3??8=()WQSycsBKy24>NjRtuZ>zxJIED;YXaUz$@0z4rl+TW zWxmvM$%4jYIpO>j5k1t1&}1VKM~s!eLsCVQ`TTjn3JRXZD~>GM z$-IT~(Y)flNqDkC%DfbxaV9?QuWCV&-U1yzrV@0jRhE;)ZO0=r-{s@W?HOFbRHDDV zq;eLo+wOW;nI|#mNf(J?RImB9{YSO2Y`9825Lz#u4(nk3)RGv3X8B(A$TsontJ8L! z9JP^eWxtKC?G8^xAZa1HECx*rp35s!^%;&@Jyk)NexVc)@U4$^X1Dag6`WKs|(HhZ#rzO2KEw3xh~-0<;|zcs0L>OcO#YYX{SN8m6`9pp+ zQG@q$I)T?aoe#AoR@%om_#z=c@ych!bj~lV13Qi-xg$i$hXEAB#l=t7QWENGbma4L zbBf*X*4oNYZUd_;1{Ln_ZeAwQv4z?n9$eoxJeI?lU9^!AB2Y~AwOSq67dT9ADZ)s@ zCRYS7W$Zpkdx$3T>7$I%3EI2ik~m!f7&$Djpt6kZqDWZJ-G{*_eXs*B8$1R4+I}Kf zqniwCI64r;>h2Lu{0c(#Atn)%E8&)=0S4BMhq9$`vu|Ct;^ur~gL`bD>J@l)P$q_A zO7b3HGOUG`vgH{}&&AgrFy%K^>? z>wf**coZ2vdSDcNYSm~dZ(vk6&m6bVKmVgrx-X<>{QzA!)2*L+HLTQz$e8UcB&Djq zl)-%s$ZtUN-R!4ZiG=L0#_P=BbUyH+YPmFl_ogkkQ$=s@T1v}rNnZ^eMaqJ|quc+6 z*ygceDOrldsL30w`H;rNu+IjlS+G~p&0SawXCA1+D zC%cZtjUkLNq%FadtHE?O(yQTP486A{1x<{krq#rpauNQaeyhM3*i0%tBpQHQo-u)x z{0{&KS`>}vf2_}b160XZO2$b)cyrHq7ZSeiSbRvaxnKUH{Q`-P(nL&^fcF2){vhN- zbX&WEjP7?b4A%0y6n_=m%l00uZ+}mCYO(!x?j$+O$*TqoD_Q5EoyDJ?w?^UIa491H zE}87(bR`X;@u#3Qy~9wWdWQIg1`cXrk$x9=ccR|RY1~%{fAJ@uq@J3e872x0v$hmv ze_KcL(wM|n0EOp;t{hKoohYyDmYO;!`7^Lx;0k=PWPGZpI>V5qYlzjSL_(%|mud50 z7#{p97s`U|Sn$WYF>-i{i4`kzlrV6a<}=72q2sAT7Zh{>P%*6B;Zl;~0xWymt10Mo zl5{bmR(wJefJpNGK=fSRP|mpCI-)Nf6?Pv==FcFmpSwF1%CTOucV{yqxSyx4Zws3O z8hr5Uyd%ezIO7?PnEO0T%af#KOiXD$e?V&OX-B|ZX-YsgSs%sv-6U+sLPuz{D4bq| zpd&|o5tNCmpT>(uIbRf?8c}d3IpOb3sn6>_dr*26R#ev<_~vi)wleW$PX|5)$_ z+_|=pi(0D(AB_sjQ;sQQSM&AWqzDO1@NHw;C9cPdXRKRI#@nUW)CgFxzQ1nyd!+h& zcjU!U=&u|>@}R(9D$%lu2TlV>@I2-n@fCr5PrZNVyKWR7hm zWjoy^p7v8m#$qN0K#8jT- zq`mSirDZDa1Jxm;Rg3rAPhC)LcI4@-RvKT+@9&KsR3b0_0zuM!Fg7u>oF>3bzOxZPU&$ab$Z9@ zY)f7pKh22I7ZykL{YsdjcqeN++=0a}elQM-4;Q)(`Ep3|VFHqnXOh14`!Bus& z9w%*EWK6AiAM{s$6~SEQS;A>ey$#`7)khZvamem{P?>k)5&7Sl&&NXKk}o!%vd;-! zpo2p-_h^b$DNBO>{h4JdGB=D>fvGIYN8v&XsfxU~VaefL?q} z3ekM?iOKkCzQHkBkhg=hD!@&(L}FcHKoa zbZ7)H1C|lHjwEb@tu=n^OvdHOo7o+W`0-y3KdP#bb~wM=Vr_gyoEq|#B?$&d$tals ziIs-&7isBpvS|CjC|7C&3I0SE?~`a%g~$PI%;au^cUp@ER3?mn-|vyu!$7MV6(uvt z+CcGuM(Ku2&G0tcRCo7#D$Dirfqef2qPOE5I)oCGzmR5G!o#Q~(k~)c=LpIfrhHQk zeAva6MilEifE7rgP1M7AyWmLOXK}i8?=z2;N=no)`IGm#y%aGE>-FN zyXCp0Sln{IsfOBuCdE*#@CQof%jzuU*jkR*Su3?5t}F(#g0BD0Zzu|1MDes8U7f9; z$JBg|mqTXt`muZ8=Z`3wx$uizZG_7>GI7tcfOHW`C2bKxNOR)XAwRkLOaHS4xwlH4 zDpU29#6wLXI;H?0Se`SRa&I_QmI{zo7p%uveBZ0KZKd9H6@U?YGArbfm)D*^5=&Rp z`k{35?Z5GbZnv>z@NmJ%+sx=1WanWg)8r}C_>EGR8mk(NR$pW<-l8OTU^_u3M@gwS z7}GGa1)`z5G|DZirw;FB@VhH7Dq*0qc=|9lLe{w2#`g+_nt>_%o<~9(VZe=zI*SSz4w43-_o>4E4`M@NPKTWZuQJs)?KXbWp1M zimd5F;?AP(LWcaI-^Sl{`~>tmxsQB9Y$Xi*{Zr#py_+I$vx7@NY`S?HFfS!hUiz$a z{>!&e1(16T!Om)m)&k1W#*d#GslD^4!TwiF2WjFBvi=Ms!ADT)ArEW6zfVuIXcXVk z>AHjPADW+mJzY`_Ieq(s?jbk4iD2Rb8*V3t6?I+E06(K8H!!xnDzO%GB;Z$N-{M|B zeT`jo%9)s%op*XZKDd6*)-^lWO{#RaIGFdBH+;XXjI(8RxpBc~azG1H^2v7c^bkFE zZCVPE+E*Q=FSe8Vm&6|^3ki{9~qafiMAf7i4APZg>b%&5>nT@pHH z%O*pOv(77?ZiT{W zBibx}Q12tRc7Py1NcZTp`Q4ey%T_nj@1WKg5Fz_Rjl4wlJQj)rtp8yL3r!Shy zvZvnmh!tH4T6Js-?vI0<-rzzl{mgT*S0d_7^AU_8gBg^03o-J=p(1o6kww2hx|!%T z-jqp}m^G*W?$!R#M%Ef?&2jYxmx+lXWZszpI4d$pUN`(S)|*c^CgdwY>Fa>> zgGBJhwe8y#Xd*q0=@SLEgPF>+Qe4?%E*v{a`||luZ~&dqMBrRfJ{SDMaJ!s_;cSJp zSqZHXIdc@@XteNySUZs^9SG7xK`8=NBNM)fRVOjw)D^)w%L2OPkTQ$Tel-J)GD3=YXy+F4in(ILy*A3m@3o73uv?JC}Q>f zrY&8SWmesiba0|3X-jmlMT3 z*ST|_U@O=i*sM_*48G)dgXqlwoFp5G6qSM3&%_f_*n!PiT>?cNI)fAUkA{qWnqdMi+aNK_yVQ&lx4UZknAc9FIzVk% zo6JmFH~c{_tK!gt4+o2>)zoP{sR}!!vfRjI=13!z5}ijMFQ4a4?QIg-BE4T6!#%?d&L;`j5=a`4is>U;%@Rd~ zXC~H7eGQhhYWhMPWf9znDbYIgwud(6$W3e>$W4$~d%qoJ z+JE`1g$qJ%>b|z*xCKenmpV$0pM=Gl-Y*LT8K+P)2X#;XYEFF4mRbc~jj?DM@(1e`nL=F4Syv)TKIePQUz)bZ?Bi3@G@HO$Aps1DvDGkYF50O$_welu^cL7;vPiMGho74$;4fDqKbE{U zd1h{;LfM#Fb|Z&uH~Rm_J)R~Vy4b;1?tW_A)Iz#S_=F|~pISaVkCnQ0&u%Yz%o#|! zS-TSg87LUfFSs{tTuM3$!06ZzH&MFtG)X-l7>3)V?Txuj2HyG*5u;EY2_5vU0ujA? zHXh5G%6e3y7v?AjhyX79pnRBVr}RmPmtrxoB7lkxEzChX^(vKd+sLh?SBic=Q)5nA zdz7Mw3_iA>;T^_Kl~?1|5t%GZ;ki_+i>Q~Q1EVdKZ)$Sh3LM@ea&D~{2HOG++7*wF zAC6jW4>fa~!Vp5+$Z{<)Qxb|{unMgCv2)@%3j=7)Zc%U<^i|SAF88s!A^+Xs!OASYT%7;Jx?olg_6NFP1475N z#0s<@E~FI}#LNQ{?B1;t+N$2k*`K$Hxb%#8tRQi*Z#No0J}Pl;HWb){l7{A8(pu#@ zfE-OTvEreoz1+p`9sUI%Y{e5L-oTP_^NkgpYhZjp&ykinnW;(fu1;ttpSsgYM8ABX4dHe_HxU+%M(D=~) zYM}XUJ5guZ;=_ZcOsC`_{CiU$zN3$+x&5C`vX-V3`8&RjlBs^rf00MNYZW+jCd~7N z%{jJuUUwY(M`8$`B>K&_48!Li682ZaRknMgQ3~dnlp8C?__!P2z@=Auv;T^$yrsNy zCARmaA@^Yo2sS%2$`031-+h9KMZsIHfB>s@}>Y(z988e!`%4=EDoAQ0kbk>+lCoK60Mx9P!~I zlq~wf7kcm_NFImt3ZYlE(b3O1K^QWiFb$V^a2Jlwvm(!XYx<`i@ZMS3UwFt{;x+-v zhx{m=m;4dgvkKp5{*lfSN3o^keSpp9{hlXj%=}e_7Ou{Yiw(J@NXuh*;pL6@$HsfB zh?v+r^cp@jQ4EspC#RqpwPY(}_SS$wZ{S959`C25777&sgtNh%XTCo9VHJC-G z;;wi9{-iv+ETiY;K9qvlEc04f;ZnUP>cUL_T*ms``EtGoP^B#Q>n2dSrbAg8a>*Lg zd0EJ^=tdW~7fbcLFsqryFEcy*-8!?;n%;F+8i{eZyCDaiYxghr z$8k>L|2&-!lhvuVdk!r-kpSFl`5F5d4DJr%M4-qOy3gdmQbqF1=aBtRM7)c_Ae?$b8 zQg4c8*KQ{XJmL)1c7#0Yn0#PTMEs4-IHPjkn0!=;JdhMXqzMLeh`yOylXROP- zl#z3+fwM9l3%VN(6R77ua*uI9%hO7l7{+Hcbr(peh;afUK?B4EC09J{-u{mv)+u#? zdKVBCPt`eU@IzL)OXA`Ebu`Xp?u0m%h&X41}FNfnJ*g1!1wcbbpo%F4x!-#R9ft!8{5`Ho}04?FI#Kg zL|k`tF1t_`ywdy8(wnTut>HND(qNnq%Sq=AvvZbXnLx|mJhi!*&lwG2g|edBdVgLy zjvVTKHAx(+&P;P#2Xobo7_RttUi)Nllc}}hX>|N?-u5g7VJ-NNdwYcaOG?NK=5)}` zMtOL;o|i0mSKm(UI_7BL_^6HnVOTkuPI6y@ZLR(H?c1cr-_ouSLp{5!bx^DiKd*Yb z{K78Ci&Twup zTKm)ioN|wcYy%Qnwb)IzbH>W!;Ah5Zdm_jRY`+VRJ2 zhkspZ9hbK3iQD91A$d!0*-1i#%x81|s+SPRmD}d~<1p6!A13(!vABP2kNgqEG z?AMgl^P+iRoIY(9@_I?n1829lGvAsRnHwS~|5vD2+Zi53j<5N4wNn0{q>>jF9*bI) zL$kMXM-awNOElF>{?Jr^tOz1glbwaD-M0OKOlTeW3C!1ZyxRbB>8JDof(O&R1bh%3x#>y2~<>OXO#IIedH0Q`(&&?eo-c~ z>*Ah#3~09unym~UC-UFqqI>{dmUD$Y4@evG#ORLI*{ZM)Jl=e1it!XzY($S3V zLG!Y6fCjE>x6r@5FG1n|8ompSZaJ>9)q6jqU;XxCQk9zV(?C9+i*>w z21+KYt1gXX&0`x3E)hS7I5}snbBzox9C@Xzcr|{B8Hw;SY1$}&BoYKXH^hpjW-RgJ z-Fb}tannKCv>y~^`r|(1Q9;+sZlYf3XPSX|^gR01UFtu$B*R;$sPZdIZShRr>|b@J z;#G{EdoY+O;REEjQ}X7_YzWLO+Ey3>a_KDe1CjSe| z6arqcEZ)CX!8r(si`dqbF$uu&pnf^Np{1f*TdJ`r2;@SaZ z#hb4xlaCA@Pwqj#LlUEe5L{I$k(Zj$d3(~)u(F%&xb8={N9hKxlZIO1ABsM{Mt|)2 zJ^t9Id;?%4PfR4&Ph9B9cFK~@tG3wlFW-0fXZS_L4U*EiAA%+`h%q2^6BCC;t0iO4V=s4Qug{M|iDV@s zC7|ef-dxiR7T&Mpre!%hiUhHM%3Qxi$Lzw6&(Tvlx9QA_7LhYq<(o~=Y>3ka-zrQa zhGpfFK@)#)rtfz61w35^sN1=IFw&Oc!Nah+8@qhJ0UEGr;JplaxOGI82OVqZHsqfX ze1}r{jy;G?&}Da}a7>SCDsFDuzuseeCKof|Dz2BPsP8? zY;a)Tkr2P~0^2BeO?wnzF_Ul-ekY=-w26VnU%U3f19Z-pj&2 z4J_a|o4Dci+MO)mPQIM>kdPG1xydiR9@#8m zh27D7GF{p|a{8({Q-Pr-;#jV{2zHR>lGoFtIfIpoMo?exuQyX_A;;l0AP4!)JEM$EwMInZkj+8*IHP4vKRd zKx_l-i*>A*C@{u%ct`y~s6MWAfO{@FPIX&sg8H{GMDc{4M3%$@c8&RAlw0-R<4DO3 trJqdc$mBpWeznn?E0M$F`|3v=`3%T2A17h;rxP7$%JLd=6(2u;`(N3pt&so# literal 0 HcmV?d00001 diff --git a/docs/index.html b/docs/index.html index 3fcd5d8..cad7eaa 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,79 +1,213 @@ + - - JSDoc: Index - - - - - - + + DocStrap Index + + + + + + +
+ - +
+ +
+ +
+ + + + + Index + + + + + + + + + + + + + + + + + + + + + +
+

Node-query

A node query builder for various SQL databases, based on CodeIgniter's query builder.

+

Basic use

var nodeQuery = require('node-query');
 
-    

+var mysql = ... // Database module connection +// Three arguments: database type, database connection, database connection library +var query = nodeQuery('mysql', mysql, 'mysql2'); - - - - - - - - - - - - -
-

Node-query

-

A node query builder for various SQL databases, based on CodeIgniter's query builder.

-

Probable use

-
var query = require('node-query');
-
-var res = query
-    .select('foo')
+query.select('foo')
     .from('bar')
     .where('x', 3)
     .orWhere('y', 2)
     .orderBy('x')
     .limit(2, 3)
-    .get();
-
+ .get(function(err, result) { + // Database module result handling + });
+
+ + + + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + - - - - -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - \ No newline at end of file diff --git a/docs/module-adapter.html b/docs/module-adapter.html new file mode 100644 index 0000000..f9ace9e --- /dev/null +++ b/docs/module-adapter.html @@ -0,0 +1,437 @@ + + + + + + DocStrap Module: adapter + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: adapter

+
+ +
+

+ adapter +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + +

Methods

+ +
+ +
+

<static> execute(sql, params, callback)

+ + +
+
+ + +
+

Run the sql query as a prepared statement

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
sql + + +String + + + +

The sql with placeholders

params + + +Array + + + +

The values to insert into the query

callback + + +function + + + +

Callback to run when a response is recieved

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

void

+
+ + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-adapters_mysql.html b/docs/module-adapters_mysql.html new file mode 100644 index 0000000..942f655 --- /dev/null +++ b/docs/module-adapters_mysql.html @@ -0,0 +1,255 @@ + + + + + + DocStrap Module: adapters/mysql + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: adapters/mysql

+
+ +
+

+ adapters/mysql +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-adapters_mysql2.html b/docs/module-adapters_mysql2.html new file mode 100644 index 0000000..0571c05 --- /dev/null +++ b/docs/module-adapters_mysql2.html @@ -0,0 +1,255 @@ + + + + + + DocStrap Module: adapters/mysql2 + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: adapters/mysql2

+
+ +
+

+ adapters/mysql2 +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-dev + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-driver.html b/docs/module-driver.html index aad217c..52a22e5 100644 --- a/docs/module-driver.html +++ b/docs/module-driver.html @@ -1,989 +1,253 @@ + - - JSDoc: Module: driver - - - - - - + + DocStrap Module: driver + + + + + + +
+ +
-
- -
-

- driver -

- -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<private, static> _prefix(str) → {String}

- - -
-
- - -
- Sets the table prefix on the passed string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - +
+ +
+ + + +

Module: driver

+
+ +
+

+ driver +

+ +
+ +
+
+ + + + +

Base Database Driver

+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + - + + + - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<private, static> _quote(str) → {String}

- - -
-
- - -
- Low level function for naive quoting of strings -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<static> limit(sql, limit, offset) → {String}

- - -
-
- - -
- Set the limit clause -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
sql - - -String - - - -
limit - - -Number - - - -
offset - - -Number -| - -null - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<static> prefixTable(table) → {String}

- - -
-
- - -
- Prefixes a table if it is not already prefixed -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
table - - -String - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<static> quoteIdentifiers(str) → {String|Array}

- - -
-
- - -
- Use the driver's escape character to quote identifiers -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -String -| - -Array - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String -| - -Array - - -
-
- - - - -
- - - -
-

<static> quoteTable(table) → {String}

- - -
-
- - -
- Quote database table name, and set prefix -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
table - - -String - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - \ No newline at end of file diff --git a/docs/module-helpers.html b/docs/module-helpers.html index e97eee0..96cfa44 100644 --- a/docs/module-helpers.html +++ b/docs/module-helpers.html @@ -1,553 +1,251 @@ + - - JSDoc: Module: helpers - - - - - - + + DocStrap Module: helpers + + + + + + +
+ +
-
- -
-

- helpers -

- -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - - - - - - - - - - - - - -

Methods

- -
- -
-

<static> isNumber(obj) → {bool}

- - -
-
- - -
- Determine whether an object is numeric -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - +
+ +
+ + + +

Module: helpers

+
+ +
+

+ helpers +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+ + + + + + + + + + + + + - + + + - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - -mixed - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -bool - - -
-
- - - - -
- - - -
-

<static> isString(obj) → {bool}

- - -
-
- - -
- Determine whether an object is a string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - -mixed - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -bool - - -
-
- - - - -
- - - -
-

<static> splitTrim(char, string) → {String}

- - -
-
- - -
- Split a string by a character, trim the string -and rejoin the string -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
char - - -String - - - -
string - - -String - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- -
- - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - \ No newline at end of file diff --git a/docs/module-node-query.html b/docs/module-node-query.html new file mode 100644 index 0000000..52146b6 --- /dev/null +++ b/docs/module-node-query.html @@ -0,0 +1,441 @@ + + + + + + DocStrap Module: node-query + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: node-query

+
+ +
+

+ node-query +

+ +
+ +
+
+ + +
+

require("node-query")(drivername, connObject, connLib) → {queryBuilder}

+ + +
+
+ + +
+

Create a query builder object

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
drivername + + +String + + + +

The name of the database type, eg. mysql or pg

connObject + + +Object + + + +

A connection object from the database library you are connecting with

connLib + + +String + + + +

The name of the db connection library you are using, eg. mysql or mysql2

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +queryBuilder + + +
+
+ + + + + +
+ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/module-query-builder.html b/docs/module-query-builder.html index 52385d4..606ac0f 100644 --- a/docs/module-query-builder.html +++ b/docs/module-query-builder.html @@ -1,772 +1,5731 @@ + - - JSDoc: Module: query-builder - - - - - - + + DocStrap Module: query-builder + + + + + + +
+ +
-
- -
-

- query-builder -

- -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - - - - - - - - - - - -

Members

- -
- -
-

<private, inner> _p

- - -
-
- -
- "Private" methods -
- - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- - - -
-

<private, inner> state :Object

- - -
-
- -
- Variables controlling the sql building -
- - - -
Type:
-
    -
  • - -Object - - -
  • -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - -
- -
- - - -

Methods

- -
- -
-

<static> from(tableName) → {exports}

- - -
-
- - -
- Specify the database table to select from -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - +
+ +
+ + + +

Module: query-builder

+
+ +
+

+ query-builder +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + +

Members

+ +
+ +
+

<private, inner> state

+ + +
+
+ +
+

Variables controlling the sql building

+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + +
+ +
+ + + +

Methods

+ +
+ +
+

from(tableName)

+ + +
+
+ + +
+

Specify the database table to select from

+
+ + + + + + + +
Parameters:
+ + +
NameTypeDescription
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
tableName + + +String + + + +

The table to use for the current query

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

get(table, limit, offset, callback)

+ + +
+
+ + +
+

Get the results of the compiled query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
table + + +String + + + + + + <optional>
+ + + + + +

The table to select from

limit + + +Number + + + + + + <optional>
+ + + + + +

A limit for the query

offset + + +Number + + + + + + <optional>
+ + + + + +

An offset for the query

callback + + +function + + + + + + + + + +

A callback for receiving the result

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

void

+
+ + + + + + + +
+ + + +
+

getCompiledDelete(table, reset) → {String}

+ + +
+
+ + +
+

Return generated delete query SQL

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
table + + +String + + + + + + + + + + + +

the name of the table to delete from

reset + + +Boolean + + + + + + <optional>
+ + + + + +
+ + true + +

Whether to reset the query builder so another query can be built

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + +
+ + + +
+

getCompiledInsert(table, reset) → {String}

+ + +
+
+ + +
+

Return generated insert query SQL

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
table + + +String + + + + + + + + + + + +

the name of the table to insert into

reset + + +Boolean + + + + + + <optional>
+ + + + + +
+ + true + +

Whether to reset the query builder so another query can be built

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + +
+ + + +
+

getCompiledSelect(table, reset)

+ + +
+
+ + +
+

Return generated select query SQL

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
table + + +String + + + + + + <optional>
+ + + + + +
+ +

the name of the table to retrieve from

reset + + +Boolean + + + + + + <optional>
+ + + + + +
+ + true + +

Whether to reset the query builder so another query can be built

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

String

+
+ + + + + + + +
+ + + +
+

getCompiledUpdate(table, reset) → {String}

+ + +
+
+ + +
+

Return generated update query SQL

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
table + + +String + + + + + + + + + + + +

the name of the table to update

reset + + +Boolean + + + + + + <optional>
+ + + + + +
+ + true + +

Whether to reset the query builder so another query can be built

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +String + + +
+
+ + + + + +
+ + + +
+

<private> getState() → {Object}

+ + +
+
+ + +
+

Returns the current class state for testing or other purposes

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + + + +
+
+ Type +
+
+ +Object + + +
+
+ + + + + +
+ + + +
+

groupBy(field)

+ + +
+
+ + +
+

Group the results by the selected field(s)

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
field + + +String +| + +Array + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

groupEnd()

+ + +
+
+ + +
+

Ends a logical grouping started with one of the groupStart methods

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

groupStart()

+ + +
+
+ + +
+

Adds an open paren to the current query for logical grouping

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

having(key, val)

+ + +
+
+ + +
+

Add a 'having' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
key + + +String +| + +Object + + + + + + + + + +

The name of the field and the comparision operator, or an object

val + + +String +| + +Number + + + + + + <optional>
+ + + + + +

The value to compare if the value of key is a string

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

insert(table, data, callback)

+ + +
+
+ + +
+

Run the generated insert query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
table + + +String + + + + + + + + + +

The table to insert into

data + + +Object + + + + + + <optional>
+ + + + + +

Data to insert, if not already added with the 'set' method

callback + + +function + + + + + + + + + +

Callback for handling response from the database

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

void

+
+ + + + + + + +
+ + + +
+

join(joinOn, cond, joinTo, type)

+ + +
+
+ + +
+

Add a join clause to the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
joinOn + + +String + + + + + + + + + + + +

The table you are joining

cond + + +String + + + + + + <optional>
+ + + + + +
+ + '=' + +

The join condition, eg. =,<,>,<>,!=,etc.

joinTo + + +String + + + + + + + + + + + +

The value of the condition you are joining on, whether another table's field, or a literal value

type + + +String + + + + + + <optional>
+ + + + + +
+ + 'inner' + +

The type of join, which defaults to inner

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

like(field, val, pos)

+ + +
+
+ + +
+

Add a 'like/ and like' clause to the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
field + + +String + + + + + + + + + + + +

The name of the field to compare to

val + + +String + + + + + + + + + + + +

The value to compare to

pos + + +String + + + + + + <optional>
+ + + + + +
+ + both + +

The placement of the wildcard character(s): before, after, or both

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

limit(limit, offset)

+ + +
+
+ + +
+

Put a limit on the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
limit + + +Number + + + + + + + + + +

The maximum number of rows to fetch

offset + + +Number + + + + + + <optional>
+ + + + + +

The row number to start from

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

notLike(field, val, pos)

+ + +
+
+ + +
+

Add a 'not like/ and not like' clause to the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
field + + +String + + + + + + + + + + + +

The name of the field to compare to

val + + +String + + + + + + + + + + + +

The value to compare to

pos + + +String + + + + + + <optional>
+ + + + + +
+ + both + +

The placement of the wildcard character(s): before, after, or both

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orderBy(field, type)

+ + +
+
+ + +
+

Order the results by the selected field(s)

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
field + + +String + + + + + + + + + + + +

The field to order by

type + + +String + + + + + + <optional>
+ + + + + +
+ + 'ASC' + +

The order direction, ASC or DESC

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orGroupStart()

+ + +
+
+ + +
+

Adds an open paren to the current query for logical grouping, +prefixed with 'OR'

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orHaving(key, val)

+ + +
+
+ + +
+

Add an 'or having' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
key + + +String +| + +Object + + + + + + + + + +

The name of the field and the comparision operator, or an object

val + + +String +| + +Number + + + + + + <optional>
+ + + + + +

The value to compare if the value of key is a string

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orLike(field, val, pos)

+ + +
+
+ + +
+

Add an 'or like' clause to the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
field + + +String + + + + + + + + + + + +

The name of the field to compare to

val + + +String + + + + + + + + + + + +

The value to compare to

pos + + +String + + + + + + <optional>
+ + + + + +
+ + both + +

The placement of the wildcard character(s): before, after, or both

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orNotGroupStart()

+ + +
+
+ + +
+

Adds an open paren to the current query for logical grouping, +prefixed with 'OR NOT'

+
+ + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orNotLike(field, val, pos)

+ + +
+
+ + +
+

Add an 'or not like' clause to the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDefaultDescription
field + + +String + + + + + + + + + + + +

The name of the field to compare to

val + + +String + + + + + + + + + + + +

The value to compare to

pos + + +String + + + + + + <optional>
+ + + + + +
+ + both + +

The placement of the wildcard character(s): before, after, or both

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orWhere(key, val)

+ + +
+
+ + +
+

Set a 'or where' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
key + + +String +| + +Object + + + + + + + + + +

The name of the field and the comparision operator, or an object

val + + +String +| + +Number + + + + + + <optional>
+ + + + + +

The value to compare if the value of key is a string

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orWhereIn(key, val)

+ + +
+
+ + +
+

Set a 'or where in' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +String + + + +

the field to search

val + + +Array + + + +

the array of items to search in

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

orWhereNotIn(key, val)

+ + +
+
+ + +
+

Set a 'or where not in' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +String + + + +

the field to search

val + + +Array + + + +

the array of items to search in

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

select(fields)

+ + +
+
+ + +
+

Specify rows to select in the query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
fields + + +String +| + +Array + + + +

The fields to select from the current table

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

set(key, val)

+ + +
+
+ + +
+

Set values for insertion or updating

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
key + + +String +| + +Object + + + + + + + + + +

The key or object to use

val + + +String + + + + + + <optional>
+ + + + + +

The value if using a scalar key

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

update(table, data, callback)

+ + +
+
+ + +
+

Run the generated update query

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
table + + +String + + + + + + + + + +

The table to insert into

data + + +Object + + + + + + <optional>
+ + + + + +

Data to insert, if not already added with the 'set' method

callback + + +function + + + + + + + + + +

Callback for handling response from the database

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

void

+
+ + + + + + + +
+ + + +
+

where(key, val)

+ + +
+
+ + +
+

Set a 'where' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeArgumentDescription
key + + +String +| + +Object + + + + + + + + + +

The name of the field and the comparision operator, or an object

val + + +String +| + +Number + + + + + + <optional>
+ + + + + +

The value to compare if the value of key is a string

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

whereIn(key, val)

+ + +
+
+ + +
+

Set a 'where in' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +String + + + +

the field to search

val + + +Array + + + +

the array of items to search in

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ + + +
+

whereNotIn(key, val)

+ + +
+
+ + +
+

Set a 'where not in' clause

+
+ + + + + + + +
Parameters:
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescription
key + + +String + + + +

the field to search

val + + +Array + + + +

the array of items to search in

+ + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + + + + + + + + +
Returns:
+ + +
+

this

+
+ + + + + + + +
+ +
+ + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + - + + + - - - - tableName - - - - - -String - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -exports - - -
-
- - - - - - - - -
-

<static> getCompiledSelect() → {String}

- - -
-
- - -
- Return generated select query SQL -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -String - - -
-
- - - - -
- - - -
-

<static> getState() → {Object}

- - -
-
- - -
- Returns the current class state for testing or other purposes -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -Object - - -
-
- - - - -
- - - -
-

<static> resetQuery()

- - -
-
- - -
- Reset the object state for a new query -
- - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - -
- void -
- - - - - - -
- - - -
-

<static> select(fields) → {exports}

- - -
-
- - -
- Specify rows to select in the query -
- - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
fields - - -String -| - -Array - - - -
- - - -
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - -
Returns:
- - - - -
-
- Type -
-
- -exports - - -
-
- - - - -
- - - - - - - - - - - - - - - - - - -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - \ No newline at end of file diff --git a/docs/modules.list.html b/docs/modules.list.html new file mode 100644 index 0000000..26212b8 --- /dev/null +++ b/docs/modules.list.html @@ -0,0 +1,241 @@ + + + + + + DocStrap Modules + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Modules

+
+ +
+

+ +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/mysql.html b/docs/mysql.html new file mode 100644 index 0000000..e2a46ef --- /dev/null +++ b/docs/mysql.html @@ -0,0 +1,261 @@ + + + + + + DocStrap Module: drivers/mysql + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: drivers/mysql

+
+ +
+

+ drivers/mysql +

+ +
+ +
+
+ + + + +

Driver for MySQL databases

+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/mysql.js.html b/docs/mysql.js.html index b4c6490..873e73e 100644 --- a/docs/mysql.js.html +++ b/docs/mysql.js.html @@ -1,38 +1,91 @@ + - - JSDoc: Source: drivers/mysql.js - - - - - - + + DocStrap Source: drivers/mysql.js + + + + + + +
+ - -
-
-
"use strict";
+	
+ + +
+ +
+ + + +

Source: drivers/mysql.js

+ +
+
+
"use strict";
 
 /**
  * Driver for MySQL databases
  *
- * @returns {driver}
+ * @module drivers/mysql
  */
-module.exports = function() {
+module.exports = (function() {
+
 	var driver = require('../driver'),
 		helpers = require('../helpers');
 
@@ -51,26 +104,106 @@ module.exports = function() {
 	};
 
 	return driver;
-};
-
-
+ +}());
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+ + + +
+ + + + + + + + + + + - - + + -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - diff --git a/docs/mysql.js_.html b/docs/mysql.js_.html new file mode 100644 index 0000000..9868cfc --- /dev/null +++ b/docs/mysql.js_.html @@ -0,0 +1,193 @@ + + + + + + DocStrap Source: adapters/mysql.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: adapters/mysql.js

+ +
+
+
'use strict';
+
+var adapter = require('../lib/adapter.js');
+
+/** @module adapters/mysql */
+module.exports = function(instance) {
+
+	adapter.execute = function(sql, params, callback) {
+		instance.query(sql, params, callback);
+	};
+
+	return adapter;
+}
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/mysql2.html b/docs/mysql2.html new file mode 100644 index 0000000..8dc4d7d --- /dev/null +++ b/docs/mysql2.html @@ -0,0 +1,259 @@ + + + + + + DocStrap Module: adapters/mysql2 + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: adapters/mysql2

+
+ +
+

+ adapters/mysql2 +

+ +
+ +
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/mysql2.js.html b/docs/mysql2.js.html new file mode 100644 index 0000000..6484c2b --- /dev/null +++ b/docs/mysql2.js.html @@ -0,0 +1,201 @@ + + + + + + DocStrap Source: adapters/mysql2.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: adapters/mysql2.js

+ +
+
+
'use strict';
+
+var adapter = require('../lib/adapter.js');
+
+/** @module adapters/mysql2 */
+module.exports = function(instance) {
+
+	/**
+	 * Run the sql query as a prepared statement
+	 *
+	 * @param {String} sql - The sql with placeholders
+	 * @param {Array} params - The values to insert into the query
+	 * @param {Function} callback - Callback to run when a response is recieved
+	 * @return void
+	 */
+	adapter.execute = function(sql, params, callback) {
+		instance.execute(sql, params, callback);
+	};
+
+	return adapter;
+}
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Tue Oct 21st 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/node-query.js.html b/docs/node-query.js.html new file mode 100644 index 0000000..636017c --- /dev/null +++ b/docs/node-query.js.html @@ -0,0 +1,208 @@ + + + + + + DocStrap Source: node-query.js + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Source: node-query.js

+ +
+
+
"use strict";
+
+/** @module node-query */
+var nodeQuery = {};
+
+/**
+ * Create a query builder object
+ *
+ * @alias module:node-query
+ * @param {String} drivername - The name of the database type, eg. mysql or pg
+ * @param {Object} connObject - A connection object from the database library you are connecting with
+ * @param {String} connLib - The name of the db connection library you are using, eg. mysql or mysql2
+ * @return {queryBuilder}
+ */
+nodeQuery.init = function (driverType, connObject, connLib) {
+	var fs = require('fs'),
+		qb = require('./query-builder');
+
+	var paths = {
+		driver: __dirname + '/drivers/' + driverType + '.js',
+		adapter: __dirname + '/adapters/' + connLib + '.js'
+	};
+
+	Object.keys(paths).forEach(function(type) {
+		if ( ! fs.existsSync(paths[type]))
+		{
+			console.log(paths[type]);
+			throw new Error('Selected ' + type + ' does not exist!');
+		}
+	});
+
+	return new qb(require(paths.driver), require(paths.adapter)(connObject));
+};
+
+
+module.exports = nodeQuery.init;
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + diff --git a/docs/pg.html b/docs/pg.html new file mode 100644 index 0000000..5df9b6d --- /dev/null +++ b/docs/pg.html @@ -0,0 +1,261 @@ + + + + + + DocStrap Module: drivers/pg + + + + + + + + + +
+ + +
+ + +
+ +
+ + + +

Module: drivers/pg

+
+ +
+

+ drivers/pg +

+ +
+ +
+
+ + + + +

Driver for PostgreSQL databases

+ + + +
+ + + + + + + + + + + + + + + + + + + + + +
Source:
+
+ +
+ + + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+
+ + +
+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/pg.js.html b/docs/pg.js.html index fa7a074..8e42118 100644 --- a/docs/pg.js.html +++ b/docs/pg.js.html @@ -1,61 +1,192 @@ + - - JSDoc: Source: drivers/pg.js - - - - - - + + DocStrap Source: drivers/pg.js + + + + + + +
+ - -
-
-
"use strict";
+	
+ + +
+ +
+ + + +

Source: drivers/pg.js

+ +
+
+
"use strict";
 
 /**
  * Driver for PostgreSQL databases
  *
- * @returns {driver}
+ * @module drivers/pg
  */
-module.exports = function() {
+module.exports = (function() {
 	var driver = require('../driver');
 
 	return driver;
-};
-
-
+}());
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+ + + +
+ + + + + + + + + + + - - + + -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - diff --git a/docs/query-builder.js.html b/docs/query-builder.js.html index 5d6bf43..aeacb93 100644 --- a/docs/query-builder.js.html +++ b/docs/query-builder.js.html @@ -1,47 +1,103 @@ + - - JSDoc: Source: query-builder.js - - - - - - + + DocStrap Source: query-builder.js + + + + + + +
+ - -
-
-
/** @module query-builder */
+	
-var async = require('async'); + +
+ +
+ + + +

Source: query-builder.js

+ +
+
+
'use strict';
 
-module.exports = function(driver) {
+/** @module query-builder */
 
-	"use strict";
+var getArgs = require('getargs'),
+	helpers = require('./helpers');
 
-	/**
-	 * Variables controlling the sql building
-	 *
-	 * @private
-	 * @type {{}}
-	 */
-	var state = {};
+/**
+ * Variables controlling the sql building
+ *
+ * @private
+ */
+var state = {};
 
-	// ------------------------------------------------------------------------
+/*
+ * SQL generation object
+ *
+ * @param {driver} - The syntax driver for the database
+ * @param {adapter} - The database module adapter for running queries
+ * @constructor
+ */
+var QueryBuilder = function(driver, adapter) {
+
+	// That 'new' keyword is annoying
+	if ( ! (this instanceof QueryBuilder)) return new QueryBuilder(driver, adapter);
+
+	// Keep these properties as object members so they can be mocked/substituted
+	this.driver = driver;
+	this.adapter = adapter;
 
 	/**
 	 * "Private" methods
@@ -54,28 +110,300 @@ module.exports = function(driver) {
 		 *
 		 * @param {String} type
 		 * @param {String} table
+		 * @private
 		 * @return {String}
 		 */
 		compile: function (type, table) {
+			// Put together the basic query
+			var sql = _p.compileType(type, table);
+
+			// Set each subClause
+			['queryMap', 'groupString', 'orderString', 'havingMap'].forEach(function(clause) {
+				var param = state[clause];
+
+				if ( ! helpers.isScalar(param))
+				{
+					Object.keys(param).forEach(function(part) {
+						sql += param[part].conjunction + param[part].string;
+					});
+				}
+				else
+				{
+					sql += param;
+				}
+			});
+
+			// Append the limit, if it exists
+			if (helpers.isNumber(state.limit))
+			{
+				sql = this.driver.limit(sql, state.limit, state.offset);
+			}
+
+			return sql;
+		},
+		compileType: function (type, table) {
+			var sql = '';
+
 			switch(type) {
 				case "insert":
+					var paramCount = state.setArrayKeys.length;
+					var params = [];
+					params.fill('?', 0, paramCount);
+
+					sql = "INSERT INTO " + table + " (";
+					sql += state.setArrayKeys.join(',');
+					sql += ") VALUES (";
+					sql += params.join(',') + ')';
 				break;
 
 				case "update":
+					sql = "UPDATE " + table + " SET " + state.setString;
 				break;
 
 				case "delete":
+					sql = "DELETE FROM " + table;
 				break;
 
 				default:
+					sql = "SELECT * FROM " + state.fromString;
+
+					// Set the select string
+					if (state.selectString.length > 0)
+					{
+						// Replace the star with the selected fields
+						sql = sql.replace('*', state.selectString);
+					}
 				break;
 			}
-		},
-		compileType: function (type, table) {
 
+			return sql;
+		},
+		like: function (field, val, pos, like, conj) {
+			field = this.driver.quoteIdentifiers(field);
+
+			like = field + " " + like + " ?";
+
+			if (pos == 'before')
+			{
+				val = "%" + val;
+			}
+			else if (pos == 'after')
+			{
+				val = val + "%";
+			}
+			else
+			{
+				val = "%" + val + "%";
+			}
+
+			conj = (state.queryMap.length < 1) ? ' WHERE ' : ' ' + conj + '';
+			_p.appendMap(conj, like, 'like');
+
+			state.whereValues.push(val);
+		},
+		/**
+		 * Append a clause to the query map
+		 *
+		 * @param {String} conjunction
+		 * @param {String} string
+		 * @param {String} type
+		 * @return void
+		 */
+		appendMap: function(conjunction, string, type) {
+			state.queryMap.push({
+				type: type,
+				conjunction: conjunction,
+				string: string
+			});
+		},
+		/**
+		 * Handle key/value pairs in an object the same way as individual arguments,
+		 * when appending to state
+		 *
+		 * @private
+		 */
+		mixedSet: function(/* varName, key, [val], valType */) {
+			var args = getArgs('varName:string, key:string|array, [val]:string, valType:string', arguments);
+
+			var obj = {};
+
+			if (helpers.isString(args.key) && helpers.isString(args.val))
+			{
+				obj[args.key] = args.val;
+			}
+			else
+			{
+				obj = args.key;
+			}
+
+			Object.keys(obj).forEach(function(k) {
+				if (args.valType != 'both')
+				{
+					state[args.varName].push(
+						(args.valType === 'key')? k: obj[k]
+					);
+				}
+				else
+				{
+					state[args.varName][k] = obj[k];
+				}
+			});
+
+			return state[args.varName];
+		},
+		whereMixedSet: function(key, val) {
+			_p.mixedSet('whereValues', key, val, 'value');
+			_p.mixedSet('whereMap', key, val, 'both');
+		},
+		where: function(key, val, conj) {
+			conj = conj || 'AND';
+
+			// Get an object to iterate over
+			_p.whereMixedSet(key, val);
+
+			Object.keys(state.whereMap).forEach(function(field) {
+				// Split each key by spaces, in case there
+				// is an operator such as >, <, !=, etc.
+				var fieldArray = field.split(' ');
+
+				var item = this.driver.quoteIdentifiers(fieldArray[0]);
+
+				// Simple key value, or an operator?
+				item += (fieldArray.length === 1) ? '=?' : " " + fieldArray[1] + " ?";
+
+				var firstItem = state.queryMap[0],
+					lastItem = state.queryMap[state.queryMap.length - 1];
+
+				// Determine the correct conjunction
+				if (state.queryMap.length < 1 || firstItem.contains('JOIN'))
+				{
+					conj = " WHERE ";
+				}
+				else if (lastItem.type === 'groupStart')
+				{
+					conj = '';
+				}
+				else
+				{
+					conj = ' ' + conj + ' ';
+				}
+
+				_p.appendMap(conj, item, 'where');
+			});
+		},
+		having: function(key, val, conj) {
+			conj = conj || 'AND';
+
+			_p.whereMixedSet(key, val);
+
+			Object.keys(state.whereMap).forEach(function(field) {
+				// Split each key by spaces, in case there
+				// is an operator such as >, <, !=, etc.
+				var fieldArray = field.split(' ').map(helpers.stringTrim);
+
+				var item = this.driver.quoteIdentifiers(fieldArray[0]);
+
+				// Simple key value, or an operator?
+				item += (fieldArray.length === 1) ? '=?' : " " + fieldArray[1] + " ?";
+
+				// Put in the having map
+				state.havingMap.push({
+					conjunction: (state.havingMap.length > 0) ? " " + conj + " " : ' HAVING ',
+					string: item
+				});
+			});
+		},
+		whereIn: function(key, val, inClause, conj) {
+			key = this.driver.quoteIdentifiers(key);
+			var params = [];
+			params.fill('?', 0, val.length);
+
+			val.forEach(function(value) {
+				state.whereValues.push(value);
+			});
+
+			conj = (state.queryMap.length > 0) ? " " + conj + " " : ' WHERE ';
+			var str = key + " " + inClause + " (" + params.join(',') + ") ";
+
+			_p.appendMap(conj, str, 'whereIn');
+		},
+		run: function(type, table, callback, sql, vals) {
+			if ( ! sql)
+			{
+				sql = _p.compile(type, table);
+			}
+
+			if ( ! vals)
+			{
+				vals = state.values.concat(state.whereValues);
+			}
+
+			// Reset the state so another query can be built
+			_p.resetState();
+
+			// Pass the sql and values to the adapter to run on the database
+			adapter.execute(sql, vals, callback);
+
+		},
+		getCompile: function(type, table, reset) {
+			reset = reset || false;
+
+			var sql = _p.compile(type, table);
+
+			if (reset) _p.resetState();
+
+			return sql;
+		},
+		resetState: function() {
+			state = {
+				// Arrays/Maps
+				queryMap: {},
+				values: [],
+				whereValues: [],
+				setArrayKeys: [],
+				orderArray: [],
+				groupArray: [],
+				havingMap: [],
+				whereMap: [],
+
+				// Partials
+				selectString: '',
+				fromString: '',
+				setString: '',
+				orderString: '',
+				groupString: '',
+
+				// Other various values
+				limit: null,
+				offset: null
+			};
 		}
 	};
 
+	// ----------------------------------------------------------------------------
+	// ! Miscellaneous Methods
+	// ----------------------------------------------------------------------------
+
+	/**
+	 * Reset the object state for a new query
+	 *
+	 * @memberOf query-builder
+	 * @return void
+	 */
+	this.resetQuery = function() {
+		_p.resetState();
+	};
+
+	/**
+	 * Returns the current class state for testing or other purposes
+	 *
+	 * @private
+	 * @return {Object}
+	 */
+	this.getState = function() {
+		return state;
+	};
+
 	// ------------------------------------------------------------------------
 
 	// Set up state object
@@ -88,23 +416,23 @@ module.exports = function(driver) {
 	/**
 	 * Specify rows to select in the query
 	 *
-	 * @param {String|Array} fields
-	 * @returns {exports}
+	 * @param {String|Array} fields - The fields to select from the current table
+	 * @return this
 	 */
 	this.select = function(fields) {
 
 		// Split/trim fields by comma
-		fields = (Array.isArray(fields)) ? fields : fields.split(",").map(String.trim);
+		fields = (Array.isArray(fields)) ? fields : fields.split(",").map(helpers.stringTrim);
 
 		// Split on 'As'
 		fields.forEach(function (field, index) {
 			if (field.match(/as/i))
 			{
-				fields[index] = field.split(/ as /i).map(String.trim);
+				fields[index] = field.split(/ as /i).map(helpers.stringTrim);
 			}
 		});
 
-		var safeArray = driver.quoteIdentifiers(fields);
+		var safeArray = this.driver.quoteIdentifiers(fields);
 
 		// Join the strings back together
 		safeArray.forEach(function (field, index) {
@@ -122,16 +450,16 @@ module.exports = function(driver) {
 	/**
 	 * Specify the database table to select from
 	 *
-	 * @param {String} tableName
-	 * @returns {exports}
+	 * @param {String} tableName - The table to use for the current query
+	 * @return this
 	 */
 	this.from = function(tableName) {
 		// Split identifiers on spaces
-		var identArray = String.trim(tableName).split(' ').map(String.trim);
+		var identArray = tableName.trim().split(' ').map(helpers.stringTrim);
 
 		// Quote/prefix identifiers
-		identArray[0] = driver.quoteTable(identArray[0]);
-		identArray = driver.quoteIdentifiers(identArray);
+		identArray[0] = this.driver.quoteTable(identArray[0]);
+		identArray = this.driver.quoteIdentifiers(identArray);
 
 		// Put it back together
 		state.fromString = identArray.join(' ');
@@ -139,118 +467,378 @@ module.exports = function(driver) {
 		return this;
 	};
 
+	/**
+	 * Add a 'like/ and like' clause to the query
+	 *
+	 * @param {String} field - The name of the field  to compare to
+	 * @param {String} val - The value to compare to
+	 * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+	 * @return this
+	 */
 	this.like = function(field, val, pos) {
-
+		_p.like(field, val, pos, ' LIKE ', 'AND');
+		return this;
 	};
 
+	/**
+	 * Add a 'not like/ and not like' clause to the query
+	 *
+	 * @param {String} field - The name of the field  to compare to
+	 * @param {String} val - The value to compare to
+	 * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+	 * @return this
+	 */
+	this.notLike = function(field, val, pos) {
+		_p.like(field, val, pos, ' NOT LIKE ', 'AND');
+		return this;
+	};
+
+	/**
+	 * Add an 'or like' clause to the query
+	 *
+	 * @param {String} field - The name of the field  to compare to
+	 * @param {String} val - The value to compare to
+	 * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+	 * @return this
+	 */
 	this.orLike = function(field, val, pos) {
-
+		_p.like(field, val, pos, ' LIKE ', 'OR');
+		return this;
 	};
 
+	/**
+	 * Add an 'or not like' clause to the query
+	 *
+	 * @param {String} field - The name of the field  to compare to
+	 * @param {String} val - The value to compare to
+	 * @param {String} [pos=both] - The placement of the wildcard character(s): before, after, or both
+	 * @return this
+	 */
 	this.orNotLike = function(field, val, pos) {
-
+		_p.like(field, val, pos, ' NOT LIKE ', 'OR');
+		return this;
 	};
 
+	/**
+	 * Add a 'having' clause
+	 *
+	 * @param {String|Object} key - The name of the field and the comparision operator, or an object
+	 * @param {String|Number} [val] - The value to compare if the value of key is a string
+	 * @return this
+	 */
 	this.having = function(key, val) {
-
+		_p.having(key, val, 'AND');
+		return this;
 	};
 
+	/**
+	 * Add an 'or having' clause
+	 *
+	 * @param {String|Object} key - The name of the field and the comparision operator, or an object
+	 * @param {String|Number} [val] - The value to compare if the value of key is a string
+	 * @return this
+	 */
 	this.orHaving = function(key, val) {
-
+		_p.having(key, val, 'OR');
+		return this;
 	};
 
+	/**
+	 * Set a 'where' clause
+	 *
+	 * @param {String|Object} key - The name of the field and the comparision operator, or an object
+	 * @param {String|Number} [val] - The value to compare if the value of key is a string
+	 * @return this
+	 */
 	this.where = function(key, val) {
-
+		_p.where(key, val, 'AND');
+		return this;
 	};
 
+	/**
+	 * Set a 'or where' clause
+	 *
+	 * @param {String|Object} key - The name of the field and the comparision operator, or an object
+	 * @param {String|Number} [val] - The value to compare if the value of key is a string
+	 * @return this
+	 */
 	this.orWhere = function(key, val) {
-
+		_p.where(key, val, 'OR');
+		return this;
 	};
 
+	/**
+	 * Set a 'where in' clause
+	 *
+	 * @param {String} key - the field to search
+	 * @param {Array} val - the array of items to search in
+	 * @return this
+	 */
 	this.whereIn = function(key, val) {
-
+		_p.whereIn(key, val, 'IN', 'AND');
+		return this;
 	};
 
+	/**
+	 * Set a 'or where in' clause
+	 *
+	 * @param {String} key - the field to search
+	 * @param {Array} val - the array of items to search in
+	 * @return this
+	 */
 	this.orWhereIn = function(key, val) {
-
+		_p.whereIn(key, val, 'IN', 'OR');
+		return this;
 	};
 
+	/**
+	 * Set a 'where not in' clause
+	 *
+	 * @param {String} key - the field to search
+	 * @param {Array} val - the array of items to search in
+	 * @return this
+	 */
 	this.whereNotIn = function(key, val) {
-
+		_p.whereIn(key, val, 'NOT IN', 'AND');
+		return this;
 	};
 
+	/**
+	 * Set a 'or where not in' clause
+	 *
+	 * @param {String} key - the field to search
+	 * @param {Array} val - the array of items to search in
+	 * @return this
+	 */
 	this.orWhereNotIn = function(key, val) {
-
-	};
-
-	this.set = function(key, val) {
+		_p.whereIn(key, val, 'NOT IN', 'OR');
 		return this;
 	};
 
-	this.join = function(table1, cond, table2, type) {
-		type = type || "inner";
+	/**
+	 * Set values for insertion or updating
+	 *
+	 * @param {String|Object} key - The key or object to use
+	 * @param {String} [val] - The value if using a scalar key
+	 * @return this
+	 */
+	this.set = function(/* key, [val] */) {
+		var args = getArgs('key:string|object, [val]:string', arguments);
+
+		// Set the appropriate state variables
+		_p.mixedSet('setArrayKeys', args.key, args.val, 'key');
+		_p.mixedSet('values', args.key, args.val, 'value');
+
+		// Use the keys of the array to make the insert/update string
+		// and escape the field names
+		state.setArrayKeys = state.setArrayKeys.map(this.driver._quote);
+
+		// Generate the "set" string
+		state.setString = state.setArrayKeys.join('=?,');
+		state.setString += '=?';
 
 		return this;
 	};
 
+	/**
+	 * Add a join clause to the query
+	 *
+	 * @param {String} joinOn - The table you are joining
+	 * @param {String} [cond='='] - The join condition, eg. =,<,>,<>,!=,etc.
+	 * @param {String} joinTo - The value of the condition you are joining on, whether another table's field, or a literal value
+	 * @param {String} [type='inner'] - The type of join, which defaults to inner
+	 * @return this
+	 */
+	this.join = function(/* joinOn, [cond='='], joinTo, [type='inner']*/) {
+		var args = getArgs('joinOn:string, [cond]:string, joinTo:string, [type]:string', arguments);
+		args.cond = args.cond || '=';
+		args.type = args.type || "inner";
+
+		return this;
+	};
+
+	/**
+	 * Group the results by the selected field(s)
+	 *
+	 * @param {String|Array} field
+	 * @return this
+	 */
 	this.groupBy = function(field) {
+		if (Array.isArray(field))
+		{
+			var newGroupArray = field.map(this.driver.quoteIdentifiers);
+			state.groupArray.concat(newGroupArray);
+		}
+		else
+		{
+			state.groupArray.push(this.driver.quoteIdentifiers(field));
+		}
 
+		state.groupString = ' GROUP BY ' + state.groupArray.join(',');
+
+		return this;
 	};
 
-	this.orderBy = function(field) {
+	/**
+	 * Order the results by the selected field(s)
+	 *
+	 * @param {String} field - The field to order by
+	 * @param {String} [type='ASC'] - The order direction, ASC or DESC
+	 * @return this
+	 */
+	this.orderBy = function(field, type) {
+		type = type || 'ASC';
 
+		// Set the fields for later manipulation
+		field = this.driver.quoteIdentifiers(field);
+		state.orderArray[field] = type;
+
+		var orderClauses = [];
+
+		// Flatten key/val pairs into an array of space-separated pairs
+		Object.keys(state.orderArray).forEach(function(key) {
+			orderClauses.push(key + ' ' + state.orderArray[key].toUpperCase());
+		});
+
+		// Set the final string
+		state.orderString = ' ORDER BY ' + orderClauses.join(', ');
+
+		return this;
 	};
 
+	/**
+	 * Put a limit on the query
+	 *
+	 * @param {Number} limit - The maximum number of rows to fetch
+	 * @param {Number} [offset] - The row number to start from
+	 * @return this
+	 */
 	this.limit = function(limit, offset) {
 		state.limit = limit;
-		state.offset = offset;
+		state.offset = offset || null;
 
 		return this;
 	};
 
+	/**
+	 * Adds an open paren to the current query for logical grouping
+	 *
+	 * @return this
+	 */
 	this.groupStart = function() {
+		var conj = (state.queryMap.length < 1) ? ' WHERE ' : ' ';
+		_p.appendMap(conj, '(', 'groupStart');
 
+		return this;
 	};
 
+	/**
+	 * Adds an open paren to the current query for logical grouping,
+	 * prefixed with 'OR'
+	 *
+	 * @return this
+	 */
 	this.orGroupStart = function() {
+		_p.appendMap('', ' OR (', 'groupStart');
 
+		return this;
 	};
 
+	/**
+	 * Adds an open paren to the current query for logical grouping,
+	 * prefixed with 'OR NOT'
+	 *
+	 * @return this
+	 */
 	this.orNotGroupStart = function() {
+		_p.appendMap('', ' OR NOT (', 'groupStart');
 
+		return this;
 	};
 
+	/**
+	 * Ends a logical grouping started with one of the groupStart methods
+	 *
+	 * @return this
+	 */
 	this.groupEnd = function() {
+		_p.appendMap('', ')', 'groupEnd');
 
+		return this;
 	};
 
 	// ------------------------------------------------------------------------
 	// ! Result Methods
 	// ------------------------------------------------------------------------
 
-	this.get = function(table, limit, offset) {
-		// Reset state
-		this.resetQuery();
+	/**
+	 * Get the results of the compiled query
+	 *
+	 * @param {String} [table] - The table to select from
+	 * @param {Number} [limit] - A limit for the query
+	 * @param {Number} [offset] - An offset for the query
+	 * @param {Function} callback - A callback for receiving the result
+	 * @return void
+	 */
+	this.get = function(/* [table], [limit], [offset], callback */) {
+		var args = getArgs('[table]:string, [limit]:number, [offset]:number, callback:function', arguments);
+
+		if (args.table) {
+			this.from(args.table);
+		}
+
+		if (args.limit) {
+			this.limit(args.limit, args.offset);
+		}
+
+		// Run the query
+		_p.run('get', args.table, args.callback);
 	};
 
-	this.getWhere = function(table, where, limit, offset) {
-		// Reset state
-		this.resetQuery();
+	/**
+	 * Run the generated insert query
+	 *
+	 * @param {String} table - The table to insert into
+	 * @param {Object} [data] - Data to insert, if not already added with the 'set' method
+	 * @param {Function} callback - Callback for handling response from the database
+	 * @return void
+	 */
+	this.insert = function(table, data, callback) {
+		if (data) {
+			this.set(data);
+		}
+
+		// Run the query
+		_p.run('insert', table, callback);
 	};
 
-	this.insert = function(table, data) {
-		// Reset state
-		this.resetQuery();
+	/**
+	 * Run the generated update query
+	 *
+	 * @param {String} table - The table to insert into
+	 * @param {Object} [data] - Data to insert, if not already added with the 'set' method
+	 * @param {Function} callback - Callback for handling response from the database
+	 * @return void
+	 */
+	this.update = function(table, data, callback) {
+		if (data) {
+			this.set(data);
+		}
+
+		// Run the query
+		_p.run('update', table, callback);
 	};
 
-	this.update = function(table, data) {
-		// Reset state
-		this.resetQuery();
-	};
-
-	this['delete'] = function (table, where) {
-		// Reset state
-		this.resetQuery();
+	/**
+	 * Run the generated delete query
+	 *
+	 * @param {String} table - The table to insert into
+	 * @param {Function} callback - Callback for handling response from the database
+	 * @return void
+	 */
+	this['delete'] = function (table, callback) {
+		// Run the query
+		_p.run('delete', table, callback);
 	};
 
 	// ------------------------------------------------------------------------
@@ -260,99 +848,154 @@ module.exports = function(driver) {
 	/**
 	 * Return generated select query SQL
 	 *
+	 * @param {String} [table] - the name of the table to retrieve from
+	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+	 * @return String
+	 */
+	this.getCompiledSelect = function(table, reset) {
+		if (table)
+		{
+			this.from(table);
+		}
+
+		return _p.getCompile('get', table, reset);
+	};
+
+	/**
+	 * Return generated insert query SQL
+	 *
+	 * @param {String} table - the name of the table to insert into
+	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
 	 * @return {String}
 	 */
-	this.getCompiledSelect = function() {
-		// Return sql
-
-		// Reset state
-		this.resetQuery();
-	};
-
-	this.getCompiledInsert = function() {
-		// Return sql
-
-		// Reset state
-		this.resetQuery();
-	};
-
-	this.getCompiledUpdate = function() {
-		// Return sql
-
-		// Reset state
-		this.resetQuery();
-	};
-
-	this.getCompiledDelete = function() {
-		// Return sql
-
-		// Reset state
-		this.resetQuery();
-	};
-
-	// ----------------------------------------------------------------------------
-	// ! Miscellaneous Methods
-	// ----------------------------------------------------------------------------
-
-	/**
-	 * Reset the object state for a new query
-	 *
-	 * @return void
-	 */
-	this.resetQuery = function() {
-		state = {
-			// Arrays/Maps
-			queryMap: {},
-			values: [],
-			whereValues: [],
-			setArrayKeys: [],
-			orderArray: [],
-			groupArray: [],
-			havingMap: [],
-
-			// Partials
-			selectString: '',
-			fromString: '',
-			setString: '',
-			orderString: '',
-			groupString: '',
-
-			// Other various values
-			limit: null,
-			offset: null
-		};
+	this.getCompiledInsert = function(table, reset) {
+		return _p.getCompile('insert', table, reset);
 	};
 
 	/**
-	 * Returns the current class state for testing or other purposes
+	 * Return generated update query SQL
 	 *
-	 * @return {Object}
+	 * @param {String} table - the name of the table to update
+	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+	 * @return {String}
 	 */
-	this.getState = function() {
-		return state;
+	this.getCompiledUpdate = function(table, reset) {
+		return _p.getCompile('update', table, reset);
+	};
+
+	/**
+	 * Return generated delete query SQL
+	 *
+	 * @param {String} table - the name of the table to delete from
+	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
+	 * @return {String}
+	 */
+	this.getCompiledDelete = function(table, reset) {
+		return _p.getCompile('delete', table, reset);
 	};
 
 	return this;
-};
-
-
+}; + +module.exports = QueryBuilder;
+
+
+ + + + + +
+ +
+
+ + + + DocStrap Copyright © 2012-2014 The contributors to the JSDoc3 and DocStrap projects. + +
+ + + Documentation generated by JSDoc 3.3.0-alpha9 + on Thu Oct 23rd 2014 using the DocStrap template. + +
+ + + +
+ + + + + + + + + + + - - + + -
- -
- Documentation generated by JSDoc 3.2.2 on Mon Oct 20 2014 16:34:02 GMT-0400 (EDT) -
- - - diff --git a/docs/scripts/URI.js b/docs/scripts/URI.js new file mode 100644 index 0000000..f8546c7 --- /dev/null +++ b/docs/scripts/URI.js @@ -0,0 +1,1429 @@ +/*! + * URI.js - Mutating URLs + * + * Version: 1.8.3 + * + * Author: Rodney Rehm + * Web: http://medialize.github.com/URI.js/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ +(function(root, factory) { + // https://github.com/umdjs/umd/blob/master/returnExports.js + if (typeof exports === 'object') { + // Node + module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains')); + } else if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['./punycode', './IPv6', './SecondLevelDomains'], factory); + } else { + // Browser globals (root is window) + root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains); + } +}(this, function(punycode, IPv6, SLD) { + "use strict"; + + function URI(url, base) { + // Allow instantiation without the 'new' keyword + if (!(this instanceof URI)) { + return new URI(url, base); + } + if (url === undefined) { + if (typeof location !== 'undefined') { + url = location.href + ""; + } else { + url = ""; + } + } + this.href(url); + // resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor + if (base !== undefined) { + return this.absoluteTo(base); + } + return this; + }; + var p = URI.prototype; + var hasOwn = Object.prototype.hasOwnProperty; + + function escapeRegEx(string) { + // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963 + return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); + } + + function isArray(obj) { + return String(Object.prototype.toString.call(obj)) === "[object Array]"; + } + + function filterArrayValues(data, value) { + var lookup = {}; + var i, length; + if (isArray(value)) { + for (i = 0, length = value.length; i < length; i++) { + lookup[value[i]] = true; + } + } else { + lookup[value] = true; + } + for (i = 0, length = data.length; i < length; i++) { + if (lookup[data[i]] !== undefined) { + data.splice(i, 1); + length--; + i--; + } + } + return data; + } + URI._parts = function() { + return { + protocol: null, + username: null, + password: null, + hostname: null, + urn: null, + port: null, + path: null, + query: null, + fragment: null, + // state + duplicateQueryParameters: URI.duplicateQueryParameters + }; + }; + // state: allow duplicate query parameters (a=1&a=1) + URI.duplicateQueryParameters = false; + // static properties + URI.protocol_expression = /^[a-z][a-z0-9-+-]*$/i; + URI.idn_expression = /[^a-z0-9\.-]/i; + URI.punycode_expression = /(xn--)/i; + // well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care? + URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; + // credits to Rich Brown + // source: http://forums.intermapper.com/viewtopic.php?p=1096#1096 + // specification: http://www.ietf.org/rfc/rfc4291.txt + URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/; + // gruber revised expression - http://rodneyrehm.de/t/url-regex.html + URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig; + // http://www.iana.org/assignments/uri-schemes.html + // http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports + URI.defaultPorts = { + http: "80", + https: "443", + ftp: "21", + gopher: "70", + ws: "80", + wss: "443" + }; + // allowed hostname characters according to RFC 3986 + // ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded + // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . - + URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/; + // encoding / decoding according to RFC3986 + + function strictEncodeURIComponent(string) { + // see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent + return encodeURIComponent(string).replace(/[!'()*]/g, escape).replace(/\*/g, "%2A"); + } + URI.encode = strictEncodeURIComponent; + URI.decode = decodeURIComponent; + URI.iso8859 = function() { + URI.encode = escape; + URI.decode = unescape; + }; + URI.unicode = function() { + URI.encode = strictEncodeURIComponent; + URI.decode = decodeURIComponent; + }; + URI.characters = { + pathname: { + encode: { + // RFC3986 2.1: For consistency, URI producers and normalizers should + // use uppercase hexadecimal digits for all percent-encodings. + expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig, + map: { + // -._~!'()* + "%24": "$", + "%26": "&", + "%2B": "+", + "%2C": ",", + "%3B": ";", + "%3D": "=", + "%3A": ":", + "%40": "@" + } + }, + decode: { + expression: /[\/\?#]/g, + map: { + "/": "%2F", + "?": "%3F", + "#": "%23" + } + } + }, + reserved: { + encode: { + // RFC3986 2.1: For consistency, URI producers and normalizers should + // use uppercase hexadecimal digits for all percent-encodings. + expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig, + map: { + // gen-delims + "%3A": ":", + "%2F": "/", + "%3F": "?", + "%23": "#", + "%5B": "[", + "%5D": "]", + "%40": "@", + // sub-delims + "%21": "!", + "%24": "$", + "%26": "&", + "%27": "'", + "%28": "(", + "%29": ")", + "%2A": "*", + "%2B": "+", + "%2C": ",", + "%3B": ";", + "%3D": "=" + } + } + } + }; + URI.encodeQuery = function(string) { + return URI.encode(string + "").replace(/%20/g, '+'); + }; + URI.decodeQuery = function(string) { + return URI.decode((string + "").replace(/\+/g, '%20')); + }; + URI.recodePath = function(string) { + var segments = (string + "").split('/'); + for (var i = 0, length = segments.length; i < length; i++) { + segments[i] = URI.encodePathSegment(URI.decode(segments[i])); + } + return segments.join('/'); + }; + URI.decodePath = function(string) { + var segments = (string + "").split('/'); + for (var i = 0, length = segments.length; i < length; i++) { + segments[i] = URI.decodePathSegment(segments[i]); + } + return segments.join('/'); + }; + // generate encode/decode path functions + var _parts = { + 'encode': 'encode', + 'decode': 'decode' + }; + var _part; + var generateAccessor = function(_group, _part) { + return function(string) { + return URI[_part](string + "").replace(URI.characters[_group][_part].expression, function(c) { + return URI.characters[_group][_part].map[c]; + }); + }; + }; + for (_part in _parts) { + URI[_part + "PathSegment"] = generateAccessor("pathname", _parts[_part]); + } + URI.encodeReserved = generateAccessor("reserved", "encode"); + URI.parse = function(string, parts) { + var pos, t; + if (!parts) { + parts = {}; + } + // [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment] + // extract fragment + pos = string.indexOf('#'); + if (pos > -1) { + // escaping? + parts.fragment = string.substring(pos + 1) || null; + string = string.substring(0, pos); + } + // extract query + pos = string.indexOf('?'); + if (pos > -1) { + // escaping? + parts.query = string.substring(pos + 1) || null; + string = string.substring(0, pos); + } + // extract protocol + if (string.substring(0, 2) === '//') { + // relative-scheme + parts.protocol = ''; + string = string.substring(2); + // extract "user:pass@host:port" + string = URI.parseAuthority(string, parts); + } else { + pos = string.indexOf(':'); + if (pos > -1) { + parts.protocol = string.substring(0, pos); + if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) { + // : may be within the path + parts.protocol = undefined; + } else if (parts.protocol === 'file') { + // the file scheme: does not contain an authority + string = string.substring(pos + 3); + } else if (string.substring(pos + 1, pos + 3) === '//') { + string = string.substring(pos + 3); + // extract "user:pass@host:port" + string = URI.parseAuthority(string, parts); + } else { + string = string.substring(pos + 1); + parts.urn = true; + } + } + } + // what's left must be the path + parts.path = string; + // and we're done + return parts; + }; + URI.parseHost = function(string, parts) { + // extract host:port + var pos = string.indexOf('/'); + var bracketPos; + var t; + if (pos === -1) { + pos = string.length; + } + if (string[0] === "[") { + // IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6 + // I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts + // IPv6+port in the format [2001:db8::1]:80 (for the time being) + bracketPos = string.indexOf(']'); + parts.hostname = string.substring(1, bracketPos) || null; + parts.port = string.substring(bracketPos + 2, pos) || null; + } else if (string.indexOf(':') !== string.lastIndexOf(':')) { + // IPv6 host contains multiple colons - but no port + // this notation is actually not allowed by RFC 3986, but we're a liberal parser + parts.hostname = string.substring(0, pos) || null; + parts.port = null; + } else { + t = string.substring(0, pos).split(':'); + parts.hostname = t[0] || null; + parts.port = t[1] || null; + } + if (parts.hostname && string.substring(pos)[0] !== '/') { + pos++; + string = "/" + string; + } + return string.substring(pos) || '/'; + }; + URI.parseAuthority = function(string, parts) { + string = URI.parseUserinfo(string, parts); + return URI.parseHost(string, parts); + }; + URI.parseUserinfo = function(string, parts) { + // extract username:password + var pos = string.indexOf('@'); + var firstSlash = string.indexOf('/'); + var t; + // authority@ must come before /path + if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) { + t = string.substring(0, pos).split(':'); + parts.username = t[0] ? URI.decode(t[0]) : null; + t.shift(); + parts.password = t[0] ? URI.decode(t.join(':')) : null; + string = string.substring(pos + 1); + } else { + parts.username = null; + parts.password = null; + } + return string; + }; + URI.parseQuery = function(string) { + if (!string) { + return {}; + } + // throw out the funky business - "?"[name"="value"&"]+ + string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, ''); + if (!string) { + return {}; + } + var items = {}; + var splits = string.split('&'); + var length = splits.length; + var v, name, value; + for (var i = 0; i < length; i++) { + v = splits[i].split('='); + name = URI.decodeQuery(v.shift()); + // no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters + value = v.length ? URI.decodeQuery(v.join('=')) : null; + if (items[name]) { + if (typeof items[name] === "string") { + items[name] = [items[name]]; + } + items[name].push(value); + } else { + items[name] = value; + } + } + return items; + }; + URI.build = function(parts) { + var t = ""; + if (parts.protocol) { + t += parts.protocol + ":"; + } + if (!parts.urn && (t || parts.hostname)) { + t += '//'; + } + t += (URI.buildAuthority(parts) || ''); + if (typeof parts.path === "string") { + if (parts.path[0] !== '/' && typeof parts.hostname === "string") { + t += '/'; + } + t += parts.path; + } + if (typeof parts.query === "string" && parts.query) { + t += '?' + parts.query; + } + if (typeof parts.fragment === "string" && parts.fragment) { + t += '#' + parts.fragment; + } + return t; + }; + URI.buildHost = function(parts) { + var t = ""; + if (!parts.hostname) { + return ""; + } else if (URI.ip6_expression.test(parts.hostname)) { + if (parts.port) { + t += "[" + parts.hostname + "]:" + parts.port; + } else { + // don't know if we should always wrap IPv6 in [] + // the RFC explicitly says SHOULD, not MUST. + t += parts.hostname; + } + } else { + t += parts.hostname; + if (parts.port) { + t += ':' + parts.port; + } + } + return t; + }; + URI.buildAuthority = function(parts) { + return URI.buildUserinfo(parts) + URI.buildHost(parts); + }; + URI.buildUserinfo = function(parts) { + var t = ""; + if (parts.username) { + t += URI.encode(parts.username); + if (parts.password) { + t += ':' + URI.encode(parts.password); + } + t += "@"; + } + return t; + }; + URI.buildQuery = function(data, duplicates) { + // according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html + // being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed + // the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax! + // URI.js treats the query string as being application/x-www-form-urlencoded + // see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type + var t = ""; + var unique, key, i, length; + for (key in data) { + if (hasOwn.call(data, key) && key) { + if (isArray(data[key])) { + unique = {}; + for (i = 0, length = data[key].length; i < length; i++) { + if (data[key][i] !== undefined && unique[data[key][i] + ""] === undefined) { + t += "&" + URI.buildQueryParameter(key, data[key][i]); + if (duplicates !== true) { + unique[data[key][i] + ""] = true; + } + } + } + } else if (data[key] !== undefined) { + t += '&' + URI.buildQueryParameter(key, data[key]); + } + } + } + return t.substring(1); + }; + URI.buildQueryParameter = function(name, value) { + // http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded + // don't append "=" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization + return URI.encodeQuery(name) + (value !== null ? "=" + URI.encodeQuery(value) : ""); + }; + URI.addQuery = function(data, name, value) { + if (typeof name === "object") { + for (var key in name) { + if (hasOwn.call(name, key)) { + URI.addQuery(data, key, name[key]); + } + } + } else if (typeof name === "string") { + if (data[name] === undefined) { + data[name] = value; + return; + } else if (typeof data[name] === "string") { + data[name] = [data[name]]; + } + if (!isArray(value)) { + value = [value]; + } + data[name] = data[name].concat(value); + } else { + throw new TypeError("URI.addQuery() accepts an object, string as the name parameter"); + } + }; + URI.removeQuery = function(data, name, value) { + var i, length, key; + if (isArray(name)) { + for (i = 0, length = name.length; i < length; i++) { + data[name[i]] = undefined; + } + } else if (typeof name === "object") { + for (key in name) { + if (hasOwn.call(name, key)) { + URI.removeQuery(data, key, name[key]); + } + } + } else if (typeof name === "string") { + if (value !== undefined) { + if (data[name] === value) { + data[name] = undefined; + } else if (isArray(data[name])) { + data[name] = filterArrayValues(data[name], value); + } + } else { + data[name] = undefined; + } + } else { + throw new TypeError("URI.addQuery() accepts an object, string as the first parameter"); + } + }; + URI.commonPath = function(one, two) { + var length = Math.min(one.length, two.length); + var pos; + // find first non-matching character + for (pos = 0; pos < length; pos++) { + if (one[pos] !== two[pos]) { + pos--; + break; + } + } + if (pos < 1) { + return one[0] === two[0] && one[0] === '/' ? '/' : ''; + } + // revert to last / + if (one[pos] !== '/') { + pos = one.substring(0, pos).lastIndexOf('/'); + } + return one.substring(0, pos + 1); + }; + URI.withinString = function(string, callback) { + // expression used is "gruber revised" (@gruber v2) determined to be the best solution in + // a regex sprint we did a couple of ages ago at + // * http://mathiasbynens.be/demo/url-regex + // * http://rodneyrehm.de/t/url-regex.html + return string.replace(URI.find_uri_expression, callback); + }; + URI.ensureValidHostname = function(v) { + // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986) + // they are not part of DNS and therefore ignored by URI.js + if (v.match(URI.invalid_hostname_characters)) { + // test punycode + if (!punycode) { + throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-] and Punycode.js is not available"); + } + if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) { + throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-]"); + } + } + }; + p.build = function(deferBuild) { + if (deferBuild === true) { + this._deferred_build = true; + } else if (deferBuild === undefined || this._deferred_build) { + this._string = URI.build(this._parts); + this._deferred_build = false; + } + return this; + }; + p.clone = function() { + return new URI(this); + }; + p.valueOf = p.toString = function() { + return this.build(false)._string; + }; + // generate simple accessors + _parts = { + protocol: 'protocol', + username: 'username', + password: 'password', + hostname: 'hostname', + port: 'port' + }; + generateAccessor = function(_part) { + return function(v, build) { + if (v === undefined) { + return this._parts[_part] || ""; + } else { + this._parts[_part] = v; + this.build(!build); + return this; + } + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_parts[_part]); + } + // generate accessors with optionally prefixed input + _parts = { + query: '?', + fragment: '#' + }; + generateAccessor = function(_part, _key) { + return function(v, build) { + if (v === undefined) { + return this._parts[_part] || ""; + } else { + if (v !== null) { + v = v + ""; + if (v[0] === _key) { + v = v.substring(1); + } + } + this._parts[_part] = v; + this.build(!build); + return this; + } + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_part, _parts[_part]); + } + // generate accessors with prefixed output + _parts = { + search: ['?', 'query'], + hash: ['#', 'fragment'] + }; + generateAccessor = function(_part, _key) { + return function(v, build) { + var t = this[_part](v, build); + return typeof t === "string" && t.length ? (_key + t) : t; + }; + }; + for (_part in _parts) { + p[_part] = generateAccessor(_parts[_part][1], _parts[_part][0]); + } + p.pathname = function(v, build) { + if (v === undefined || v === true) { + var res = this._parts.path || (this._parts.urn ? '' : '/'); + return v ? URI.decodePath(res) : res; + } else { + this._parts.path = v ? URI.recodePath(v) : "/"; + this.build(!build); + return this; + } + }; + p.path = p.pathname; + p.href = function(href, build) { + var key; + if (href === undefined) { + return this.toString(); + } + this._string = ""; + this._parts = URI._parts(); + var _URI = href instanceof URI; + var _object = typeof href === "object" && (href.hostname || href.path); + // window.location is reported to be an object, but it's not the sort + // of object we're looking for: + // * location.protocol ends with a colon + // * location.query != object.search + // * location.hash != object.fragment + // simply serializing the unknown object should do the trick + // (for location, not for everything...) + if (!_URI && _object && Object.prototype.toString.call(href) !== "[object Object]") { + href = href.toString(); + } + if (typeof href === "string") { + this._parts = URI.parse(href, this._parts); + } else if (_URI || _object) { + var src = _URI ? href._parts : href; + for (key in src) { + if (hasOwn.call(this._parts, key)) { + this._parts[key] = src[key]; + } + } + } else { + throw new TypeError("invalid input"); + } + this.build(!build); + return this; + }; + // identification accessors + p.is = function(what) { + var ip = false; + var ip4 = false; + var ip6 = false; + var name = false; + var sld = false; + var idn = false; + var punycode = false; + var relative = !this._parts.urn; + if (this._parts.hostname) { + relative = false; + ip4 = URI.ip4_expression.test(this._parts.hostname); + ip6 = URI.ip6_expression.test(this._parts.hostname); + ip = ip4 || ip6; + name = !ip; + sld = name && SLD && SLD.has(this._parts.hostname); + idn = name && URI.idn_expression.test(this._parts.hostname); + punycode = name && URI.punycode_expression.test(this._parts.hostname); + } + switch (what.toLowerCase()) { + case 'relative': + return relative; + case 'absolute': + return !relative; + // hostname identification + case 'domain': + case 'name': + return name; + case 'sld': + return sld; + case 'ip': + return ip; + case 'ip4': + case 'ipv4': + case 'inet4': + return ip4; + case 'ip6': + case 'ipv6': + case 'inet6': + return ip6; + case 'idn': + return idn; + case 'url': + return !this._parts.urn; + case 'urn': + return !!this._parts.urn; + case 'punycode': + return punycode; + } + return null; + }; + // component specific input validation + var _protocol = p.protocol; + var _port = p.port; + var _hostname = p.hostname; + p.protocol = function(v, build) { + if (v !== undefined) { + if (v) { + // accept trailing :// + v = v.replace(/:(\/\/)?$/, ''); + if (v.match(/[^a-zA-z0-9\.+-]/)) { + throw new TypeError("Protocol '" + v + "' contains characters other than [A-Z0-9.+-]"); + } + } + } + return _protocol.call(this, v, build); + }; + p.scheme = p.protocol; + p.port = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v !== undefined) { + if (v === 0) { + v = null; + } + if (v) { + v += ""; + if (v[0] === ":") { + v = v.substring(1); + } + if (v.match(/[^0-9]/)) { + throw new TypeError("Port '" + v + "' contains characters other than [0-9]"); + } + } + } + return _port.call(this, v, build); + }; + p.hostname = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v !== undefined) { + var x = {}; + URI.parseHost(v, x); + v = x.hostname; + } + return _hostname.call(this, v, build); + }; + // compound accessors + p.host = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + return this._parts.hostname ? URI.buildHost(this._parts) : ""; + } else { + URI.parseHost(v, this._parts); + this.build(!build); + return this; + } + }; + p.authority = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + return this._parts.hostname ? URI.buildAuthority(this._parts) : ""; + } else { + URI.parseAuthority(v, this._parts); + this.build(!build); + return this; + } + }; + p.userinfo = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined) { + if (!this._parts.username) { + return ""; + } + var t = URI.buildUserinfo(this._parts); + return t.substring(0, t.length - 1); + } else { + if (v[v.length - 1] !== '@') { + v += '@'; + } + URI.parseUserinfo(v, this._parts); + this.build(!build); + return this; + } + }; + p.resource = function(v, build) { + var parts; + if (v === undefined) { + return this.path() + this.search() + this.hash(); + } + parts = URI.parse(v); + this._parts.path = parts.path; + this._parts.query = parts.query; + this._parts.fragment = parts.fragment; + this.build(!build); + return this; + }; + // fraction accessors + p.subdomain = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + // convenience, return "www" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + // grab domain and add another segment + var end = this._parts.hostname.length - this.domain().length - 1; + return this._parts.hostname.substring(0, end) || ""; + } else { + var e = this._parts.hostname.length - this.domain().length; + var sub = this._parts.hostname.substring(0, e); + var replace = new RegExp('^' + escapeRegEx(sub)); + if (v && v[v.length - 1] !== '.') { + v += "."; + } + if (v) { + URI.ensureValidHostname(v); + } + this._parts.hostname = this._parts.hostname.replace(replace, v); + this.build(!build); + return this; + } + }; + p.domain = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (typeof v === 'boolean') { + build = v; + v = undefined; + } + // convenience, return "example.org" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + // if hostname consists of 1 or 2 segments, it must be the domain + var t = this._parts.hostname.match(/\./g); + if (t && t.length < 2) { + return this._parts.hostname; + } + // grab tld and add another segment + var end = this._parts.hostname.length - this.tld(build).length - 1; + end = this._parts.hostname.lastIndexOf('.', end - 1) + 1; + return this._parts.hostname.substring(end) || ""; + } else { + if (!v) { + throw new TypeError("cannot set domain empty"); + } + URI.ensureValidHostname(v); + if (!this._parts.hostname || this.is('IP')) { + this._parts.hostname = v; + } else { + var replace = new RegExp(escapeRegEx(this.domain()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.tld = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (typeof v === 'boolean') { + build = v; + v = undefined; + } + // return "org" from "www.example.org" + if (v === undefined) { + if (!this._parts.hostname || this.is('IP')) { + return ""; + } + var pos = this._parts.hostname.lastIndexOf('.'); + var tld = this._parts.hostname.substring(pos + 1); + if (build !== true && SLD && SLD.list[tld.toLowerCase()]) { + return SLD.get(this._parts.hostname) || tld; + } + return tld; + } else { + var replace; + if (!v) { + throw new TypeError("cannot set TLD empty"); + } else if (v.match(/[^a-zA-Z0-9-]/)) { + if (SLD && SLD.is(v)) { + replace = new RegExp(escapeRegEx(this.tld()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } else { + throw new TypeError("TLD '" + v + "' contains characters other than [A-Z0-9]"); + } + } else if (!this._parts.hostname || this.is('IP')) { + throw new ReferenceError("cannot set TLD on non-domain host"); + } else { + replace = new RegExp(escapeRegEx(this.tld()) + "$"); + this._parts.hostname = this._parts.hostname.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.directory = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path && !this._parts.hostname) { + return ''; + } + if (this._parts.path === '/') { + return '/'; + } + var end = this._parts.path.length - this.filename().length - 1; + var res = this._parts.path.substring(0, end) || (this._parts.hostname ? "/" : ""); + return v ? URI.decodePath(res) : res; + } else { + var e = this._parts.path.length - this.filename().length; + var directory = this._parts.path.substring(0, e); + var replace = new RegExp('^' + escapeRegEx(directory)); + // fully qualifier directories begin with a slash + if (!this.is('relative')) { + if (!v) { + v = '/'; + } + if (v[0] !== '/') { + v = "/" + v; + } + } + // directories always end with a slash + if (v && v[v.length - 1] !== '/') { + v += '/'; + } + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + this.build(!build); + return this; + } + }; + p.filename = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path || this._parts.path === '/') { + return ""; + } + var pos = this._parts.path.lastIndexOf('/'); + var res = this._parts.path.substring(pos + 1); + return v ? URI.decodePathSegment(res) : res; + } else { + var mutatedDirectory = false; + if (v[0] === '/') { + v = v.substring(1); + } + if (v.match(/\.?\//)) { + mutatedDirectory = true; + } + var replace = new RegExp(escapeRegEx(this.filename()) + "$"); + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + if (mutatedDirectory) { + this.normalizePath(build); + } else { + this.build(!build); + } + return this; + } + }; + p.suffix = function(v, build) { + if (this._parts.urn) { + return v === undefined ? '' : this; + } + if (v === undefined || v === true) { + if (!this._parts.path || this._parts.path === '/') { + return ""; + } + var filename = this.filename(); + var pos = filename.lastIndexOf('.'); + var s, res; + if (pos === -1) { + return ""; + } + // suffix may only contain alnum characters (yup, I made this up.) + s = filename.substring(pos + 1); + res = (/^[a-z0-9%]+$/i).test(s) ? s : ""; + return v ? URI.decodePathSegment(res) : res; + } else { + if (v[0] === '.') { + v = v.substring(1); + } + var suffix = this.suffix(); + var replace; + if (!suffix) { + if (!v) { + return this; + } + this._parts.path += '.' + URI.recodePath(v); + } else if (!v) { + replace = new RegExp(escapeRegEx("." + suffix) + "$"); + } else { + replace = new RegExp(escapeRegEx(suffix) + "$"); + } + if (replace) { + v = URI.recodePath(v); + this._parts.path = this._parts.path.replace(replace, v); + } + this.build(!build); + return this; + } + }; + p.segment = function(segment, v, build) { + var separator = this._parts.urn ? ':' : '/'; + var path = this.path(); + var absolute = path.substring(0, 1) === '/'; + var segments = path.split(separator); + if (typeof segment !== 'number') { + build = v; + v = segment; + segment = undefined; + } + if (segment !== undefined && typeof segment !== 'number') { + throw new Error("Bad segment '" + segment + "', must be 0-based integer"); + } + if (absolute) { + segments.shift(); + } + if (segment < 0) { + // allow negative indexes to address from the end + segment = Math.max(segments.length + segment, 0); + } + if (v === undefined) { + return segment === undefined ? segments : segments[segment]; + } else if (segment === null || segments[segment] === undefined) { + if (isArray(v)) { + segments = v; + } else if (v || (typeof v === "string" && v.length)) { + if (segments[segments.length - 1] === "") { + // empty trailing elements have to be overwritten + // to prefent results such as /foo//bar + segments[segments.length - 1] = v; + } else { + segments.push(v); + } + } + } else { + if (v || (typeof v === "string" && v.length)) { + segments[segment] = v; + } else { + segments.splice(segment, 1); + } + } + if (absolute) { + segments.unshift(""); + } + return this.path(segments.join(separator), build); + }; + // mutating query string + var q = p.query; + p.query = function(v, build) { + if (v === true) { + return URI.parseQuery(this._parts.query); + } else if (v !== undefined && typeof v !== "string") { + this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters); + this.build(!build); + return this; + } else { + return q.call(this, v, build); + } + }; + p.addQuery = function(name, value, build) { + var data = URI.parseQuery(this._parts.query); + URI.addQuery(data, name, value === undefined ? null : value); + this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); + if (typeof name !== "string") { + build = value; + } + this.build(!build); + return this; + }; + p.removeQuery = function(name, value, build) { + var data = URI.parseQuery(this._parts.query); + URI.removeQuery(data, name, value); + this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters); + if (typeof name !== "string") { + build = value; + } + this.build(!build); + return this; + }; + p.addSearch = p.addQuery; + p.removeSearch = p.removeQuery; + // sanitizing URLs + p.normalize = function() { + if (this._parts.urn) { + return this.normalizeProtocol(false).normalizeQuery(false).normalizeFragment(false).build(); + } + return this.normalizeProtocol(false).normalizeHostname(false).normalizePort(false).normalizePath(false).normalizeQuery(false).normalizeFragment(false).build(); + }; + p.normalizeProtocol = function(build) { + if (typeof this._parts.protocol === "string") { + this._parts.protocol = this._parts.protocol.toLowerCase(); + this.build(!build); + } + return this; + }; + p.normalizeHostname = function(build) { + if (this._parts.hostname) { + if (this.is('IDN') && punycode) { + this._parts.hostname = punycode.toASCII(this._parts.hostname); + } else if (this.is('IPv6') && IPv6) { + this._parts.hostname = IPv6.best(this._parts.hostname); + } + this._parts.hostname = this._parts.hostname.toLowerCase(); + this.build(!build); + } + return this; + }; + p.normalizePort = function(build) { + // remove port of it's the protocol's default + if (typeof this._parts.protocol === "string" && this._parts.port === URI.defaultPorts[this._parts.protocol]) { + this._parts.port = null; + this.build(!build); + } + return this; + }; + p.normalizePath = function(build) { + if (this._parts.urn) { + return this; + } + if (!this._parts.path || this._parts.path === '/') { + return this; + } + var _was_relative; + var _was_relative_prefix; + var _path = this._parts.path; + var _parent, _pos; + // handle relative paths + if (_path[0] !== '/') { + if (_path[0] === '.') { + _was_relative_prefix = _path.substring(0, _path.indexOf('/')); + } + _was_relative = true; + _path = '/' + _path; + } + // resolve simples + _path = _path.replace(/(\/(\.\/)+)|\/{2,}/g, '/'); + // resolve parents + while (true) { + _parent = _path.indexOf('/../'); + if (_parent === -1) { + // no more ../ to resolve + break; + } else if (_parent === 0) { + // top level cannot be relative... + _path = _path.substring(3); + break; + } + _pos = _path.substring(0, _parent).lastIndexOf('/'); + if (_pos === -1) { + _pos = _parent; + } + _path = _path.substring(0, _pos) + _path.substring(_parent + 3); + } + // revert to relative + if (_was_relative && this.is('relative')) { + if (_was_relative_prefix) { + _path = _was_relative_prefix + _path; + } else { + _path = _path.substring(1); + } + } + _path = URI.recodePath(_path); + this._parts.path = _path; + this.build(!build); + return this; + }; + p.normalizePathname = p.normalizePath; + p.normalizeQuery = function(build) { + if (typeof this._parts.query === "string") { + if (!this._parts.query.length) { + this._parts.query = null; + } else { + this.query(URI.parseQuery(this._parts.query)); + } + this.build(!build); + } + return this; + }; + p.normalizeFragment = function(build) { + if (!this._parts.fragment) { + this._parts.fragment = null; + this.build(!build); + } + return this; + }; + p.normalizeSearch = p.normalizeQuery; + p.normalizeHash = p.normalizeFragment; + p.iso8859 = function() { + // expect unicode input, iso8859 output + var e = URI.encode; + var d = URI.decode; + URI.encode = escape; + URI.decode = decodeURIComponent; + this.normalize(); + URI.encode = e; + URI.decode = d; + return this; + }; + p.unicode = function() { + // expect iso8859 input, unicode output + var e = URI.encode; + var d = URI.decode; + URI.encode = strictEncodeURIComponent; + URI.decode = unescape; + this.normalize(); + URI.encode = e; + URI.decode = d; + return this; + }; + p.readable = function() { + var uri = this.clone(); + // removing username, password, because they shouldn't be displayed according to RFC 3986 + uri.username("").password("").normalize(); + var t = ''; + if (uri._parts.protocol) { + t += uri._parts.protocol + '://'; + } + if (uri._parts.hostname) { + if (uri.is('punycode') && punycode) { + t += punycode.toUnicode(uri._parts.hostname); + if (uri._parts.port) { + t += ":" + uri._parts.port; + } + } else { + t += uri.host(); + } + } + if (uri._parts.hostname && uri._parts.path && uri._parts.path[0] !== '/') { + t += '/'; + } + t += uri.path(true); + if (uri._parts.query) { + var q = ''; + for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) { + var kv = (qp[i] || "").split('='); + q += '&' + URI.decodeQuery(kv[0]).replace(/&/g, '%26'); + if (kv[1] !== undefined) { + q += "=" + URI.decodeQuery(kv[1]).replace(/&/g, '%26'); + } + } + t += '?' + q.substring(1); + } + t += uri.hash(); + return t; + }; + // resolving relative and absolute URLs + p.absoluteTo = function(base) { + var resolved = this.clone(); + var properties = ['protocol', 'username', 'password', 'hostname', 'port']; + var basedir, i, p; + if (this._parts.urn) { + throw new Error('URNs do not have any generally defined hierachical components'); + } + if (this._parts.hostname) { + return resolved; + } + if (!(base instanceof URI)) { + base = new URI(base); + } + for (i = 0, p; p = properties[i]; i++) { + resolved._parts[p] = base._parts[p]; + } + properties = ['query', 'path']; + for (i = 0, p; p = properties[i]; i++) { + if (!resolved._parts[p] && base._parts[p]) { + resolved._parts[p] = base._parts[p]; + } + } + if (resolved.path()[0] !== '/') { + basedir = base.directory(); + resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path; + resolved.normalizePath(); + } + resolved.build(); + return resolved; + }; + p.relativeTo = function(base) { + var relative = this.clone(); + var properties = ['protocol', 'username', 'password', 'hostname', 'port']; + var common, _base, _this, _base_diff, _this_diff; + if (this._parts.urn) { + throw new Error('URNs do not have any generally defined hierachical components'); + } + if (!(base instanceof URI)) { + base = new URI(base); + } + if (this.path()[0] !== '/' || base.path()[0] !== '/') { + throw new Error('Cannot calculate common path from non-relative URLs'); + } + // determine common sub path + common = URI.commonPath(relative.path(), base.path()); + // no relation if there's nothing in common + if (!common || common === '/') { + return relative; + } + // relative paths don't have authority + for (var i = 0, p; p = properties[i]; i++) { + relative._parts[p] = null; + } + _base = base.directory(); + _this = this.directory(); + // base and this are on the same level + if (_base === _this) { + relative._parts.path = './' + relative.filename(); + return relative.build(); + } + _base_diff = _base.substring(common.length); + _this_diff = _this.substring(common.length); + // this is a descendant of base + if (_base + '/' === common) { + if (_this_diff) { + _this_diff += '/'; + } + relative._parts.path = './' + _this_diff + relative.filename(); + return relative.build(); + } + // this is a descendant of base + var parents = '../'; + var _common = new RegExp('^' + escapeRegEx(common)); + var _parents = _base.replace(_common, '/').match(/\//g).length - 1; + while (_parents--) { + parents += '../'; + } + relative._parts.path = relative._parts.path.replace(_common, parents); + return relative.build(); + }; + // comparing URIs + p.equals = function(uri) { + var one = this.clone(); + var two = new URI(uri); + var one_map = {}; + var two_map = {}; + var checked = {}; + var one_query, two_query, key; + one.normalize(); + two.normalize(); + // exact match + if (one.toString() === two.toString()) { + return true; + } + // extract query string + one_query = one.query(); + two_query = two.query(); + one.query(""); + two.query(""); + // definitely not equal if not even non-query parts match + if (one.toString() !== two.toString()) { + return false; + } + // query parameters have the same length, even if they're permutated + if (one_query.length !== two_query.length) { + return false; + } + one_map = URI.parseQuery(one_query); + two_map = URI.parseQuery(two_query); + for (key in one_map) { + if (hasOwn.call(one_map, key)) { + if (!isArray(one_map[key])) { + if (one_map[key] !== two_map[key]) { + return false; + } + } else { + if (!isArray(two_map[key])) { + return false; + } + // arrays can't be equal if they have different amount of content + if (one_map[key].length !== two_map[key].length) { + return false; + } + one_map[key].sort(); + two_map[key].sort(); + for (var i = 0, l = one_map[key].length; i < l; i++) { + if (one_map[key][i] !== two_map[key][i]) { + return false; + } + } + } + checked[key] = true; + } + } + for (key in two_map) { + if (hasOwn.call(two_map, key)) { + if (!checked[key]) { + // two contains a parameter not present in one + return false; + } + } + } + return true; + }; + // state + p.duplicateQueryParameters = function(v) { + this._parts.duplicateQueryParameters = !! v; + return this; + }; + return URI; +})); \ No newline at end of file diff --git a/docs/scripts/bootstrap-dropdown.js b/docs/scripts/bootstrap-dropdown.js new file mode 100644 index 0000000..d04da5d --- /dev/null +++ b/docs/scripts/bootstrap-dropdown.js @@ -0,0 +1,169 @@ +/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://getbootstrap.com/2.3.2/javascript.html#dropdowns + * ============================================================ + * Copyright 2013 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('