From 8dd9b54af501ea78720d0e12bd1fe16745ab081f Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Sun, 4 Nov 2018 18:34:33 -0600 Subject: [PATCH 01/20] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e4c30ae..b38d226 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,6 @@ # SQL Bricks.js -[![Build Status](https://travis-ci.org/CSNW/sql-bricks.png?branch=master)](https://travis-ci.org/CSNW/sql-bricks) +[![Build Status](https://travis-ci.org/CSNW/sql-bricks.svg?branch=master)](https://travis-ci.org/CSNW/sql-bricks) SQL Bricks.js is a transparent, schemaless library for building and composing SQL statements. From fa026723865a1f7ad74c2c71445c91d555015b4c Mon Sep 17 00:00:00 2001 From: Paleo Date: Fri, 14 Dec 2018 10:35:07 +0100 Subject: [PATCH 02/20] Add TypeScript definitions --- package.json | 1 + sql-bricks.d.ts | 408 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 409 insertions(+) create mode 100644 sql-bricks.d.ts diff --git a/package.json b/package.json index 29fbe49..4ca34e6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "test": "mocha tests/tests.js tests/doctests.js && mocha tests/tests.js tests/doctests.js --empty-extension" }, "main": "sql-bricks.js", + "types": "sql-bricks.d.ts", "repository": { "type": "git", "url": "https://github.com/CSNW/sql-bricks.git" diff --git a/sql-bricks.d.ts b/sql-bricks.d.ts new file mode 100644 index 0000000..5496b6c --- /dev/null +++ b/sql-bricks.d.ts @@ -0,0 +1,408 @@ +// Type definitions for sql-bricks 2.0 +// Project: http://csnw.github.io/sql-bricks +// Definitions by: Narcisse Assogba +// Paleo + +declare namespace SqlBricks { + /** + * Statement is an abstract base class for all statements (SELECT, INSERT, UPDATE, DELETE) + * and should never be instantiated directly. It is exposed because it can be used with the + * instanceof operator to easily determine whether something is a SQL Bricks statement: my_var instanceof Statement. + */ + interface Statement { + /** + * Clones a statement so that subsequent modifications do not affect the original statement. + */ + clone(): this + + /** + * Returns the non-parameterized SQL for the statement. This is called implicitly by Javascript when using a Statement anywhere that a string is expected (string concatenation, Array.join(), etc). + * While toString() is easy to use, it is not recommended in most cases because: + * It doesn't provide robust protection against SQL injection attacks (it just does basic escaping) + * It doesn't provide as much support for complex data types (objects, arrays, etc, are "stringified" before being passed to your database driver, which then has to interpret them correctly) + * It does not provide the same level of detail in error messages (see this issue) + * For the above reasons, it is usually better to use toParams(). + */ + toString(): string + + /** + * Returns an object with two properties: a parameterized text string and a values array. The values are populated with anything on the right-hand side + * of a WHERE criteria,as well as any values passed into an insert() or update() (they can be passed explicitly with val() or opted out of with sql()) + * @param options A placeholder option of '?%d' can be passed to generate placeholders compatible with node-sqlite3 (%d is replaced with the parameter #): + * @example + * update('person', {'first_name': 'Fred'}).where({'last_name': 'Flintstone'}).toParams({placeholder: '?%d'}); + * // {"text": "UPDATE person SET first_name = ?1 WHERE last_name = ?2", "values": ["Fred", "Flintstone"]} + */ + toParams(options?: { placeholder: string }): SqlBricksParam + } + + interface SqlBricksParam { + text: string + values: any[] + } + + type TableName = string | SelectStatement + + interface OnCriteria { + [column: string]: string + } + + interface WhereObject { + [column: string]: any + } + + interface WhereGroup { + op?: string + expressions: WhereExpression[] + } + + interface WhereBinary { + op: string + col: string | SelectStatement + val: any + quantifier: string + } + + /** + * When a non-expression object is passed somewhere a whereExpression is expected, + * each key/value pair will be ANDed together: + */ + type WhereExpression = WhereGroup | WhereBinary | WhereObject | string + + /** + * A SELECT statement + */ + interface SelectStatement extends Statement { + /** + * Appends additional columns to an existing query. + * @param columns can be passed as multiple arguments, a comma-delimited string or an array. + */ + select(...columns: Array): SelectStatement + /** + * Appends additional columns to an existing query. + * @param columns can be passed as multiple arguments, a comma-delimited string or an array. + */ + select(columns: string[] | SelectStatement[]): SelectStatement + + as(alias: string): SelectStatement + + distinct(...columns: Array): SelectStatement + distinct(columns: string[] | SelectStatement[]): SelectStatement + + /** + * Makes the query a SELECT ... INTO query (which creates a new table with the results of the query). + * @alias intoTable + * @param tbl new table to create + */ + into(tbl: TableName): SelectStatement + /** + * Makes the query a SELECT ... INTO query (which creates a new table with the results of the query). + * @alias into + * @param tbl new table to create + */ + intoTable(tbl: TableName): SelectStatement + + intoTemp(tbl: TableName): SelectStatement + intoTempTable(tbl: TableName): SelectStatement + + /** + * Table names can be passed in as multiple string arguments, a comma-delimited string or an array. + * @param tbls table names + */ + from(...tbls: TableName[]): SelectStatement + /** + * Table names can be passed in as multiple string arguments, a comma-delimited string or an array. + * @param tbls array of table names + */ + from(tbls: TableName[]): SelectStatement + + /** + * Adds the specified join to the query. + * @alias innerJoin + * @param tbl can include an alias after a space or after the 'AS' keyword ('my_table my_alias'). + * @param onCriteria is optional if a joinCriteria function has been supplied. + */ + join(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + join(tbl: string, onCol1: string, onCol2: string): SelectStatement + join(firstTbl: string, ...otherTbls: string[]): SelectStatement + + leftJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + leftJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + leftJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + rightJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + rightJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + rightJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + fullJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + fullJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + fullJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + crossJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + crossJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + crossJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + innerJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + innerJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + innerJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + leftOuterJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + leftOuterJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + leftOuterJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + rightOuterJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + rightOuterJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + rightOuterJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + fullOuterJoin(tbl: string, criteria?: OnCriteria | string[] | WhereExpression): SelectStatement + fullOuterJoin(tbl: string, onCol1: string, onCol2: string): SelectStatement + fullOuterJoin(firstTbl: string, ...otherTbls: string[]): SelectStatement + + on(onCriteria: OnCriteria | WhereExpression): SelectStatement + on(onCol1: string, onCol2: string): SelectStatement + + /** + * Joins using USING instead of ON. + * @param columnList columnList can be passed in as one or more string arguments, a comma-delimited string, or an array. + * @example + * select('*').from('person').join('address').using('address_id', 'country_id'); + * // SELECT * FROM person INNER JOIN address USING (address_id, country_id) + */ + using(...columnList: string[]): SelectStatement + using(columnList: string[]): SelectStatement + + /** + * Adds the specified natural join to the query. + * @param tbl can include an alias after a space or after the 'AS' keyword ('my_table my_alias'). + */ + naturalJoin(tbl: string): SelectStatement + naturalLeftJoin(tbl: string): SelectStatement + naturalRightJoin(tbl: string): SelectStatement + naturalFullJoin(tbl: string): SelectStatement + + naturalInnerJoin(tbl: string): SelectStatement + naturalLeftOuterJoin(tbl: string): SelectStatement + naturalRightOuterJoin(tbl: string): SelectStatement + naturalFullOuterJoin(tbl: string): SelectStatement + + where(column?: string | null, value?: any): SelectStatement + where(...whereExpr: WhereExpression[]): SelectStatement + + and(...options: any[]): SelectStatement + + /** + * Sets or extends the GROUP BY columns. + * @param columns can take multiple arguments, a single comma-delimited string or an array. + */ + groupBy(...columns: string[]): SelectStatement + groupBy(columns: string[]): SelectStatement + + having(column: string, value: string): SelectStatement + having(whereExpr: WhereExpression): SelectStatement + + /** + * Sets or extends the list of columns in the ORDER BY clause. + * @param columns can be passed as multiple arguments, a single comma-delimited string or an array. + */ + orderBy(...columns: string[]): SelectStatement + orderBy(columns: string[]): SelectStatement + order(...columns: string[]): SelectStatement + order(columns: string[]): SelectStatement + + forUpdate(...tbls: string[]): SelectStatement + of(tlb: string): SelectStatement + noWait(): SelectStatement + + union(...stmt: Statement[]): SelectStatement + intersect(...stmt: Statement[]): SelectStatement + minus(...stmt: Statement[]): SelectStatement + except(...stmt: Statement[]): SelectStatement + } + + /** + * An INSERT statement + */ + interface InsertStatement extends Statement { + into(tbl: TableName, ...columns: any[]): InsertStatement + intoTable(tbl: TableName, ...columns: any[]): InsertStatement + select(...columns: Array): InsertStatement + select(columns: string[] | SelectStatement[]): InsertStatement + values(...values: any[]): InsertStatement + } + + /** + * An UPDATE statement + */ + interface UpdateStatement extends Statement { + values(...values: any[]): UpdateStatement + set(...values: any[]): UpdateStatement + where(column?: string | null, value?: any): UpdateStatement + where(...whereExpr: WhereExpression[]): UpdateStatement + and(column?: string | null, value?: any): UpdateStatement + and(...whereExpr: WhereExpression[]): UpdateStatement + } + + /** + * A DELETE statement + */ + interface DeleteStatement extends Statement { + from(...tbls: string[]): DeleteStatement + using(...columnList: string[]): DeleteStatement + using(columnList: string[]): DeleteStatement + where(column?: string | null, value?: any): DeleteStatement + where(...whereExpr: WhereExpression[]): DeleteStatement + and(column?: string | null, value?: any): DeleteStatement + and(...whereExpr: WhereExpression[]): DeleteStatement + } +} + +interface SqlBricksFn { + (...params: any[]): any + /** + * Wraps a value (user-supplied string, number, boolean, etc) so that it can be passed into SQL Bricks + * anywhere that a column is expected (the left-hand side of WHERE criteria and many other SQL Bricks APIs) + * @param value value to be wraped + */ + val(value: any): any + + /** + * Returns a new INSERT statement. It can be used with or without the new operator. + * @alias insertInto + * @param tbl table name + * @param values a values object or a columns list. Passing a set of columns (as multiple arguments, a comma-delimited string or an array) + * will put the statement into split keys/values mode, where a matching array of values is expected in values() + * @example + * insert('person', {'first_name': 'Fred', 'last_name': 'Flintstone'}); + * // INSERT INTO person (first_name, last_name) VALUES ('Fred', 'Flintstone') + */ + insert(tbl?: string, ...values: any[]): SqlBricks.InsertStatement + + /** + * Returns a new INSERT statement. It can be used with or without the new operator. + * @alias insert + * @param tbl table name + * @param values a values object or a columns list. Passing a set of columns (as multiple arguments, a comma-delimited string or an array) + * will put the statement into split keys/values mode, where a matching array of values is expected in values() + * @example + * insert('person', {'first_name': 'Fred', 'last_name': 'Flintstone'}); + * // INSERT INTO person (first_name, last_name) VALUES ('Fred', 'Flintstone') + */ + insertInto(tbl?: string, ...values: any[]): SqlBricks.InsertStatement + + /** + * Returns a new select statement, seeded with a set of columns. It can be used with or without the new keyword. + * @param columns it can be passed in here (or appended later via sel.select() or sel.distinct()) via multiple arguments + * or a comma-delimited string or an array. If no columns are specified, toString() will default to SELECT *. + */ + select(...columns: Array): SqlBricks.SelectStatement + select(columns: string[] | SqlBricks.SelectStatement[]): SqlBricks.SelectStatement + + /** + * Returns a new UPDATE statement. It can be used with or without the new operator. + * @param tbl table name + * @param values + */ + update(tbl: string, ...values: any[]): SqlBricks.UpdateStatement + + /** + * Returns a new DELETE statement. It can be used with or without the new operator. + * @alias deleteFrom + * @param tbl table name + */ + delete(tbl?: string): SqlBricks.DeleteStatement + /** + * Returns a new DELETE statement. It can be used with or without the new operator. + * @alias delete + * @param tbl table name + */ + deleteFrom(tbl?: string): SqlBricks.DeleteStatement + + /** + * Registers a set of frequently-used table aliases with SQL Bricks. + * These table aliases can then be used by themselves in from(), join(), etc + * and SQL Bricks will automatically expand them to include the table name as well as the alias. + * @param expansions + * @example + * sql.aliasExpansions({'psn': 'person', 'addr': 'address', 'zip': 'zipcode', 'usr': 'user'}); + * select().from('psn').join('addr', {'psn.addr_id': 'addr.id'}); + * // SELECT * FROM person psn INNER JOIN address addr ON psn.addr_id = addr.id + */ + aliasExpansions(expansions: { [tbl: string]: string }): void + + /** + * Sets a user-supplied function to automatically generate the .on() criteria for joins whenever it is not supplied explicitly. + * @param func + */ + joinCriteria(func?: (...args: any[]) => SqlBricks.OnCriteria): any + + _extension(): any + prop: number + conversions: any + + ////////////////////////////////////////// + ////// Where Expression functions ////// + ////////////////////////////////////////// + + /** + * Joins the passed expressions with AND + * @param whereExprs + */ + and(...whereExprs: SqlBricks.WhereExpression[]): SqlBricks.WhereGroup + + /** + * Joins the passed expressions with OR: + * @param whereExprs + */ + or(...whereExprs: SqlBricks.WhereExpression[]): SqlBricks.WhereGroup + + /** + * Negates the expression by wrapping it in NOT (...) + * (if it is at the top level, the parentheses are unnecessary and will be omitted) + * @param whereExpr + */ + not(whereExpr: SqlBricks.WhereExpression): SqlBricks.WhereGroup + + /** + * Generates a BETWEEN + * @param column + * @param value1 + * @param value2 + */ + between(column: string, value1: any, value2: any): SqlBricks.WhereExpression + isNull(column: string): SqlBricks.WhereExpression + isNotNull(column: string): SqlBricks.WhereExpression + like(column: string, value: any, escapeStr?: string): SqlBricks.WhereExpression + exists(stmt: any): SqlBricks.WhereExpression + in(column: string, stmt: SqlBricks.SelectStatement): SqlBricks.WhereExpression + in(column: string, ...values: any[]): SqlBricks.WhereExpression + + /** + * Generates the appropriate relational operator (=, <>, <, <=, > or >=). + * @param column column name or query result + * @param value column value + */ + eq(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + equal(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + notEq(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + lt(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + lte(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gt(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gte(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + + eqAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + notEqAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + ltAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + lteAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gtAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gteAll(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + + eqAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + notEqAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + ltAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + lteAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gtAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gteAny(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + + eqSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + notEqSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + ltSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + lteSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gtSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary + gteSome(column: string | SqlBricks.SelectStatement, value?: any): SqlBricks.WhereBinary +} + +declare const SqlBricks: SqlBricksFn +export = SqlBricks From 11e52200eec6c1e648c6585e314338ebdd4de609 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Fri, 25 Jan 2019 10:44:17 -0800 Subject: [PATCH 03/20] Create CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..9a741a1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at peter@cornerstonenw.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq From 087027d2f3738d769873b0c76ac9090697077b2b Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Fri, 25 Jan 2019 10:47:41 -0800 Subject: [PATCH 04/20] Create CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1aa031a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +Before sending a pull request, please verify that [all the existing tests](http://csnw.github.io/sql-bricks/browser-tests.html) pass and add new tests for the changes you are making. The tests can be run in node with `npm test` (provided `npm install` has been run to install the dependencies) or they can be run in the browser with `browser-tests.html`. All of the examples in the documentation are run as tests, in addition to the tests in tests.js. + +Note that **pull requests for additional SQL dialects** or extensions beyond ANSI SQL-92 will probably not be merged. If you would like support for a different dialect, you are welcome to maintain a dialect-specific fork or a library that extends sql-bricks. + +Also, **pull requests for additional SQL statements** beyond the four CRUD statements (`SELECT`, `UPDATE`, `INSERT`, `DELETE`) will probably not be merged. Other SQL statements do not benefit as much from re-use and composition; the goal being to keep SQL Bricks small, sharp and low-maintenance. From e9868952b6b9665558debaca96886b5e08427807 Mon Sep 17 00:00:00 2001 From: Stephen Schutt Date: Tue, 22 Oct 2019 15:53:25 -0600 Subject: [PATCH 05/20] update package.json so it uses mocha without npm audit issues --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29fbe49..0213a37 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "underscore": "1.4.x" }, "devDependencies": { - "mocha": "1.13.x" + "mocha": "^6.2.2" }, "license": "MIT", "testling": { From bd4b80c24767fe468e13ac5d434edfd1ca50892c Mon Sep 17 00:00:00 2001 From: Stephen Schutt Date: Wed, 23 Oct 2019 09:32:49 -0600 Subject: [PATCH 06/20] remove underscore from sql-bricks codebase --- index.html | 2 +- package.json | 4 +- sql-bricks.js | 277 +++++++--- tests/doctests.js | 29 +- tests/doctests.tmpl | 27 +- tests/gen-tests.js | 17 +- tests/tests.js | 25 +- tests/underscore.js | 1226 ------------------------------------------- 8 files changed, 273 insertions(+), 1334 deletions(-) delete mode 100644 tests/underscore.js diff --git a/index.html b/index.html index 9d2690b..6185a02 100644 --- a/index.html +++ b/index.html @@ -762,7 +762,7 @@

Conveniences

 var alias_expansions = {'psn': 'person', 'addr': 'address', 'zip': 'zipcode', 'usr': 'user'};
-var table_to_alias = _.invert(alias_expansions);
+var table_to_alias = invert(alias_expansions);
 sql.joinCriteria(function(left_tbl, left_alias, right_tbl, right_alias) {
   var criteria = {};
   criteria[left_alias + '.' + table_to_alias[right_tbl] + '_id'] = right_alias + '.id';
diff --git a/package.json b/package.json
index 29fbe49..a69f110 100644
--- a/package.json
+++ b/package.json
@@ -31,9 +31,7 @@
   "engines": {
     "node": "*"
   },
-  "dependencies": {
-    "underscore": "1.4.x"
-  },
+  "dependencies": {},
   "devDependencies": {
     "mocha": "1.13.x"
   },
diff --git a/sql-bricks.js b/sql-bricks.js
index 33942f6..9c86e3d 100644
--- a/sql-bricks.js
+++ b/sql-bricks.js
@@ -3,12 +3,81 @@
 
   var is_common_js = typeof exports != 'undefined';
   var default_opts = { placeholder: '$%d' };
-  
-  var _;
-  if (is_common_js)
-    _ = require('underscore');
-  else
-    _ = window._;
+
+  function toArray(obj) {
+    return Object.keys(obj).map(function(key) {
+      return obj[key];
+    });
+  }
+
+  function extend(obj) {
+    var other_objs = arguments;
+    delete other_objs['0'];
+
+    Object.keys(other_objs).forEach(function(arg_num) {
+      var other_obj = other_objs[arg_num];
+      Object.keys(other_obj).forEach(function(key) {
+        obj[key] = other_obj[key];
+      });
+    });
+    return obj;
+  }
+
+  function cloneObj(obj) {
+    if (types.isArray(obj))
+      return [].concat(arr);
+    else
+      return extend({}, obj);
+  }
+
+  var types = {
+    isObject: function isObject(val) {
+      return typeof val == 'object';
+    },
+    isArray: function isArray(val) {
+      return val instanceof Array;
+    },
+    isUndefined: function isUndefined(val) {
+      return typeof val == 'undefined';
+    },
+    isNull: function isNull(val) {
+      return val === null;
+    },
+    isNumber: function isNumber(val) {
+      return typeof val == 'number';
+    },
+    isString: function isString(val) {
+      return typeof val == 'string';
+    },
+    isBoolean: function isBoolean(val) {
+      return typeof val == 'boolean';
+    },
+    isDate: function isDate(val) {
+      return val instanceof Date;
+    }
+  };
+
+  function findIndex(arr, fn) {
+    var arr_index = -1;
+    arr.forEach(function(val, index) {
+      if (fn(val)) {
+        arr_index = index;
+        break;
+      }
+    });
+    return index;
+  }
+
+  function isEmpty(obj) {
+    return types.isUndefined(obj) || obj === null || Object.keys(obj).length == 0;
+  }
+
+  function applyDefaults(opts) {
+    Object.keys(default_opts).forEach(function(key) {
+      if (!opts[key]) opts[key] = default_opts[key];
+    });
+    return opts;
+  }
 
   // sql() wrapper allows SQL (column/table/etc) where a value (string/number/etc) is expected
   // it is also the main namespace for SQLBricks
@@ -17,15 +86,15 @@
       return applyNew(sql, arguments);
 
     this.str = str;
-    this.vals = _.toArray(arguments).slice(1);
+    this.vals = toArray(arguments).slice(1);
 
     // support passing a single array
-    if (_.isArray(this.vals[0]))
+    if (types.isArray(this.vals[0]))
       this.vals = this.vals[0];
   }
   sql.setDefaultOpts = setDefaultOpts;
   function setDefaultOpts(opts) {
-    default_opts = _.extend(default_opts, opts);
+    default_opts = extend(default_opts, opts);
   }
   sql.prototype.toString = function toString(opts) {
     // replacer(match, [capture1, capture2, ...,] offset, string)
@@ -36,9 +105,9 @@
 
       var ix = arguments.length > 3 ? parseInt(arguments[1], 10) : opts.value_ix++;
       var val = opts.values[ix - 1];
-      if (_.isUndefined(val))
+      if (types.isUndefined(val))
         throw new Error('Parameterized sql() (' + str + ') requires ' + ix + ' parameter(s) but only ' + opts.values.length + ' parameter(s) were supplied');
-      if (_.isObject(sql) && !_.isArray(sql) && sql == null)
+      if (types.isObject(sql) && !types.isArray(sql) && sql == null)
         return val.toString(opts);
       else
         return sql.convert(val);
@@ -46,7 +115,7 @@
 
     var str = this.str;
     if (!opts)
-      opts = _.extend({}, default_opts);
+      opts = extend({}, default_opts);
     if (!opts.values)
       opts.values = [];
     if (!opts.value_ix)
@@ -107,7 +176,7 @@
       
       var index;
       if (opts.after || opts.before) {
-        index = _.findIndex(this.prototype.clauses, function(render_fn) {
+        index = findIndex(this.prototype.clauses, function(render_fn) {
           return render_fn.clause_id == (opts.after || opts.before);
         });
         if (index == -1)
@@ -171,26 +240,31 @@
   });
   Select.prototype.on = function(on) {
     var last_join = this.joins[this.joins.length - 1];
-    if (_.isArray(last_join.on) && !_.isEmpty(last_join.on))
+    if (types.isArray(last_join.on) && !isEmpty(last_join.on))
       throw new Error('Error adding clause ON: ' + last_join.left_tbl + ' JOIN ' + last_join.tbl + ' already has a USING clause.');
     if (isExpr(on)) {
       last_join.on = on;
     }
     else {
-      if (!last_join.on || (_.isArray(last_join.on))) // Instantiate object, including if it's an empty array from .using().
+      if (!last_join.on || (types.isArray(last_join.on))) // Instantiate object, including if it's an empty array from .using().
         last_join.on = {};
-      _.extend(last_join.on, argsToObject(arguments));
+      extend(last_join.on, argsToObject(arguments));
     }
     return this;
   };
   Select.prototype.using = function(columns) {
     var last_join = this.joins[this.joins.length - 1];
-    if (!_.isEmpty(last_join.on) && !_.isArray(last_join.on))
+    if (!isEmpty(last_join.on) && !types.isArray(last_join.on))
       throw new Error('Error adding clause USING: ' + last_join.left_tbl + ' JOIN ' + last_join.tbl + ' already has an ON clause.');
 
-    if (_.isEmpty(last_join.on))
+    if (isEmpty(last_join.on))
       last_join.on = []; // Using _.isEmpty tolerates overwriting of empty {}.
-    last_join.on = _.union(last_join.on, argsToArray(arguments));
+
+    var argsArray = argsToArray(arguments);
+    argsArray.forEach(function(key) {
+      if (last_join.on.indexOf(key) == -1) last_join.on.push(key);
+    });
+
     return this;
   };
 
@@ -225,7 +299,7 @@
     'intersect': 'INTERSECT', 'intersectAll': 'INTERSECT ALL',
     'except': 'EXCEPT', 'exceptAll': 'EXCEPT ALL'
   };
-  _.forEach(compounds, function(value, key) {
+  Object.keys(compounds).forEach(function(key) {
     Select.prototype[key] = function() {
       var stmts = argsToArray(arguments);
       if (!stmts.length) {
@@ -278,8 +352,11 @@
     if (!this._from)
       return;
     var result = `FROM ${handleTables(this._from, opts)}`;
-    if (this.joins)
-      result += ` ${_.invoke(this.joins, 'toString', opts).join(' ')}`;
+    if (this.joins) {
+      result += ' ' + this.joins.map(function(join) {
+        return join.toString(opts);
+      }.bind(this)).join(' ');
+    }
     return result;
   });
   Select.defineClause('where', function(opts) {
@@ -295,7 +372,8 @@
       return `HAVING ${handleExpression(this._having, opts)}`;
   });
 
-  _.forEach(compounds, function(sql_keyword, clause_id) {
+  Object.keys(compounds).forEach(function(clause_id) {
+    var sql_keyword = compounds[clause_id];
     Select.defineClause(clause_id, function(opts) {
       var arr = this['_' + clause_id];
       if (arr) {
@@ -321,10 +399,10 @@
   sql.insert = sql.insertInto = inherits(Insert, Statement);
   function Insert(tbl, values) {
     if (!(this instanceof Insert)) {
-      if (typeof values == 'object' && !_.isArray(values))
+      if (typeof values == 'object' && !types.isArray(values))
         return new Insert(tbl, values);
       else
-        return new Insert(tbl, argsToArray(_.toArray(arguments).slice(1)));
+        return new Insert(tbl, argsToArray(toArray(arguments).slice(1)));
     }
 
     Insert.super_.call(this, 'insert');
@@ -336,14 +414,14 @@
       this._table = tbl;
 
     if (values) {
-      if (isPlainObject(values) || (_.isArray(values) && isPlainObject(values[0]))) {
+      if (isPlainObject(values) || (types.isArray(values) && isPlainObject(values[0]))) {
         this.values(values);
       }
       else if (values.length) {
         this._split_keys_vals_mode = true;
         this._values = [{}];
-        var val_arr = argsToArray(_.toArray(arguments).slice(1));
-        _.forEach(val_arr, function(key) {
+        var val_arr = argsToArray(toArray(arguments).slice(1));
+        val_arr.forEach(function(key) {
           this._values[0][key] = null;
         }.bind(this));
       }
@@ -353,23 +431,23 @@
   Insert.prototype.values = function values() {
     if (this._split_keys_vals_mode) {
       var outer_arr;
-      if (_.isArray(arguments[0]) && _.isArray(arguments[0][0]))
+      if (types.isArray(arguments[0]) && types.isArray(arguments[0][0]))
         outer_arr = arguments[0];
       else
         outer_arr = [argsToArray(arguments)];
 
-      var keys = _.keys(this._values[0]);
-      _.forEach(outer_arr, function(args, outer_ix) {
+      var keys = Object.keys(this._values[0]);
+      outer_arr.forEach(function(args, outer_ix) {
         if (!this._values[outer_ix])
           this._values[outer_ix] = {};
 
-        _.forEach(keys, function(key, ix) {
+        keys.forEach(function(key, ix) {
           this._values[outer_ix][key] = args[ix];
         }.bind(this));
       }.bind(this));
     }
     else {
-      if (_.isArray(arguments[0]) && isPlainObject(arguments[0][0])) {
+      if (types.isArray(arguments[0]) && isPlainObject(arguments[0][0])) {
         if (!this._values)
           this._values = [];
         this._values = this._values.concat(arguments[0]);
@@ -377,7 +455,7 @@
       else {
         if (!this._values)
           this._values = [{}];
-        _.extend(this._values[0], argsToObject(arguments));
+        extend(this._values[0], argsToObject(arguments));
       }
     }
     return this;
@@ -394,16 +472,19 @@
   });
   Insert.defineClause('columns', function(opts) {
     if (this._values)
-      return '(' + handleColumns(_.keys(this._values[0]), opts) + ')';
+      return '(' + handleColumns(Object.keys(this._values[0]), opts) + ')';
   });
   Insert.defineClause('values', function(opts) {
     if (this._select) {
       return this._select._toString(opts);
     }
     else {
-      var pickOrder = _.keys(this._values[0]);
-      return 'VALUES ' + _.map(this._values, function(values) {
-        return '(' + handleValues(_.values(_.pick(values, pickOrder)), opts).join(', ') + ')';
+      var pickOrder = Object.keys(this._values[0]);
+      return 'VALUES ' + this._values.map(function(values) {
+        var pickValues = pickOrder.map(function(key) {
+          return values[key];
+        });
+        return '(' + handleValues(pickValues, opts).join(', ') + ')';
       }).join(', ');
     }
   });
@@ -413,7 +494,7 @@
   sql.update = inherits(Update, Statement);
   function Update(tbl, values) {
     if (!(this instanceof Update))
-      return new Update(tbl, argsToObject(_.toArray(arguments).slice(1)));
+      return new Update(tbl, argsToObject(toArray(arguments).slice(1)));
 
     Update.super_.call(this, 'update');
     this._table = tbl;
@@ -435,9 +516,9 @@
     return handleTable(this._table, opts);
   });
   Update.defineClause('set', function(opts) {
-    return 'SET ' + _.map(this._values, function(value, key) {
-      return handleColumn(key, opts) + ' = ' + handleValue(value, opts);
-    }).join(', ');
+    return 'SET ' + Object.keys(this._values).map(function(key) {
+      return handleColumn(key, opts) + ' = ' + handleValue(this._values[key], opts);
+    }.bind(this)).join(', ');
   });
   Update.defineClause('where', function(opts) {
     if (this._where)
@@ -479,23 +560,24 @@
 
   // TODO: this seems to not handle... a *lot* of properties
   Statement.prototype.clone = function clone() {
-    var ctor = _.find([Select, Insert, Update, Delete], function(ctor) {
-      return this instanceof ctor;
+    var ctor;
+    [Select, Insert, Update, Delete].forEach(function(fn) {
+      if (this instanceof fn) ctor = fn;
     }.bind(this));
 
-    var stmt = _.extend(new ctor(), this);
+    var stmt = extend(new ctor(), this);
     if (stmt._where)
       stmt._where = stmt._where.clone();
     if (stmt.joins)
       stmt.joins = stmt.joins.slice();
     if (stmt._values) {
-      if (_.isArray(stmt._values)) {
-        stmt._values = _.map(stmt._values, function(val) {
-          return _.clone(val);
+      if (types.isArray(stmt._values)) {
+        stmt._values = stmt._values.map(function(val) {
+          return cloneObj(val);
         });
       }
       else {
-        stmt._values = _.clone(stmt._values);
+        stmt._values = cloneObj(stmt._values);
       }
     }
     return stmt;
@@ -507,8 +589,8 @@
 
     if (!opts)
       opts = {};
-    _.extend(opts, {'parameterized': true, 'values': [], 'value_ix': 1});
-    _.defaults(opts, default_opts);
+    extend(opts, {'parameterized': true, 'values': [], 'value_ix': 1});
+    opts = applyDefaults(opts);
     var sql = this._toString(opts);
 
     return {'text': sql, 'values': opts.values};
@@ -517,7 +599,7 @@
   Statement.prototype.toString = function toString(opts) {
     if (!opts)
       opts = {};
-    _.defaults(opts, default_opts);
+    opts = applyDefaults(opts);
 
     if (this.prev_stmt)
       return this.prev_stmt.toString(opts);
@@ -526,9 +608,12 @@
   };
 
   Statement.prototype._toString = function(opts) {
-    return _.compact(this.clauses.map(function(clause) {
-      return clause.call(this, opts)
-    }.bind(this))).join(' ');
+    var clauses = [];
+    this.clauses.forEach(function(clause) {
+      var clause = clause.call(this, opts);
+      if (clause) clauses.push(clause);
+    }.bind(this));
+    return clauses.join(' ');
   };
 
   Statement.prototype._add = function _add(arr, name) {
@@ -543,7 +628,7 @@
     if (!this[name])
       this[name] = {};
 
-    _.extend(this[name], obj);
+    extend(this[name], obj);
     return this;
   };
 
@@ -552,7 +637,7 @@
   };
 
   Statement.prototype._addExpression = function _addExpression(args, name) {
-    if (args.length <= 1 && (args[0] == null || _.isEmpty(args[0])))
+    if (args.length <= 1 && (args[0] == null || isEmpty(args[0])))
       return this;
 
     if (!this[name])
@@ -575,7 +660,7 @@
       tbls = argsToArray(args);
     }
 
-    _.forEach(tbls, function(tbl) {
+    tbls.forEach(function(tbl) {
       var left_tbl = this.last_join || (this._from && this._from[this._from.length - 1]);
       this.joins.push(new Join(tbl, left_tbl, on, type));
     }.bind(this));
@@ -604,7 +689,7 @@
       return this.type + ' JOIN ' + tbl;
     
     // Not a natural or cross, check for criteria.
-    if (!on || _.isEmpty(on)) {
+    if (!on || isEmpty(on)) {
       if (sql._joinCriteria) {
         var left_tbl = handleTable(this.left_tbl, opts);
         on = this.autoGenerateOn(tbl, left_tbl);
@@ -615,8 +700,8 @@
     }
 
     // Array value for on indicates join using "using", rather than "on".
-    if (_.isArray(on)) {
-      on = _.map(on, function (column) {
+    if (types.isArray(on)) {
+      on = on.map(function (column) {
         return handleColumn(column);
       }).join(', ');
       return this.type + ' JOIN ' + tbl + ' USING (' + on + ')';
@@ -627,7 +712,7 @@
       on = on.toString(opts);
     }
     else {
-      on = _.map(_.keys(on), function(key) {
+      on = Object.keys(on).map(function(key) {
         return handleColumn(key, opts) + ' = ' + handleColumn(on[key], opts);
       }).join(' AND ')
     }
@@ -636,12 +721,17 @@
 
   // handle an array, a comma-delimited str or separate args
   function argsToArray(args) {
-    if (_.isArray(args[0]))
+    if (types.isArray(args[0])) {
       return args[0];
-    else if (typeof args[0] == 'string' && args[0].indexOf(',') > -1)
-      return _.invoke(args[0].split(','), 'trim');
-    else
-      return _.toArray(args);
+    }
+    else if (typeof args[0] == 'string' && args[0].indexOf(',') > -1) {
+      return args[0].split(',').map(function(arg) {
+        return arg.trim();
+      });
+    }
+    else {
+      return toArray(args);
+    }
   }
 
   function argsToObject(args) {
@@ -655,8 +745,13 @@
   }
 
   function argsToExpressions(args) {
-    var flat_args = _.all(args, function(arg) {
-      return typeof arg != 'object' || arg instanceof val || arg instanceof sql || arg == null;
+    var flat_args = true;
+    Object.keys(args).forEach(function(key) {
+      var arg = args[key];
+      if (!(typeof arg != 'object' || arg instanceof val || arg instanceof sql || arg == null)) {
+        flat_args = false;
+        return;
+      }
     });
     if (flat_args) {
       if (args[0] instanceof sql && args.length == 1)
@@ -666,7 +761,8 @@
     }
     else {
       var exprs = [];
-      _.each(args, function(expr) {
+      Object.keys(args).forEach(function(key) {
+        var expr = args[key];
         if (isExpr(expr))
           exprs.push(expr);
         else
@@ -684,7 +780,7 @@
   function Group(op, expressions) {
     this.op = op;
     this.expressions = [];
-    _.forEach(expressions, function(expr) {
+    expressions.forEach(function(expr) {
       if (isExpr(expr))
         this.expressions.push(expr);
       else
@@ -693,13 +789,15 @@
   }
   sql.Group = Group;
   Group.prototype.clone = function clone() {
-    return new Group(this.op, _.invoke(this.expressions, 'clone'));
+    return new Group(this.op, this.expressions.map(function(expr) {
+      return expr.clone();
+    }));
   };
   Group.prototype.toString = function toString(opts) {
-    opts = opts || _.extend({}, default_opts);
-    var sql = _.map(this.expressions, function(expr) {
-      return expr.toString(opts);
-    }).join(' ' + this.op + ' ');
+    opts = opts || extend({}, default_opts);
+    var sql = Object.keys(this.expressions).map(function(expr) {
+      return this.expressions[expr].toString(opts);
+    }.bind(this)).join(' ' + this.op + ' ');
     if (this.expressions.length > 1 && this.parens !== false)
       sql = '(' + sql + ')';
     return sql;
@@ -733,7 +831,7 @@
       return new Binary(binary_ops[name], col, val);
     }.bind(null, name);
 
-    _.forEach(quantifiers, function(name, quantifier) {
+    quantifiers.forEach(function(name, quantifier) {
       sql[name + quantifier] = function(col, val) {
         return new Binary(binary_ops[name], col, val, quantifier.toUpperCase() + ' ');
       };
@@ -810,10 +908,10 @@
   };
 
   sql['in'] = function(col, list) {
-    if (_.isArray(list) || list instanceof Statement)
+    if (types.isArray(list) || list instanceof Statement)
       return new In(col, list);
     else
-      return new In(col, _.toArray(arguments).slice(1));
+      return new In(col, toArray(arguments).slice(1));
   };
 
   function In(col, list) {
@@ -822,13 +920,13 @@
   }
   sql.In = In;
   In.prototype.clone = function clone() {
-    var list = (this.list instanceof Statement) ? this.list.clone() : _.clone(this.list);
+    var list = (this.list instanceof Statement) ? this.list.clone() : cloneObj(this.list);
     return new In(this.col, list);
   };
   In.prototype.toString = function toString(opts) {
     var col_sql = handleColumn(this.col, opts);
     var sql;
-    if (_.isArray(this.list))
+    if (types.isArray(this.list))
       sql = handleValues(this.list, opts).join(', ');
     else if (this.list instanceof Statement)
       sql = this.list._toString(opts);
@@ -916,9 +1014,10 @@
   sql._handleValue = handleValue;
 
   sql.convert = function(val) {
-    for (var type in sql.conversions)
-      if (_['is' + type].call(_, val))
+    for (var type in sql.conversions) {
+      if (types['is' + type](val))
         return sql.conversions[type](val);
+    }
 
     throw new Error('value is of an unsupported type and cannot be converted to SQL: ' + val);
   }
@@ -999,11 +1098,15 @@
   // Postgres: Table C-1 of http://www.postgresql.org/docs/9.3/static/sql-keywords-appendix.html
   // SQLite: http://www.sqlite.org/lang_keywords.html
   var reserved = ['all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 'asymmetric', 'authorization', 'both', 'case', 'cast', 'check', 'collate', 'collation', 'column', 'constraint', 'create', 'cross', 'current_catalog', 'current_date', 'current_role', 'current_time', 'current_timestamp', 'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end', 'except', 'false', 'fetch', 'for', 'foreign', 'freeze', 'from', 'full', 'grant', 'group', 'having', 'ilike', 'in', 'initially', 'inner', 'intersect', 'into', 'is', 'isnull', 'join', 'lateral', 'leading', 'left', 'like', 'limit', 'localtime', 'localtimestamp', 'natural', 'not', 'notnull', 'null', 'offset', 'on', 'only', 'or', 'order', 'outer', 'over', 'overlaps', 'placing', 'primary', 'references', 'returning', 'right', 'select', 'session_user', 'similar', 'some', 'symmetric', 'table', 'then', 'to', 'trailing', 'true', 'union', 'unique', 'user', 'using', 'variadic', 'verbose', 'when', 'where', 'window', 'with', 'abort', 'action', 'add', 'after', 'all', 'alter', 'analyze', 'and', 'as', 'asc', 'attach', 'autoincrement', 'before', 'begin', 'between', 'by', 'cascade', 'case', 'cast', 'check', 'collate', 'column', 'commit', 'conflict', 'constraint', 'create', 'cross', 'current_date', 'current_time', 'current_timestamp', 'database', 'default', 'deferrable', 'deferred', 'delete', 'desc', 'detach', 'distinct', 'drop', 'each', 'else', 'end', 'escape', 'except', 'exclusive', 'exists', 'explain', 'fail', 'for', 'foreign', 'from', 'full', 'glob', 'group', 'having', 'if', 'ignore', 'immediate', 'in', 'index', 'indexed', 'initially', 'inner', 'insert', 'instead', 'intersect', 'into', 'is', 'isnull', 'join', 'key', 'left', 'like', 'limit', 'match', 'natural', 'no', 'not', 'notnull', 'null', 'of', 'offset', 'on', 'or', 'order', 'outer', 'plan', 'pragma', 'primary', 'query', 'raise', 'references', 'regexp', 'reindex', 'release', 'rename', 'replace', 'restrict', 'right', 'rollback', 'row', 'savepoint', 'select', 'set', 'table', 'temp', 'temporary', 'then', 'to', 'transaction', 'trigger', 'union', 'unique', 'update', 'using', 'vacuum', 'values', 'view', 'virtual', 'when', 'where'];
-  reserved = _.object(reserved, reserved);
+  var reserved_obj = {};
+  reserved.forEach(function(val) {
+    reserved_obj[val] = val;
+  });
+  reserved = reserved_obj;
   sql._reserved = reserved;
 
   function isPlainObject(val) {
-    return _.isObject(val) && !_.isArray(val);
+    return types.isObject(val) && !types.isArray(val);
   }
 
 
@@ -1050,7 +1153,7 @@
   sql._extension = function () {
     var ext = subclass(sql);
 
-    _.forEach(_.keys(sql), function(prop_name) {
+    Object.keys(sql).forEach(function(prop_name) {
       ext[prop_name] = sql[prop_name];
     });
 
@@ -1078,7 +1181,7 @@
 
   // http://stackoverflow.com/a/8843181/194758
   function applyNew(cls, args) {
-    args = _.toArray(args);
+    args = toArray(args);
     args.unshift(null);
     return new (cls.bind.apply(cls, args));
   }
diff --git a/tests/doctests.js b/tests/doctests.js
index f3fae9e..905437e 100644
--- a/tests/doctests.js
+++ b/tests/doctests.js
@@ -1,7 +1,6 @@
 (function() {
 
 var is_common_js = typeof exports != 'undefined';
-var _ = is_common_js ? require('underscore') : window._;
 var sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks;
 
 if (is_common_js) {
@@ -22,7 +21,21 @@ else {
       if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
     },
     'deepEqual': function(actual, expected) {
-      if (!_.isEqual(actual, expected)) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
+      var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected);
+      var has_error = false;
+      if (actual_keys.length != expected_keys.length) 
+        has_error = true;
+      
+      actual_keys.forEach(function(key) {
+        if (actual[key] != expected[key]) has_error = true;
+      });
+
+      expected_keys.forEach(function(key) {
+        if (actual[key] != expected[key]) has_error = true;
+      });
+
+      if (has_error)
+        throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
     }
   };
 }
@@ -38,6 +51,14 @@ describe('SQL Bricks', function() {
   describe('documentation examples', function() {
 
 
+function invert(obj) {
+  var inverted_obj = {};
+  Object.keys(obj).forEach(function(key) {
+    inverted_obj[obj[key]] = key;
+  });
+  return inverted_obj; 
+}
+
 it(".where(or({last_name: 'Rubble'}, $in('first_name', ['Fred', 'Wilma', 'Pebbles'])));", function() {
 
 check(select().from('person')
  .where(or({last_name: 'Rubble'}, $in('first_name', ['Fred', 'Wilma', 'Pebbles']))), "SELECT * FROM person WHERE last_name = 'Rubble' OR first_name IN ('Fred', 'Wilma', 'Pebbles')");
@@ -269,7 +290,7 @@ check(select().from('psn').join('addr', {'psn.addr_id': 'addr.id'}), "SELECT * F
 
 it("select().from('person').join('address');", function() {
 var alias_expansions = {'psn': 'person', 'addr': 'address', 'zip': 'zipcode', 'usr': 'user'};
-var table_to_alias = _.invert(alias_expansions);
+var table_to_alias = invert(alias_expansions);
 sql.joinCriteria(function(left_tbl, left_alias, right_tbl, right_alias) {
   var criteria = {};
   criteria[left_alias + '.' + table_to_alias[right_tbl] + '_id'] = right_alias + '.id';
@@ -321,7 +342,7 @@ check(select('person.order AS person_order').from('person'), "SELECT person.\"or
 });
 
 function check(actual, expected) {
-  if (_.isObject(actual) && _.isString(expected))
+  if (typeof actual == 'object' && typeof expected == 'string')
     assert.equal(actual.toString(), expected);
   else
     assert.deepEqual(actual, expected);
diff --git a/tests/doctests.tmpl b/tests/doctests.tmpl
index 8790627..36bcd00 100644
--- a/tests/doctests.tmpl
+++ b/tests/doctests.tmpl
@@ -1,7 +1,6 @@
 (function() {
 
 var is_common_js = typeof exports != 'undefined';
-var _ = is_common_js ? require('underscore') : window._;
 var sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks;
 
 if (is_common_js) {
@@ -22,7 +21,21 @@ else {
       if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
     },
     'deepEqual': function(actual, expected) {
-      if (!_.isEqual(actual, expected)) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
+      var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected);
+      var has_error = false;
+      if (actual_keys.length != expected_keys.length) 
+        has_error = true;
+      
+      actual_keys.forEach(function(key) {
+        if (actual[key] != expected[key]) has_error = true;
+      });
+
+      expected_keys.forEach(function(key) {
+        if (actual[key] != expected[key]) has_error = true;
+      });
+
+      if (has_error)
+        throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected));
     }
   };
 }
@@ -38,6 +51,14 @@ describe('SQL Bricks', function() {
   describe('documentation examples', function() {
 
 
+function invert(obj) {
+  var inverted_obj = {};
+  Object.keys(obj).forEach(function(key) {
+    inverted_obj[obj[key]] = key;
+  });
+  return inverted_obj; 
+}
+
 {{tests}}
 
 
@@ -45,7 +66,7 @@ describe('SQL Bricks', function() {
 });
 
 function check(actual, expected) {
-  if (_.isObject(actual) && _.isString(expected))
+  if (typeof actual == 'object' && typeof expected == 'string')
     assert.equal(actual.toString(), expected);
   else
     assert.deepEqual(actual, expected);
diff --git a/tests/gen-tests.js b/tests/gen-tests.js
index 9b30105..72cdf00 100644
--- a/tests/gen-tests.js
+++ b/tests/gen-tests.js
@@ -1,12 +1,14 @@
 var fs = require('fs');
-var _ = require('underscore');
 
 var comment = '// ';
 var readme = fs.readFileSync(__dirname + '/../index.html', 'utf8');
 var contents = '';
 readme.match(/
[^<]+<\/pre>/g).forEach(function(ex) {
   ex = ex.slice('
'.length, -'
'.length); - var lines = _.compact(ex.split('\n')); + var lines = []; + ex.split('\n').forEach(function(line) { + if (line) lines.push(line); + }); lines.forEach(function(line, ix) { line = line.trim(); var next_line = (lines[ix + 1] || '').trim(); @@ -45,9 +47,12 @@ function wrap(lines) { var match = /var (\w+) =/.exec(last_line); if (match) lines.push(match[1] + ';'); - lines = _.compact(lines); - lines = _.reject(lines, isComment); - return lines; + + var processed_lines = []; + lines.forEach(function(line) { + if (line && !isComment(line)) processed_lines.push(line); + }); + return processed_lines; } function isComment(str) { return str.slice(0, comment.length) == comment; @@ -62,6 +67,6 @@ function getExpected(lines, ix) { ix--; } comments.reverse(); - comments = _.invoke(comments, 'trim'); + comments = comments.map(function(comment) { return comment.trim(); }); return comments.join(' '); } diff --git a/tests/tests.js b/tests/tests.js index c834045..2159bdb 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -2,7 +2,6 @@ var is_common_js = typeof exports != 'undefined'; -var _ = is_common_js ? require('underscore') : window._; var sql = is_common_js ? require('../sql-bricks.js') : window.SqlBricks; if (is_common_js) { @@ -26,7 +25,21 @@ else { if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }; assert.deepEqual = function(actual, expected) { - if (!_.isEqual(actual, expected)) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); + var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected); + var has_error = false; + if (actual_keys.length != expected_keys.length) + has_error = true; + + actual_keys.forEach(function(key) { + if (actual[key] != expected[key]) has_error = true; + }); + + expected_keys.forEach(function(key) { + if (actual[key] != expected[key]) has_error = true; + }); + + if (has_error) + throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }; assert.throws = function(fn) { try { @@ -48,7 +61,10 @@ var and = sql.and, or = sql.or, like = sql.like, not = sql.not, $in = sql.in, union = sql.union; var alias_expansions = {'usr': 'user', 'psn': 'person', 'addr': 'address'}; -var table_to_alias = _.invert(alias_expansions); +var table_to_alias = {}; +Object.keys(alias_expansions).forEach(function(key) { + table_to_alias[alias_expansions[key]] = key; +}); sql.aliasExpansions(alias_expansions); sql.joinCriteria(function(left_tbl, left_alias, right_tbl, right_alias) { @@ -240,6 +256,7 @@ describe('SQL Bricks', function() { 'INNER JOIN address addr ON usr.addr_fk = addr.pk'); }); it('should handle unions', function() { + console.log() check(select().from('usr').where({'name': 'Roy'}) .union(select().from('usr').where({'name': 'Moss'})) .union(select().from('usr').where({'name': 'The elders of the internet'})), @@ -773,7 +790,7 @@ describe('SQL Bricks', function() { for (var col in criteria) { var val = criteria[col]; var expr; - if (_.isArray(val)) + if (val instanceof Array) expr = or(val.map(function(val) { return eq(col, val); })); else expr = eq(col, val); diff --git a/tests/underscore.js b/tests/underscore.js deleted file mode 100644 index a12f0d9..0000000 --- a/tests/underscore.js +++ /dev/null @@ -1,1226 +0,0 @@ -// Underscore.js 1.4.4 -// http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore may be freely distributed under the MIT license. - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root._ = _; - } - - // Current version. - _.VERSION = '1.4.4'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - return results; - }; - - var reduceError = 'Reduce of empty array with no initial value'; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var length = obj.length; - if (length !== +length) { - var keys = _.keys(obj); - length = keys.length; - } - each(obj, function(value, index, list) { - index = keys ? keys[--length] : --length; - if (!initial) { - memo = obj[index]; - initial = true; - } else { - memo = iterator.call(context, memo, obj[index], index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); - }, context); - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if the array or object contains a given value (using `===`). - // Aliased as `include`. - _.contains = _.include = function(obj, target) { - if (obj == null) return false; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { - return value === target; - }); - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - return (isFunc ? method : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? null : []; - return _[first ? 'find' : 'filter'](obj, function(value) { - for (var key in attrs) { - if (attrs[key] !== value[key]) return false; - } - return true; - }); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); - }; - - // Return the maximum element or (element-based computation). - // Can't optimize arrays of integers longer than 65,535 elements. - // See: https://bugs.webkit.org/show_bug.cgi?id=80797 - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.max.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.min.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Shuffle an array. - _.shuffle = function(obj) { - var rand; - var index = 0; - var shuffled = []; - each(obj, function(value) { - rand = _.random(index++); - shuffled[index - 1] = shuffled[rand]; - shuffled[rand] = value; - }); - return shuffled; - }; - - // An internal function to generate lookup iterators. - var lookupIterator = function(value) { - return _.isFunction(value) ? value : function(obj){ return obj[value]; }; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, value, context) { - var iterator = lookupIterator(value); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - index : index, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index < right.index ? -1 : 1; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(obj, value, context, behavior) { - var result = {}; - var iterator = lookupIterator(value || _.identity); - each(obj, function(value, index) { - var key = iterator.call(context, value, index, obj); - behavior(result, key, value); - }); - return result; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = function(obj, value, context) { - return group(obj, value, context, function(result, key, value) { - (_.has(result, key) ? result[key] : (result[key] = [])).push(value); - }); - }; - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = function(obj, value, context) { - return group(obj, value, context, function(result, key) { - if (!_.has(result, key)) result[key] = 0; - result[key]++; - }); - }; - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator, context) { - iterator = iterator == null ? _.identity : lookupIterator(iterator); - var value = iterator.call(context, obj); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >>> 1; - iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (obj.length === +obj.length) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, (n == null) || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, output) { - each(input, function(value) { - if (_.isArray(value)) { - shallow ? push.apply(output, value) : flatten(value, shallow, output); - } else { - output.push(value); - } - }); - return output; - }; - - // Return a completely flattened version of an array. - _.flatten = function(array, shallow) { - return flatten(array, shallow, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator, context) { - if (_.isFunction(isSorted)) { - context = iterator; - iterator = isSorted; - isSorted = false; - } - var initial = iterator ? _.map(array, iterator, context) : array; - var results = []; - var seen = []; - each(initial, function(value, index) { - if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { - seen.push(value); - results.push(array[index]); - } - }); - return results; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(concat.apply(ArrayProto, arguments)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); - return _.filter(array, function(value){ return !_.contains(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) { - results[i] = _.pluck(args, "" + i); - } - return results; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - if (list == null) return {}; - var result = {}; - for (var i = 0, l = list.length; i < l; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i = 0, l = array.length; - if (isSorted) { - if (typeof isSorted == 'number') { - i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); - } else { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); - for (; i < l; i++) if (array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item, from) { - if (array == null) return -1; - var hasIndex = from != null; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { - return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); - } - var i = (hasIndex ? from : array.length); - while (i--) if (array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(context, args.concat(slice.call(arguments))); - }; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. - _.partial = function(func) { - var args = slice.call(arguments, 1); - return function() { - return func.apply(this, args.concat(slice.call(arguments))); - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length === 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, result; - var previous = 0; - var later = function() { - previous = new Date; - timeout = null; - result = func.apply(context, args); - }; - return function() { - var now = new Date; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, result; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) result = func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) result = func.apply(context, args); - return result; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - memo = func.apply(this, arguments); - func = null; - return memo; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - if (times <= 0) return func(); - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var values = []; - for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); - return values; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var pairs = []; - for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - each(keys, function(key) { - if (key in obj) copy[key] = obj[key]; - }); - return copy; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - for (var key in obj) { - if (!_.contains(keys, key)) copy[key] = obj[key]; - } - return copy; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) return bStack[length] == b; - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - if (!(result = eq(a[size], b[size], aStack, bStack))) break; - } - } - } else { - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor))) { - return false; - } - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return result; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, [], []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. - each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) == '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Optimize `isFunction` if appropriate. - if (typeof (/./) !== 'function') { - _.isFunction = function(obj) { - return typeof obj === 'function'; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj != +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function(n, iterator, context) { - var accum = Array(n); - for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // List of HTML entities for escaping. - var entityMap = { - escape: { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/' - } - }; - entityMap.unescape = _.invert(entityMap.escape); - - // Regexes containing the keys and values listed immediately above. - var entityRegexes = { - escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), - unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') - }; - - // Functions for escaping and unescaping strings to/from HTML interpolation. - _.each(['escape', 'unescape'], function(method) { - _[method] = function(string) { - if (string == null) return ''; - return ('' + string).replace(entityRegexes[method], function(match) { - return entityMap[method][match]; - }); - }; - }); - - // If the value of the named property is a function then invoke it; - // otherwise, return it. - _.result = function(object, property) { - if (object == null) return null; - var value = object[property]; - return _.isFunction(value) ? value.call(object) : value; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result.call(this, func.apply(_, args)); - }; - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - var render; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = new RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset) - .replace(escaper, function(match) { return '\\' + escapes[match]; }); - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } - if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } - if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - index = offset + match.length; - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; - - try { - render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled function source as a convenience for precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(obj) { - return this._chain ? _(obj).chain() : obj; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; - return result.call(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result.call(this, method.apply(this._wrapped, arguments)); - }; - }); - - _.extend(_.prototype, { - - // Start chaining a wrapped Underscore object. - chain: function() { - this._chain = true; - return this; - }, - - // Extracts the result from a wrapped and chained object. - value: function() { - return this._wrapped; - } - - }); - -}).call(this); From 9663defe67a3012f089c32d11cc172d525ba5faf Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 23 Oct 2019 16:36:27 -0700 Subject: [PATCH 07/20] Update readme.md --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index b38d226..eb68629 100644 --- a/readme.md +++ b/readme.md @@ -50,6 +50,10 @@ library | lines | files | schema | other notes * transactions * query execution * data accessors +* [A Layer Above Database Connectors](https://github.com/paleo/ladc) adds: + * A common way to access to relational databases (SQLite & Postgres as of Oct 2019) + * A pool of connections in order to allow transactions in an asynchronous context; + * A way to augment your connector with your SQL query builder (has a sql-bricks plugin) # Use From 70351a62450470dadf6d383a2247783e715bb3b4 Mon Sep 17 00:00:00 2001 From: Stephen Schutt Date: Fri, 25 Oct 2019 19:08:35 -0500 Subject: [PATCH 08/20] review change --- sql-bricks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql-bricks.js b/sql-bricks.js index 9c86e3d..ac155bb 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -62,7 +62,7 @@ arr.forEach(function(val, index) { if (fn(val)) { arr_index = index; - break; + return; } }); return index; From 6441e75d1ecb46af2fa88c958cfd510376d92e85 Mon Sep 17 00:00:00 2001 From: Stephen Schutt Date: Sat, 26 Oct 2019 03:20:27 -0500 Subject: [PATCH 09/20] remove console.log --- tests/tests.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/tests.js b/tests/tests.js index 2159bdb..b57c854 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -256,7 +256,6 @@ describe('SQL Bricks', function() { 'INNER JOIN address addr ON usr.addr_fk = addr.pk'); }); it('should handle unions', function() { - console.log() check(select().from('usr').where({'name': 'Roy'}) .union(select().from('usr').where({'name': 'Moss'})) .union(select().from('usr').where({'name': 'The elders of the internet'})), From 25f46ca68a3a4e028a042f2870d86f1be7333a0c Mon Sep 17 00:00:00 2001 From: pgarrison Date: Mon, 12 Jul 2021 16:27:48 -0700 Subject: [PATCH 10/20] Write findIndex with a for loop --- sql-bricks.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sql-bricks.js b/sql-bricks.js index ac155bb..3044eef 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -58,14 +58,12 @@ }; function findIndex(arr, fn) { - var arr_index = -1; - arr.forEach(function(val, index) { + for (var i = 0; i < arr.length; i++) { if (fn(val)) { - arr_index = index; - return; + return i; } - }); - return index; + } + return -1; } function isEmpty(obj) { From bb161a769ac2473f6c517cf070b78cd3c0712b9e Mon Sep 17 00:00:00 2001 From: pgarrison Date: Mon, 12 Jul 2021 16:45:35 -0700 Subject: [PATCH 11/20] Make deepEqual actually recursive This is much sloppier than the underscore function, but the deepest object the tests compare to is something like [["Paul", "Maud'Dib"]] --- tests/doctests.js | 33 +++++++++++++++++---------------- tests/doctests.tmpl | 23 ++++++++++++----------- tests/tests.js | 23 ++++++++++++----------- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/tests/doctests.js b/tests/doctests.js index 905437e..50dedb0 100644 --- a/tests/doctests.js +++ b/tests/doctests.js @@ -20,22 +20,23 @@ else { 'equal': function(actual, expected) { if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }, - 'deepEqual': function(actual, expected) { - var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected); - var has_error = false; - if (actual_keys.length != expected_keys.length) - has_error = true; - - actual_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; - }); - - expected_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; - }); - - if (has_error) - throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); + '_eq': function(actual, expected) { + if (typeof actual != 'object') return actual === expected; + + var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected); + if (actual_keys.length != expected_keys.length) + return false; + + var result = true; + actual_keys.forEach(function(key) { + if (!assert._eq(actual[key], expected[key])) result = false; + }); + + return result; + }, + 'deepEqual': function(actual, expected) { + if (!assert._eq(actual, expected)) + throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); } }; } diff --git a/tests/doctests.tmpl b/tests/doctests.tmpl index 36bcd00..70d061c 100644 --- a/tests/doctests.tmpl +++ b/tests/doctests.tmpl @@ -20,21 +20,22 @@ else { 'equal': function(actual, expected) { if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }, - 'deepEqual': function(actual, expected) { + '_eq': function(actual, expected) { + if (typeof actual != 'object') return actual === expected; + var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected); - var has_error = false; - if (actual_keys.length != expected_keys.length) - has_error = true; - - actual_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; - }); + if (actual_keys.length != expected_keys.length) + return false; - expected_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; + var result = true; + actual_keys.forEach(function(key) { + if (!assert._eq(actual[key], expected[key])) result = false; }); - if (has_error) + return result; + }, + 'deepEqual': function(actual, expected) { + if (!assert._eq(actual, expected)) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); } }; diff --git a/tests/tests.js b/tests/tests.js index b57c854..7c84384 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -24,21 +24,22 @@ else { assert.equal = function(actual, expected) { if (actual != expected) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }; - assert.deepEqual = function(actual, expected) { + assert._eq = function(actual, expected) { + if (typeof actual != 'object') return actual === expected; + var actual_keys = Object.keys(actual), expected_keys = Object.keys(expected); - var has_error = false; - if (actual_keys.length != expected_keys.length) - has_error = true; - - actual_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; - }); + if (actual_keys.length != expected_keys.length) + return false; - expected_keys.forEach(function(key) { - if (actual[key] != expected[key]) has_error = true; + var result = true; + actual_keys.forEach(function(key) { + if (!assert._eq(actual[key], expected[key])) result = false; }); - if (has_error) + return result; + }; + assert.deepEqual = function(actual, expected) { + if (!assert._eq(actual, expected)) throw new Error(JSON.stringify(actual) + ' == ' + JSON.stringify(expected)); }; assert.throws = function(fn) { From 9fa50b3eb842c520aa6cf1daff09e035051fcd40 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Tue, 7 Sep 2021 10:33:41 -0700 Subject: [PATCH 12/20] 3.0.0-beta.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e56ff63..fa8a44e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sql-bricks", - "version": "3.0.0-beta.2", + "version": "3.0.0-beta.3", "author": "Peter Rust ", "description": "Transparent, Schemaless SQL Generation", "homepage": "http://csnw.github.io/sql-bricks", From 3f544f1d9c5e5dae431e29c32b0df7e99abcf795 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 30 Mar 2022 12:37:40 -0700 Subject: [PATCH 13/20] Fixed findIndex bug introduced in 25f46ca68a, added regression test --- sql-bricks.js | 2 +- tests/tests.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sql-bricks.js b/sql-bricks.js index 3044eef..7a1035e 100644 --- a/sql-bricks.js +++ b/sql-bricks.js @@ -59,7 +59,7 @@ function findIndex(arr, fn) { for (var i = 0; i < arr.length; i++) { - if (fn(val)) { + if (fn(arr[i])) { return i; } } diff --git a/tests/tests.js b/tests/tests.js index 7c84384..54bbf8d 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -974,6 +974,23 @@ describe('SQL Bricks', function() { assert(ext.select.prototype.clauses !== sql.select.prototype.clauses) }); }); + + describe('defineClause', function() { + // this extension mechanism is used by sql-bricks-postgres + it('should be able to inject clauses after other clauses', function() { + var Insert = sql.insert; + Insert.defineClause('returning', function(opts) { + return `RETURNING test_column`; + }, {after: 'values'}); + + check(insert('user', {'id': 33, 'name': 'Fred'}), + "INSERT INTO \"user\" (id, name) VALUES (33, 'Fred') RETURNING test_column"); + + // remove the newly-added clause, so subsequent INSERT tests won't fail + var ix = Insert.prototype.clauses.findIndex(clause => clause.clause_id == 'returning'); + Insert.prototype.clauses.splice(ix, 1); + }); + }) }); function check(stmt, expected) { From 038029ac7a41f2db89e10347cf4a62cdd3a58237 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 30 Mar 2022 12:38:03 -0700 Subject: [PATCH 14/20] 3.0.0-beta.4 --- package-lock.json | 963 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 964 insertions(+), 1 deletion(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..020315c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,963 @@ +{ + "name": "sql-bricks", + "version": "3.0.0-beta.4", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "es-abstract": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.2.tgz", + "integrity": "sha512-gfSBJoZdlL2xRiOCy0g8gLMryhoe1TlimjzU99L/31Z8QEGIhVQI+EWwt5lT+AuU9SnorVupXFqqOGqGfsyO6w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + }, + "dependencies": { + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", + "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "2.2.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.4", + "ms": "2.1.1", + "node-environment-flags": "1.0.5", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", + "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", + "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } +} diff --git a/package.json b/package.json index fa8a44e..a753e29 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sql-bricks", - "version": "3.0.0-beta.3", + "version": "3.0.0-beta.4", "author": "Peter Rust ", "description": "Transparent, Schemaless SQL Generation", "homepage": "http://csnw.github.io/sql-bricks", From 4a195d1a77616d58836b16a129cb8123ae66a760 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 30 Mar 2022 12:41:55 -0700 Subject: [PATCH 15/20] Fixed outdated readme sentence re: dependencies --- readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/readme.md b/readme.md index eb68629..5ee2bb6 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ SQL Bricks.js is a transparent, schemaless library for building and composing SQ - Over [200 tests](http://csnw.github.io/sql-bricks/browser-tests.html) - Easy-to-use, comprehensive [docs](http://csnw.github.io/sql-bricks) - Single [source file](sql-bricks.js) (~1,100 lines) +- No production dependencies and only 1 dev dependency (Mocha.js) Comparison with other SQL-generation JS libraries: @@ -57,8 +58,6 @@ library | lines | files | schema | other notes # Use -SQLBricks' only dependency is [Underscore.js](http://underscorejs.org/). - In the browser: ```javascript From 5eb39fbea9b31ce51b6ee5fd81917b268717cbb7 Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 30 Mar 2022 13:15:26 -0700 Subject: [PATCH 16/20] 3.0.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 020315c..f3614e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "sql-bricks", - "version": "3.0.0-beta.4", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a753e29..02b7ff1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sql-bricks", - "version": "3.0.0-beta.4", + "version": "3.0.0", "author": "Peter Rust ", "description": "Transparent, Schemaless SQL Generation", "homepage": "http://csnw.github.io/sql-bricks", From a004a72c17bc0010366bbd8cfeb5f1590db16c4e Mon Sep 17 00:00:00 2001 From: Peter Rust Date: Wed, 30 Mar 2022 13:35:32 -0700 Subject: [PATCH 17/20] Updated docs re: underscore.js removal and http->https --- index.html | 15 +++++++-------- readme.md | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 6185a02..a2912fc 100644 --- a/index.html +++ b/index.html @@ -6,7 +6,7 @@ - + SQL Bricks