From 10304498703c516ec2e8197832070f2457de681c Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Fri, 19 Feb 2016 17:02:20 -0600 Subject: [PATCH 01/37] support projections in populates --- sequel/select.js | 12 ++++++++++++ sequel/where.js | 44 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/sequel/select.js b/sequel/select.js index cd54434..a017e03 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -66,6 +66,18 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje var selectKeys = []; var query = 'SELECT '; + // If there is a select projection, ensure that the primary key is added. + var pk; + _.each(this.schema[this.currentTable].attributes, function(val, key) { + if(_.has(val, 'primaryKey') && val.primaryKey) { + pk = key; + } + }); + + if(queryObject.select && !_.includes(queryObject.select, pk)) { + queryObject.select.push(pk); + } + var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].attributes); delete queryObject.select; diff --git a/sequel/where.js b/sequel/where.js index 39f8e59..ea6d63c 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -71,7 +71,7 @@ var WhereBuilder = module.exports = function WhereBuilder(schema, currentTable, if(options && hop(options, 'schemaName')) { this.schemaName = options.schemaName; - } + } return this; }; @@ -84,8 +84,8 @@ var WhereBuilder = module.exports = function WhereBuilder(schema, currentTable, WhereBuilder.prototype.single = function single(queryObject, options) { if(!queryObject) return { - query: '', - values: [] + query: '', + values: [] }; var self = this; @@ -233,7 +233,27 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Read the queryObject and get back a query string and params parsedCriteria = criteriaParser.read(population.criteria); - queryString = '(SELECT * FROM ' + utils.escapeName(population.child, self.escapeCharacter, self.schemaName) + ' AS ' + utils.escapeName(populationAlias, self.escapeCharacter) + ' WHERE ' + utils.escapeName(population.childKey, self.escapeCharacter) + ' = ^?^ '; + queryString = '(SELECT '; + if(_.isArray(population.select) && population.select.length) { + var selectKeys = population.select.map(function(projection) { + return { table: population.child, key: projection }; + }); + + _.each(selectKeys, function(projection) { + var projectionAlias = _.find(_.values(self.schema), {tableName: projection.table}).tableName; + queryString += utils.escapeName(projectionAlias, self.escapeCharacter) + '.' + + utils.escapeName(projection.key, self.escapeCharacter) + ','; + }); + // remove trailing comma + population.select.length && (queryString.slice(-1) === ',') && (queryString = queryString.slice(0, -1)); + } + else { + queryString += '*'; + } + + // Build the rest of the query string + queryString += ' FROM ' + utils.escapeName(population.child, self.escapeCharacter, self.schemaName) + ' AS ' + utils.escapeName(populationAlias, self.escapeCharacter) + ' WHERE ' + utils.escapeName(population.childKey, self.escapeCharacter) + ' = ^?^ '; + if(parsedCriteria) { // If where criteria was used append an AND clause @@ -292,12 +312,16 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Look into the schema and build up attributes to select var selectKeys = []; - - _.keys(self.schema[stage2ChildAlias].attributes).forEach(function(key) { - var schema = self.schema[stage2ChildAlias].attributes[key]; - if(hop(schema, 'collection')) return; - selectKeys.push({ table: stage2.child, key: schema.columnName || key }); - }); + if(_.isArray(stage2.select) && stage2.select.length) { + var selectKeys = stage2.select.map(function(projection) { + return { table: stage2.child, key: projection }; + }); + } else { + _.each(self.schema[stage2ChildAlias].attributes, function(val, key) { + if(_.has(val, 'collection')) return; + selectKeys.push({ table: stage2.child, key: val.columnName || key }); + }); + } queryString += '(SELECT '; selectKeys.forEach(function(projection) { From b3a5e41714b0cb4a0ff676bd26df8d3f9bc6f66e Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 16 Mar 2016 18:04:34 -0500 Subject: [PATCH 02/37] use the definition for select's rather than attributes --- sequel/lib/criteriaProcessor.js | 6 +++--- sequel/select.js | 12 ++++++------ sequel/where.js | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sequel/lib/criteriaProcessor.js b/sequel/lib/criteriaProcessor.js index c158ac3..be2cb51 100644 --- a/sequel/lib/criteriaProcessor.js +++ b/sequel/lib/criteriaProcessor.js @@ -36,7 +36,7 @@ var CriteriaProcessor = module.exports = function CriteriaProcessor(currentTable this.currentTable = currentTable; this.schema = schema; - this.currentSchema = schema[currentTable].attributes; + this.currentSchema = schema[currentTable].definition; this.tableScope = null; this.queryString = ''; this.values = []; @@ -428,7 +428,7 @@ CriteriaProcessor.prototype.findChild = function findChild (child) { CriteriaProcessor.prototype.processSimple = function processSimple (tableName, parent, value, combinator, sensitive) { // Set lower logic to true var sensitiveTypes = ['text', 'string'], - currentSchema = this.schema[tableName].attributes, + currentSchema = this.schema[tableName].definition, self = this, parentType, lower; @@ -499,7 +499,7 @@ CriteriaProcessor.prototype.processSimple = function processSimple (tableName, p * @param {string} [alias] */ CriteriaProcessor.prototype.processObject = function processObject (tableName, parent, value, combinator, sensitive) { - var currentSchema = this.schema[tableName].attributes, + var currentSchema = this.schema[tableName].definition, self = this, parentType; diff --git a/sequel/select.js b/sequel/select.js index a017e03..5e9e7f8 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -15,7 +15,7 @@ var hop = utils.object.hasOwnProperty; var SelectBuilder = module.exports = function(schema, currentTable, queryObject, options) { this.schema = schema; - this.currentSchema = schema[currentTable].attributes; + this.currentSchema = schema[currentTable].definition; this.currentTable = currentTable; this.escapeCharacter = '"'; this.cast = false; @@ -68,7 +68,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje // If there is a select projection, ensure that the primary key is added. var pk; - _.each(this.schema[this.currentTable].attributes, function(val, key) { + _.each(this.schema[this.currentTable].definition, function(val, key) { if(_.has(val, 'primaryKey') && val.primaryKey) { pk = key; } @@ -78,14 +78,14 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje queryObject.select.push(pk); } - var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].attributes); + var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].definition); delete queryObject.select; attributes.forEach(function(key) { // Default schema to {} in case a raw DB column name is sent. This shouldn't happen // after https://github.com/balderdashy/waterline/commit/687c869ad54f499018ab0b038d3de4435c96d1dd // but leaving here as a failsafe. - var schema = self.schema[self.currentTable].attributes[key] || {}; + var schema = self.schema[self.currentTable].definition[key] || {}; if(hop(schema, 'collection')) return; selectKeys.push({ table: self.currentTable, key: schema.columnName || key }); }); @@ -101,8 +101,8 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje // Handle hasFK var childAlias = _.find(_.values(self.schema), {tableName: population.child}).tableName; - _.keys(self.schema[childAlias].attributes).forEach(function(key) { - var schema = self.schema[childAlias].attributes[key]; + _.keys(self.schema[childAlias].definition).forEach(function(key) { + var schema = self.schema[childAlias].definition[key]; if(hop(schema, 'collection')) return; selectKeys.push({ table: population.alias ? "__"+population.alias : population.child, key: schema.columnName || key, alias: population.parentKey }); }); diff --git a/sequel/where.js b/sequel/where.js index ea6d63c..0ec8d13 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -122,8 +122,8 @@ WhereBuilder.prototype.single = function single(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(queryObject, 'sort')) { var childPK; - _.keys(this.schema[this.currentTable].attributes).forEach(function(attr) { - var expandedAttr = self.schema[self.currentTable].attributes[attr]; + _.keys(this.schema[this.currentTable].definition).forEach(function(attr) { + var expandedAttr = self.schema[self.currentTable].definition[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; }); @@ -220,8 +220,8 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(population.criteria, 'sort')) { - _.keys(self.schema[populationAlias].attributes).forEach(function(attr) { - var expandedAttr = self.schema[populationAlias].attributes[attr]; + _.keys(self.schema[populationAlias].definition).forEach(function(attr) { + var expandedAttr = self.schema[populationAlias].definition[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; }); From 2091e423b76943b4039594276a6205079df9271c Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 16 Mar 2016 18:07:21 -0500 Subject: [PATCH 03/37] add definition to satisfy tests --- test/schema.js | 131 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/test/schema.js b/test/schema.js index 383e851..ae6dcef 100644 --- a/test/schema.js +++ b/test/schema.js @@ -22,6 +22,25 @@ module.exports = { type : "datetime", default: "NOW" } + }, + definition: { + color_a : "string", + color_b : "string", + color_c : "string", + id : { + type : "integer", + autoIncrement: true, + primaryKey : true, + unique : true + }, + createdAt: { + type : "datetime", + default: "NOW" + }, + updatedAt: { + type : "datetime", + default: "NOW" + } } }, bat: { @@ -47,6 +66,25 @@ module.exports = { type : "datetime", default: "NOW" } + }, + definition: { + color_g : "string", + color_h : "string", + color_i : "string", + id : { + type : "integer", + autoIncrement: true, + primaryKey : true, + unique : true + }, + createdAt: { + type : "datetime", + default: "NOW" + }, + updatedAt: { + type : "datetime", + default: "NOW" + } } }, baz: { @@ -72,6 +110,25 @@ module.exports = { type : "datetime", default: "NOW" } + }, + definition: { + color_d : "string", + color_e : "string", + color_f : "string", + id : { + type : "integer", + autoIncrement: true, + primaryKey : true, + unique : true + }, + createdAt: { + type : "datetime", + default: "NOW" + }, + updatedAt: { + type : "datetime", + default: "NOW" + } } }, foo: { @@ -119,6 +176,47 @@ module.exports = { on : "id", onKey : "id" } + }, + definition: { + color : "string", + id : { + type : "integer", + autoIncrement: true, + primaryKey : true, + unique : true + }, + createdAt: { + type : "datetime", + default: "NOW" + }, + updatedAt: { + type : "datetime", + default: "NOW" + }, + bar : { + columnName: "bar", + type : "integer", + foreignKey: true, + references: "bar", + on : "id", + onKey : "id" + }, + bat : { + columnName: "bat", + type : "integer", + foreignKey: true, + references: "bat", + on : "id", + onKey : "id" + }, + baz : { + columnName: "baz", + type : "integer", + foreignKey: true, + references: "baz", + on : "id", + onKey : "id" + } } }, oddity: { @@ -158,6 +256,39 @@ module.exports = { on : "id", onKey : "id" } + }, + definition: { + meta : "string", + id : { + type : "integer", + autoIncrement: true, + primaryKey : true, + unique : true + }, + createdAt: { + type : "datetime", + default: "NOW" + }, + updatedAt: { + type : "datetime", + default: "NOW" + }, + bar : { + columnName: "stubborn", + type : "integer", + foreignKey: true, + references: "bar", + on : "id", + onKey : "id" + }, + bat : { + columnName: "bat", + type : "integer", + foreignKey: true, + references: "bat", + on : "id", + onKey : "id" + } } } }; From 23cfcc715cf38bec5ad70ec9fb981952c9112598 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Thu, 17 Mar 2016 11:37:13 -0500 Subject: [PATCH 04/37] respect select criteria in hasFK type joins --- sequel/select.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sequel/select.js b/sequel/select.js index 5e9e7f8..65cd409 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -101,10 +101,16 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje // Handle hasFK var childAlias = _.find(_.values(self.schema), {tableName: population.child}).tableName; - _.keys(self.schema[childAlias].definition).forEach(function(key) { + // Ensure the foreignKey is selected if a custom select was defined + if(population.select && !_.includes(population.select, population.childKey)) { + population.select.push(population.childKey); + } + + var attributes = population.select || _.keys(self.schema[childAlias].definition); + _.each(attributes, function(key) { var schema = self.schema[childAlias].definition[key]; if(hop(schema, 'collection')) return; - selectKeys.push({ table: population.alias ? "__"+population.alias : population.child, key: schema.columnName || key, alias: population.parentKey }); + selectKeys.push({ table: population.alias ? '__' + population.alias : population.child, key: schema.columnName || key, alias: population.parentKey }); }); }); From c9599441a6fee6958bfb95a93af99233232442f7 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Thu, 17 Mar 2016 16:23:04 -0500 Subject: [PATCH 05/37] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f08106..a849031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Waterline-Sequel Changelog +### 0.6.0 + +* [ENHANCEMENT] Add the ability to use projections in join queries. See [#80](https://github.com/balderdashy/waterline-sequel/pull/80) for more details. + ### 0.5.7 * [Bug] Actually fixes issue when building criteria with dates instead of causing more issues. See [#79](https://github.com/balderdashy/waterline-sequel/pull/79) for more. From f88eb82d58dad45f7a674cf80fc3a3a92b74b30c Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Thu, 17 Mar 2016 16:25:07 -0500 Subject: [PATCH 06/37] 0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c16b1e..d3f7da7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "waterline-sequel", "description": "A helper library for generating SQL queries from the Waterline Query Language.", - "version": "0.5.7", + "version": "0.6.0", "author": "Cody Stoltman ", "url": "http://github.com/balderdashy/waterline-sequel", "keywords": [], From b07af495df5f6d65d566de2c17147a58e1b00df2 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 21 Mar 2016 17:24:35 -0500 Subject: [PATCH 07/37] ignore schema values that are undefined --- sequel/select.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sequel/select.js b/sequel/select.js index 65cd409..79e78c5 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -86,6 +86,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje // after https://github.com/balderdashy/waterline/commit/687c869ad54f499018ab0b038d3de4435c96d1dd // but leaving here as a failsafe. var schema = self.schema[self.currentTable].definition[key] || {}; + if(!schema) return; if(hop(schema, 'collection')) return; selectKeys.push({ table: self.currentTable, key: schema.columnName || key }); }); @@ -109,6 +110,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje var attributes = population.select || _.keys(self.schema[childAlias].definition); _.each(attributes, function(key) { var schema = self.schema[childAlias].definition[key]; + if(!schema) return; if(hop(schema, 'collection')) return; selectKeys.push({ table: population.alias ? '__' + population.alias : population.child, key: schema.columnName || key, alias: population.parentKey }); }); From 9b7292babc6decf25825be1ef01823c0cac0939c Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 22 Mar 2016 11:06:25 -0500 Subject: [PATCH 08/37] bump waterline-adapter-tests dev dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d3f7da7..539d324 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "sails-mysql": "balderdashy/sails-mysql", "sails-postgresql": "balderdashy/sails-postgresql", "should": "8.2.1", - "waterline-adapter-tests": "~0.10.17" + "waterline-adapter-tests": "~0.12.0" }, "scripts": { "test": "make test", From cba3425d4a9c41d6b93a062d3b3fce149a0b6e72 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 22 Mar 2016 11:07:02 -0500 Subject: [PATCH 09/37] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a849031..d7fce39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Waterline-Sequel Changelog +### 0.6.1 + +* [BUG] Fix an issue when populating the one side of a one-to-many association where virtual attributes were trying to be selected. See [#84](https://github.com/balderdashy/waterline-sequel/pull/84) for more details. Thanks [@Bazze](https://github.com/Bazze) for the issue submission. + ### 0.6.0 * [ENHANCEMENT] Add the ability to use projections in join queries. See [#80](https://github.com/balderdashy/waterline-sequel/pull/80) for more details. From ea36547c93fd909343b92dec8745f5aa7b5dfbb2 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 22 Mar 2016 11:07:10 -0500 Subject: [PATCH 10/37] 0.6.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 539d324..50a529b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "waterline-sequel", "description": "A helper library for generating SQL queries from the Waterline Query Language.", - "version": "0.6.0", + "version": "0.6.1", "author": "Cody Stoltman ", "url": "http://github.com/balderdashy/waterline-sequel", "keywords": [], From 4ecceffa41c876c9386cf68049fa91a9b08f6d65 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 22 Mar 2016 17:58:53 -0500 Subject: [PATCH 11/37] filter projections in complex queries --- sequel/where.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sequel/where.js b/sequel/where.js index 0ec8d13..4c0e308 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -241,6 +241,24 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { _.each(selectKeys, function(projection) { var projectionAlias = _.find(_.values(self.schema), {tableName: projection.table}).tableName; + + // Find the projection in the schema and make sure it's a valid key + // that can be selected. + var schema = _.find(self.schema[projection.table]); + if(!schema) { + return; + } + + var schemaVal = schema[projection.key]; + if(!schemaVal) { + return; + } + + // If this is a virtual attribute, it can't be selected + if(_.has(schemaVal, 'collection')) { + return; + } + queryString += utils.escapeName(projectionAlias, self.escapeCharacter) + '.' + utils.escapeName(projection.key, self.escapeCharacter) + ','; }); @@ -326,6 +344,24 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { queryString += '(SELECT '; selectKeys.forEach(function(projection) { var projectionAlias = _.find(_.values(self.schema), {tableName: projection.table}).tableName; + + // Find the projection in the schema and make sure it's a valid key + // that can be selected. + var schema = _.find(self.schema[projection.table]); + if(!schema) { + return; + } + + var schemaVal = schema[projection.key]; + if(!schemaVal) { + return; + } + + // If this is a virtual attribute, it can't be selected + if(_.has(schemaVal, 'collection')) { + return; + } + queryString += utils.escapeName(projectionAlias, self.escapeCharacter) + '.' + utils.escapeName(projection.key, self.escapeCharacter) + ','; }); From 32e089a009c027b87e458835320d0eb2ad14f3ba Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 23 Mar 2016 11:16:40 -0500 Subject: [PATCH 12/37] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7fce39..d5b97d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Waterline-Sequel Changelog +### 0.6.2 + +* [BUG] Fix the second part of the issue from `0.6.0` this time by updating the complex queries. See [#85](https://github.com/balderdashy/waterline-sequel/pull/85) for more details. Thanks again to [@Bazze](https://github.com/Bazze), [@wulfsolter](https://github.com/wulfsolter) and others who helped debug this. + ### 0.6.1 * [BUG] Fix an issue when populating the one side of a one-to-many association where virtual attributes were trying to be selected. See [#84](https://github.com/balderdashy/waterline-sequel/pull/84) for more details. Thanks [@Bazze](https://github.com/Bazze) for the issue submission. From 998b9efbb30870211be36a391b5365021e7c7163 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 23 Mar 2016 11:16:55 -0500 Subject: [PATCH 13/37] 0.6.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50a529b..856582f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "waterline-sequel", "description": "A helper library for generating SQL queries from the Waterline Query Language.", - "version": "0.6.1", + "version": "0.6.2", "author": "Cody Stoltman ", "url": "http://github.com/balderdashy/waterline-sequel", "keywords": [], From ae8dfd05751c0794c68b16e2a3efa52c32f0efa8 Mon Sep 17 00:00:00 2001 From: Kevin Burke Date: Tue, 29 Mar 2016 08:39:41 -0700 Subject: [PATCH 14/37] Throw an error if the operator is unknown Previously passing a query with an unknown operator would place the word "undefined" in the SQL query: ```javascript sequel.find('users', { balance: { 'in': [ 1, 2 ] } }); ``` ```sql 'SELECT "users"."id", "users"."email", "users"."balance", "users"."pickupCount" FROM "users" AS "users" "users"."balance" undefined ' ``` (Valid operators are things like 'contains', 'startsWith', 'endsWith', '>'.) This happens because we define the var `str` to be undefined, never set it, and then append it to the query string. Instead, immediately throw an error when an unknown key gets passed to Waterline, which should help diagnose these problems going forward (instead of forcing us to parse a Postgres syntax error). Cherry-picked from https://github.com/Shyp/waterline-sequel/pull/6. Fixes #86. --- Makefile | 7 ++++++- sequel/lib/criteriaProcessor.js | 5 +++++ test/unit/index.test.js | 10 +++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b2a610a..4784f5e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,10 @@ +.PHONY: test test-unit install test-integration + ROOT=$(shell pwd) +install: + npm install + test: test-unit test-unit: @@ -12,4 +17,4 @@ test-integration: ln -s $(ROOT) node_modules/sails-postgresql/node_modules/waterline-sequel rm -rf node_modules/sails-mysql/node_modules/waterline-sequel ln -s $(ROOT) node_modules/sails-mysql/node_modules/waterline-sequel - @NODE_ENV=test node test/integration/runnerDispatcher.js \ No newline at end of file + @NODE_ENV=test node test/integration/runnerDispatcher.js diff --git a/sequel/lib/criteriaProcessor.js b/sequel/lib/criteriaProcessor.js index be2cb51..2fcffdc 100644 --- a/sequel/lib/criteriaProcessor.js +++ b/sequel/lib/criteriaProcessor.js @@ -830,6 +830,11 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va } break; + + default: + var err = new Error('Unknown filtering operator: "' + key + "\". Should be 'startsWith', '>', 'contains' or similar"); + err.operator = key; + throw err; } // Bump paramCount diff --git a/test/unit/index.test.js b/test/unit/index.test.js index dce209d..c16a168 100644 --- a/test/unit/index.test.js +++ b/test/unit/index.test.js @@ -82,6 +82,14 @@ describe('Sequel', function () { }); }); + describe('queries with an unknown operator', function () { + it('throws an error when the operator is unknown', function() { + var sequel = new Sequel(schema); + assert.throws(sequel.find.bind(sequel, 'bar', { id: { 'in': [ 1, 2 ] } }), + Error, "Unknown filtering operator: \"in\". Should be 'startsWith', '>', 'contains' or similar"); + }); + }); + describe('.find() with schema name', function () { var _options = _.extend({}, options, {schemaName: {'foo':'myschema','oddity':'anotherschema','bat':'public'}}); // Loop through the query objects and test them against the `.find()` method. @@ -99,5 +107,5 @@ describe('Sequel', function () { done(); }); }); - }); + }); }); From fc03cf3b5462ae9daa216ddd3d8a7baeeaf5631a Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 11 Apr 2016 18:06:13 -0500 Subject: [PATCH 15/37] fix to not use lodash method incorrectly my brain must have been mush when this was written --- sequel/where.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sequel/where.js b/sequel/where.js index 4c0e308..b72d19f 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -244,12 +244,12 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Find the projection in the schema and make sure it's a valid key // that can be selected. - var schema = _.find(self.schema[projection.table]); - if(!schema) { + var schema = self.schema[projection.table]; + if(!schema || !schema.definition) { return; } - var schemaVal = schema[projection.key]; + var schemaVal = schema.definition[projection.key]; if(!schemaVal) { return; } @@ -347,7 +347,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Find the projection in the schema and make sure it's a valid key // that can be selected. - var schema = _.find(self.schema[projection.table]); + var schema = self.schema[projection.table]; if(!schema) { return; } From 4d55945470972a73f1b23f55fb8c6507139ab7c7 Mon Sep 17 00:00:00 2001 From: acekat Date: Mon, 23 May 2016 09:28:05 +0200 Subject: [PATCH 16/37] Missing changes relative to #fc03cf3 --- sequel/where.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sequel/where.js b/sequel/where.js index b72d19f..720ed44 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -348,11 +348,11 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Find the projection in the schema and make sure it's a valid key // that can be selected. var schema = self.schema[projection.table]; - if(!schema) { + if(!schema || !schema.definition) { return; } - var schemaVal = schema[projection.key]; + var schemaVal = schema.definition[projection.key]; if(!schemaVal) { return; } From cbe58928dbde9f5f23737724053e57086e81a996 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 6 Jun 2016 17:15:14 -0500 Subject: [PATCH 17/37] bump travis node versions --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 39ed8d6..908d09d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ -language: node_js - +anguage: node_js node_js: - - 0.10 - - 0.11 \ No newline at end of file + - "5.0" + - "4.0" + - "0.12" + - "0.10" +sudo: false From 3571582e1fb863986ca1290e9f93945d3fcb3bb0 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 6 Jun 2016 17:20:01 -0500 Subject: [PATCH 18/37] fix spelling --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 908d09d..add628c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -anguage: node_js +language: node_js node_js: - "5.0" - "4.0" From bd7346c577b9baeb74835af0b16095fad1633374 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 6 Jun 2016 17:28:36 -0500 Subject: [PATCH 19/37] 0.6.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 856582f..b4f3020 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "waterline-sequel", "description": "A helper library for generating SQL queries from the Waterline Query Language.", - "version": "0.6.2", + "version": "0.6.3", "author": "Cody Stoltman ", "url": "http://github.com/balderdashy/waterline-sequel", "keywords": [], From 47567b4ddae481ca3bff831a3a1d8df3fc400b3a Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Mon, 6 Jun 2016 17:33:51 -0500 Subject: [PATCH 20/37] update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5b97d0..75630ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Waterline-Sequel Changelog +### 0.6.3 + +* [ENHANCEMENT] Added newer versions of Node to the Travis test runner. + +* [BUG] Fix a bug from a previous commit. See [#91](https://github.com/balderdashy/waterline-sequel/pull/91) for more details. Thanks to [@acekat](https://github.com/acekat) for the patch. + +* [STABILITY] Fix to prevent undefined keys from being used. See [95b0a080a9c5010d867a5dca80b7084501f8dad4](https://github.com/balderdashy/waterline-sequel/commit/95b0a080a9c5010d867a5dca80b7084501f8dad4) for more details. + +* [BUG] Fix for unknown operators. See [#87](https://github.com/balderdashy/waterline-sequel/pull/87) for more details. Thanks to [@kevinburkeshyp](https://github.com/kevinburkeshyp) for the patch. + ### 0.6.2 * [BUG] Fix the second part of the issue from `0.6.0` this time by updating the complex queries. See [#85](https://github.com/balderdashy/waterline-sequel/pull/85) for more details. Thanks again to [@Bazze](https://github.com/Bazze), [@wulfsolter](https://github.com/wulfsolter) and others who helped debug this. From 52391687e6aff5ecd060169360a9a220d9f27404 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 7 Jun 2016 15:35:30 -0500 Subject: [PATCH 21/37] normalize use of lodash methods --- sequel/lib/cast.js | 2 +- sequel/lib/criteriaProcessor.js | 28 ++++++++++++++-------------- sequel/lib/utils.js | 6 +++--- sequel/select.js | 28 ++++++++++++++-------------- sequel/where.js | 12 ++++++------ 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/sequel/lib/cast.js b/sequel/lib/cast.js index e39d41d..b38f8fc 100644 --- a/sequel/lib/cast.js +++ b/sequel/lib/cast.js @@ -9,7 +9,7 @@ Query.prototype.cast = function(values) { var self = this; var _values = _.clone(values); - Object.keys(values).forEach(function(key) { + _.each(_.keys(values), function(key) { self.castValue(key, _values[key], _values, self._schema); }); diff --git a/sequel/lib/criteriaProcessor.js b/sequel/lib/criteriaProcessor.js index 2fcffdc..186809d 100644 --- a/sequel/lib/criteriaProcessor.js +++ b/sequel/lib/criteriaProcessor.js @@ -100,7 +100,7 @@ CriteriaProcessor.prototype.read = function read(options) { delete _options.groupBy; if(_options.where !== null) { - _.keys(_options).forEach(function(key) { + _.each(_.keys(_options), function(key) { self.expand(key, _options[key]); }); } @@ -174,18 +174,18 @@ CriteriaProcessor.prototype.or = function or(val) { var self = this; - if(!Array.isArray(val)) { + if(!_.isArray(val)) { throw new Error('`or` statements must be in an array.'); } // Wrap the entire OR clause this.queryString += '('; - val.forEach(function(statement) { + _.each(val, function(statement) { self.queryString += '('; // Recursively call expand. Assumes no nesting of `or` statements - _.keys(statement).forEach(function(key) { + _.each(_.keys(statement), function(key) { self.expand(key, statement[key]); }); @@ -236,7 +236,7 @@ CriteriaProcessor.prototype.like = function like(val) { self.queryString += ' AND '; }; - _.keys(val).forEach(function(parent) { + _.each(_.keys(val), function(parent) { expandBlock(parent); }); @@ -335,7 +335,7 @@ CriteriaProcessor.prototype._in = function _in(key, val) { } // Append each value to query - val.forEach(function(value) { + _.each(val, function(value) { // If case sensitivity if off lowercase the value if(!caseSensitivity && _.isString(value)) { @@ -514,7 +514,7 @@ CriteriaProcessor.prototype.processObject = function processObject (tableName, p sensitiveTypes = ['text', 'string'], // haha, "sensitive types". "I'll watch 'the notebook' with you, babe." lower; - _.keys(obj).forEach(function(key) { + _.each(_.keys(obj), function(key) { if (child && !self.isOperator(key)) { self.tableScope = child; self.expand(key, obj[key]); @@ -684,7 +684,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va } else { // For array values, do a "NOT IN" - if (Array.isArray(value)) { + if (_.isArray(value)) { if(self.parameterized) { var params = []; @@ -692,7 +692,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va this.values = this.values.concat(value); str = 'NOT IN ('; - value.forEach(function() { + _.each(value, function() { params.push('$' + self.paramCount++); }); @@ -703,7 +703,7 @@ CriteriaProcessor.prototype.prepareCriterion = function prepareCriterion(key, va } else { str = 'NOT IN ('; - value.forEach(function(val) { + _.each(value, function(val) { if(_.isString(val)) { val = '"' + utils.escapeString(val) + '"'; @@ -874,13 +874,13 @@ CriteriaProcessor.prototype.skip = function(options) { */ CriteriaProcessor.prototype.sort = function(options) { - var keys = Object.keys(options); + var keys = _.keys(options); if (!keys.length) { return; } var self = this; this.queryString += ' ORDER BY '; - keys.forEach(function(key) { + _.each(keys, function(key) { var direction = options[key] === 1 ? 'ASC' : 'DESC'; self.queryString += utils.escapeName(self.currentTable, self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ' ' + direction + ', '; }); @@ -899,9 +899,9 @@ CriteriaProcessor.prototype.group = function(options) { this.queryString += ' GROUP BY '; // Normalize to array - if(!Array.isArray(options)) options = [options]; + if(!_.isArray(options)) options = [options]; - options.forEach(function(key) { + _.each(options, function(key) { // Check whether we are grouping by a column or an expression. if (_.includes(_.keys(self.currentSchema), key)) { self.queryString += utils.escapeName(self.currentTable, self.escapeCharacter, self.schemaName) + '.' + utils.escapeName(key, self.escapeCharacter) + ', '; diff --git a/sequel/lib/utils.js b/sequel/lib/utils.js index a142d2e..82718c9 100644 --- a/sequel/lib/utils.js +++ b/sequel/lib/utils.js @@ -47,7 +47,7 @@ utils.escapeName = function escapeName(name, escapeCharacter, schemaName) { var replacementString = '' + escapeCharacter + escapeCharacter; var replacementDot = '\.'; if (schemaName && schemaName[name]) { - return utils.escapeName(schemaName[name], escapeCharacter) + '.' + + return utils.escapeName(schemaName[name], escapeCharacter) + '.' + utils.escapeName(name, escapeCharacter); } return '' + escapeCharacter + name.replace(regex, replacementString).replace(/\./g, replacementDot) + escapeCharacter; @@ -87,7 +87,7 @@ utils.mapAttributes = function(data, options) { // Determine if we should escape the inserted characters var escapeInserts = options && utils.object.hasOwnProperty(options, 'escapeInserts') ? options.escapeInserts : false; - Object.keys(data).forEach(function(key) { + _.each(_.keys(data), function(key) { var k = escapeInserts ? (options.escapeCharacter + key + options.escapeCharacter) : key; keys.push(k); @@ -133,7 +133,7 @@ utils.prepareValue = function(value) { } // Store Arrays as strings - if (Array.isArray(value)) { + if (_.isArray(value)) { value = JSON.stringify(value); } diff --git a/sequel/select.js b/sequel/select.js index 79e78c5..b13c97d 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -78,10 +78,10 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje queryObject.select.push(pk); } - var attributes = queryObject.select || Object.keys(this.schema[this.currentTable].definition); + var attributes = queryObject.select || _.keys(this.schema[this.currentTable].definition); delete queryObject.select; - attributes.forEach(function(key) { + _.each(attributes, function(key) { // Default schema to {} in case a raw DB column name is sent. This shouldn't happen // after https://github.com/balderdashy/waterline/commit/687c869ad54f499018ab0b038d3de4435c96d1dd // but leaving here as a failsafe. @@ -92,7 +92,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje }); // Add any hasFK strategy joins to the main query - _.keys(queryObject.instructions).forEach(function(attr) { + _.each(_.keys(queryObject.instructions), function(attr) { var strategy = queryObject.instructions[attr].strategy.strategy; if(strategy !== 1) return; @@ -117,7 +117,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje }); // Add all the columns to be selected - selectKeys.forEach(function(select) { + _.each(selectKeys, function(select) { // If there is an alias, set it in the select (used for hasFK associations) if(select.alias) { query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ' AS ' + self.escapeCharacter + select.alias + '___' + select.key + self.escapeCharacter + ', '; @@ -156,9 +156,9 @@ SelectBuilder.prototype.processAggregates = function processAggregates(criteria) // Append groupBy columns to select statement if(criteria.groupBy) { - if(!Array.isArray(criteria.groupBy)) criteria.groupBy = [criteria.groupBy]; + if(!_.isArray(criteria.groupBy)) criteria.groupBy = [criteria.groupBy]; - criteria.groupBy.forEach(function(key, index) { + _.each(criteria.groupBy, function(key, index) { // Check whether we are grouping by a column or an expression. if (_.includes(_.keys(self.currentSchema), key)) { query += tableName + '.' + utils.escapeName(key, self.escapeCharacter) + ', '; @@ -171,8 +171,8 @@ SelectBuilder.prototype.processAggregates = function processAggregates(criteria) // Handle SUM if (criteria.sum) { var sum = ''; - if(Array.isArray(criteria.sum)) { - criteria.sum.forEach(function(opt) { + if(_.isArray(criteria.sum)) { + _.each(criteria.sum, function(opt) { sum = 'SUM(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')'; if(self.cast) { sum = 'CAST(' + sum + ' AS float)'; @@ -192,8 +192,8 @@ SelectBuilder.prototype.processAggregates = function processAggregates(criteria) // Handle AVG (casting to float to fix percision with trailing zeros) if (criteria.average) { var avg = ''; - if(Array.isArray(criteria.average)) { - criteria.average.forEach(function(opt){ + if(_.isArray(criteria.average)) { + _.each(criteria.average, function(opt){ avg = 'AVG(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ')'; if(self.cast) { avg = 'CAST( ' + avg + ' AS float)'; @@ -212,8 +212,8 @@ SelectBuilder.prototype.processAggregates = function processAggregates(criteria) // Handle MAX if (criteria.max) { var max = ''; - if(Array.isArray(criteria.max)) { - criteria.max.forEach(function(opt){ + if(_.isArray(criteria.max)) { + _.each(criteria.max, function(opt){ query += 'MAX(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', '; }); @@ -224,8 +224,8 @@ SelectBuilder.prototype.processAggregates = function processAggregates(criteria) // Handle MIN if (criteria.min) { - if(Array.isArray(criteria.min)) { - criteria.min.forEach(function(opt){ + if(_.isArray(criteria.min)) { + _.each(criteria.min, function(opt){ query += 'MIN(' + tableName + '.' + utils.escapeName(opt, self.escapeCharacter) + ') AS ' + opt + ', '; }); diff --git a/sequel/where.js b/sequel/where.js index 720ed44..0592a60 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -93,7 +93,7 @@ WhereBuilder.prototype.single = function single(queryObject, options) { var addSpace = false; // Add any hasFK strategy joins to the main query - _.keys(queryObject.instructions).forEach(function(attr) { + _.each(_.keys(queryObject.instructions), function(attr) { var strategy = queryObject.instructions[attr].strategy.strategy; var population = queryObject.instructions[attr].instructions[0]; @@ -122,7 +122,7 @@ WhereBuilder.prototype.single = function single(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(queryObject, 'sort')) { var childPK; - _.keys(this.schema[this.currentTable].definition).forEach(function(attr) { + _.each(_.keys(this.schema[this.currentTable].definition), function(attr) { var expandedAttr = self.schema[self.currentTable].definition[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; @@ -190,7 +190,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Look up the child instructions and build out a template for each based on the type of join. if(!queryObject) return ''; - _.keys(queryObject.instructions).forEach(function(attr) { + _.each(_.keys(queryObject.instructions), function(attr) { var queryString = ''; var criteriaParser; @@ -220,7 +220,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(population.criteria, 'sort')) { - _.keys(self.schema[populationAlias].definition).forEach(function(attr) { + _.each(_.keys(self.schema[populationAlias].definition), function(attr) { var expandedAttr = self.schema[populationAlias].definition[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; @@ -315,7 +315,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(stage2.criteria, 'sort')) { - _.keys(self.schema[stage2ChildAlias].attributes).forEach(function(attr) { + _.each(_.keys(self.schema[stage2ChildAlias].attributes), function(attr) { var expandedAttr = self.schema[stage2ChildAlias].attributes[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; @@ -342,7 +342,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { } queryString += '(SELECT '; - selectKeys.forEach(function(projection) { + _.each(selectKeys, function(projection) { var projectionAlias = _.find(_.values(self.schema), {tableName: projection.table}).tableName; // Find the projection in the schema and make sure it's a valid key From 6615181abd606a0d6b9159a4748eb88c2fc2163b Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 7 Jun 2016 15:48:23 -0500 Subject: [PATCH 22/37] only add the pk if its available, otherwise you end up with [undefined] --- sequel/select.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequel/select.js b/sequel/select.js index b13c97d..ba50eaf 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -74,7 +74,7 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje } }); - if(queryObject.select && !_.includes(queryObject.select, pk)) { + if(pk && queryObject.select && !_.includes(queryObject.select, pk)) { queryObject.select.push(pk); } From 124bc2a3d269c9c5b72da2da2e82417bcc51e667 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Tue, 7 Jun 2016 15:49:45 -0500 Subject: [PATCH 23/37] use a * so empty selects don't end up with SELEC FROM --- sequel/select.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sequel/select.js b/sequel/select.js index ba50eaf..6988915 100644 --- a/sequel/select.js +++ b/sequel/select.js @@ -126,8 +126,15 @@ SelectBuilder.prototype.buildSimpleSelect = function buildSimpleSelect(queryObje query += utils.escapeName(select.table, self.escapeCharacter) + '.' + utils.escapeName(select.key, self.escapeCharacter) + ', '; } }); - // Remove the last comma - query = query.slice(0, -2) + ' FROM ' + tableName + ' AS ' + utils.escapeName(self.currentTable, self.escapeCharacter) + ' '; + + // Remove the last comma in a list of items being selected + if(selectKeys.length) { + query = query.slice(0, -2); + } else { + query += '*'; + } + + query = query + ' FROM ' + tableName + ' AS ' + utils.escapeName(self.currentTable, self.escapeCharacter) + ' '; return query; }; From 3212732732378493fe53ee0c4f8518b32d254622 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 13:44:51 -0500 Subject: [PATCH 24/37] catch last piece that was still referencing .attributes --- sequel/where.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sequel/where.js b/sequel/where.js index 0592a60..16036d5 100644 --- a/sequel/where.js +++ b/sequel/where.js @@ -315,8 +315,8 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { // Ensure a sort is always set so that we get back consistent results if(!hop(stage2.criteria, 'sort')) { - _.each(_.keys(self.schema[stage2ChildAlias].attributes), function(attr) { - var expandedAttr = self.schema[stage2ChildAlias].attributes[attr]; + _.each(_.keys(self.schema[stage2ChildAlias].definition), function(attr) { + var expandedAttr = self.schema[stage2ChildAlias].definition[attr]; if(!hop(expandedAttr, 'primaryKey')) return; childPK = expandedAttr.columnName || attr; }); @@ -335,7 +335,7 @@ WhereBuilder.prototype.complex = function complex(queryObject, options) { return { table: stage2.child, key: projection }; }); } else { - _.each(self.schema[stage2ChildAlias].attributes, function(val, key) { + _.each(self.schema[stage2ChildAlias].definition, function(val, key) { if(_.has(val, 'collection')) return; selectKeys.push({ table: stage2.child, key: val.columnName || key }); }); From 0ee75c6851b44d07db62a444fe0718771f89e14a Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 15:01:52 -0500 Subject: [PATCH 25/37] bump lodash to latest 3.x version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b4f3020..a101340 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "url": "git://github.com/balderdashy/waterline-sequel.git" }, "dependencies": { - "lodash": "3.10.0" + "lodash": "3.10.1" }, "devDependencies": { "async": "1.5.2", From 448ef9063a304fb17c1f0960a91658697d63eb88 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 15:02:19 -0500 Subject: [PATCH 26/37] update outdated dependencies to remove warning messages --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index a101340..ccc36f4 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,12 @@ "async": "1.5.2", "chai": "3.5.0", "jpath": "0.0.20", - "mocha": "2.4.5", - "npm": "2.7.4", + "mocha": "2.5.3", + "npm": "2.15.6", "sails-mysql": "balderdashy/sails-mysql", "sails-postgresql": "balderdashy/sails-postgresql", - "should": "8.2.1", "waterline-adapter-tests": "~0.12.0" + "should": "9.0.0", }, "scripts": { "test": "make test", From da0fe8c6f303c66743929d6e44386405497579ca Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 15:02:57 -0500 Subject: [PATCH 27/37] bump min wl-adapter-tests version to latest --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ccc36f4..e5c82af 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,8 @@ "npm": "2.15.6", "sails-mysql": "balderdashy/sails-mysql", "sails-postgresql": "balderdashy/sails-postgresql", - "waterline-adapter-tests": "~0.12.0" "should": "9.0.0", + "waterline-adapter-tests": "~0.12.1" }, "scripts": { "test": "make test", From 02e017d89dfd92e754732baf534e54b18d17a952 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 15:07:56 -0500 Subject: [PATCH 28/37] update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75630ac..19f9af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Waterline-Sequel Changelog +### 0.6.4 + +* [ENHANCEMENT] Update any outdated dependencies that may have been causing warnings on install. + +* [BUG] Fixes issued where `[undefined]` was being used to select invalid custom primary keys in certain situations. + +* [BUG] Add a check to revert to `SELECT *` when the select array is empty to prevent the case where the query gets built with `SELEC`. + +* [BUG] Fix case where `attributes` was still being used instead of `definition`. + ### 0.6.3 * [ENHANCEMENT] Added newer versions of Node to the Travis test runner. From 84ca5370884e95cddba5f757c77075ccc72f6a66 Mon Sep 17 00:00:00 2001 From: Cody Stoltman Date: Wed, 8 Jun 2016 15:08:12 -0500 Subject: [PATCH 29/37] 0.6.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e5c82af..c5ecabc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "waterline-sequel", "description": "A helper library for generating SQL queries from the Waterline Query Language.", - "version": "0.6.3", + "version": "0.6.4", "author": "Cody Stoltman ", "url": "http://github.com/balderdashy/waterline-sequel", "keywords": [], From 6c0ff36fc2c97711c1bbed36ec77db8cde442db9 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:30:32 -0500 Subject: [PATCH 30/37] Set adapter devDeps to a published semver range rather than GitHub repos. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c5ecabc..812195b 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "jpath": "0.0.20", "mocha": "2.5.3", "npm": "2.15.6", - "sails-mysql": "balderdashy/sails-mysql", - "sails-postgresql": "balderdashy/sails-postgresql", + "sails-mysql": "^0.11.5", + "sails-postgresql": "^0.11.4", "should": "9.0.0", "waterline-adapter-tests": "~0.12.1" }, From ab6a9a1ff2b1281a528a066e2720a90dbbc3ff93 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:30:51 -0500 Subject: [PATCH 31/37] no tildas --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 812195b..2345d44 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "sails-mysql": "^0.11.5", "sails-postgresql": "^0.11.4", "should": "9.0.0", - "waterline-adapter-tests": "~0.12.1" + "waterline-adapter-tests": "^0.12.1" }, "scripts": { "test": "make test", From 72706b8ed9b25180685dec119de776bb5ebe637d Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:31:42 -0500 Subject: [PATCH 32/37] Bump async (no code needs to migrate) and also bump mocha devDep. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2345d44..6c88b88 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "lodash": "3.10.1" }, "devDependencies": { - "async": "1.5.2", + "async": "2.0.1", "chai": "3.5.0", "jpath": "0.0.20", - "mocha": "2.5.3", + "mocha": "3.0.2", "npm": "2.15.6", "sails-mysql": "^0.11.5", "sails-postgresql": "^0.11.4", From 26b8a899fd7fe26d9bbc98aa7030bce48aa9bb7f Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:36:46 -0500 Subject: [PATCH 33/37] Normalize readme w/ other waterline modules. --- README.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index df6807b..17b856c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,39 @@ -Waterline-Sequel -==================== +# waterline-sequel + +A helper library for generating SQL queries from the Waterline Query Language (see docs on sailsjs.com for more information.) + + +## Bugs   [![NPM version](https://badge.fury.io/js/waterline-sequel.svg)](http://npmjs.com/package/waterline-sequel) + +To report a bug, [click here](http://sailsjs.com/bugs). + +> This is a built-in module in `sails-mysql` and `sails-postgresql`, officially-supported adapters in the Sails framework. + +## Contributing   [![Build Status](https://travis-ci.org/balderdashy/waterline-sequel.svg?branch=master)](https://travis-ci.org/balderdashy/waterline-sequel) + +Please observe the guidelines and conventions laid out in the [Sails project contribution guide](http://sailsjs.com/contribute) when opening issues or submitting pull requests. + +[![NPM package info](https://nodei.co/npm/waterline-sequel.png?downloads=true)](http://npmjs.com/package/waterline-sequel) + + build | integration tests | npm | dependencies | ------|-------------------|-----|---------------| [![Build Status](https://travis-ci.org/balderdashy/waterline-sequel.svg?branch=master)](https://travis-ci.org/balderdashy/waterline-sequel) | [![Circle CI](https://img.shields.io/circleci/project/balderdashy/waterline-sequel/master.svg?style=shield)](https://circleci.com/gh/balderdashy/waterline-sequel/tree/master) | [![npm version](https://badge.fury.io/js/waterline-sequel.svg)](http://badge.fury.io/js/waterline-sequel) | [![Dependency Status](https://david-dm.org/balderdashy/waterline-sequel.svg)](https://david-dm.org/balderdashy/waterline-sequel) -A helper library for generating SQL queries from the Waterline Query Language. -### Running the tests +#### Running the tests Simply run `npm test`. + #### Integration Tests You can read more about waterline-sequel integration tests [here](https://github.com/balderdashy/waterline-sequel/blob/master/test/integration/README.md). To run them, do: + ``` npm run test-integration ``` + + +## License + +> The [Sails framework](http://sailsjs.com) is free and open-source under the [MIT License](http://sailsjs.com/license). + From 54c29766696ea5027876fde56f21d13a2b41b135 Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:38:39 -0500 Subject: [PATCH 34/37] Bring in updated boilerplate. --- .editorconfig | 18 ++++++++ .gitignore | 40 +++++++++++++++++ .jshintrc | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++ .npmignore | 21 +++++++++ .travis.yml | 8 ++-- 5 files changed, 205 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 .jshintrc create mode 100644 .npmignore diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..98a4353 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# ╔═╗╔╦╗╦╔╦╗╔═╗╦═╗┌─┐┌─┐┌┐┌┌─┐┬┌─┐ +# ║╣ ║║║ ║ ║ ║╠╦╝│ │ ││││├┤ ││ ┬ +# o╚═╝═╩╝╩ ╩ ╚═╝╩╚═└─┘└─┘┘└┘└ ┴└─┘ +# +# This file (`.editorconfig`) exists to help maintain consistent formatting +# throughout this package, the Sails framework, and the Node-Machine project. +# +# To review what each of these options mean, see: +# http://editorconfig.org/ +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.gitignore b/.gitignore index 3c3629e..1254d43 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,41 @@ +# ┌─┐┬┌┬┐╦╔═╗╔╗╔╔═╗╦═╗╔═╗ +# │ ┬│ │ ║║ ╦║║║║ ║╠╦╝║╣ +# o└─┘┴ ┴ ╩╚═╝╝╚╝╚═╝╩╚═╚═╝ +# +# This file (`.gitignore`) exists to signify to `git` that certain files +# and/or directories should be ignored for the purposes of version control. +# +# This is primarily useful for excluding temporary files of all sorts; stuff +# generated by IDEs, build scripts, automated tests, package managers, or even +# end-users (e.g. file uploads). `.gitignore` files like this also do a nice job +# at keeping sensitive credentials and personal data out of version control systems. +# + +############################ +# npm +############################ node_modules +npm-debug.log + + +############################ +# tmp, editor & OS files +############################ +.tmp +*.swo +*.swp +*.swn +*.swm +.DS_STORE +*# +*~ +.idea +nbproject + + +############################ +# Tests +############################ + +# n/a + diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..059786a --- /dev/null +++ b/.jshintrc @@ -0,0 +1,122 @@ +{ + // ┬┌─┐╦ ╦╦╔╗╔╔╦╗┬─┐┌─┐ + // │└─┐╠═╣║║║║ ║ ├┬┘│ + // o└┘└─┘╩ ╩╩╝╚╝ ╩ ┴└─└─┘ + // + // This file (`.jshintrc`) exists to help with consistency of code + // throughout this package, and throughout Sails and the Node-Machine project. + // + // To review what each of these options mean, see: + // http://jshint.com/docs/options + // + // (or: https://github.com/jshint/jshint/blob/master/examples/.jshintrc) + + + + ////////////////////////////////////////////////////////////////////// + // NOT SUPPORTED IN SOME JSHINT VERSIONS SO LEAVING COMMENTED OUT: + ////////////////////////////////////////////////////////////////////// + // Prevent overwriting prototypes of native classes like `Array`. + // (doing this is _never_ ok in any of our packages that are intended + // to be used as dependencies of other developers' modules and apps) + // "freeze": true, + ////////////////////////////////////////////////////////////////////// + + + ////////////////////////////////////////////////////////////////////// + // EVERYTHING ELSE: + ////////////////////////////////////////////////////////////////////// + + // Allow the use of `eval` and `new Function()` + // (we sometimes actually need to use these things) + "evil": true, + + // Tolerate funny-looking dashes in RegExp literals. + // (see https://github.com/jshint/jshint/issues/159#issue-903547) + "regexdash": true, + + // The potential runtime "Environments" (as defined by jshint) + // that the _style_ of code written in this package should be + // compatible with (not the code itself, of course). + "browser": true, + "node": true, + "wsh": true, + + // Tolerate the use `[]` notation when dot notation would be possible. + // (this is sometimes preferable for readability) + "sub": true, + + // Do NOT suppress warnings about mixed tabs and spaces + // (two spaces always, please; see `.editorconfig`) + "smarttabs": false, + + // Suppress warnings about trailing whitespace + // (this is already enforced by the .editorconfig, so no need to warn as well) + "trailing": false, + + // Suppress warnings about the use of expressions where fn calls or assignments + // are expected, and about using assignments where conditionals are expected. + // (while generally a good idea, without this setting, JSHint needlessly lights up warnings + // in existing, working code that really shouldn't be tampered with. Pandora's box and all.) + "expr": true, + "boss": true, + + // Do NOT suppress warnings about using functions inside loops + // (in the general case, we should be using iteratee functions with `_.each()` + // or `Array.prototype.forEach()` instead of `for` or `while` statements + // anyway. This warning serves as a helpful reminder.) + "loopfunc": false, + + // Suppress warnings about "weird constructions" + // i.e. allow code like: + // ``` + // (new (function OneTimeUsePrototype () { } )) + // ``` + // + // (sometimes order of operations in JavaScript can be scary. There is + // nothing wrong with using an extra set of parantheses when the mood + // strikes or you get "that special feeling".) + "supernew": true, + + // Do NOT allow backwards, node-dependency-style commas. + // (while this code style choice was used by the project in the past, + // we have since standardized these practices to make code easier to + // read, albeit a bit less exciting) + "laxcomma": false, + + // Strictly enforce the consistent use of single quotes. + // (this is a convention that was established primarily to make it easier + // to grep [or FIND+REPLACE in Sublime] particular string literals in + // JavaScript [.js] files. Note that JSON [.json] files are, of course, + // still written exclusively using double quotes around key names and + // around string literals.) + "quotmark": "single", + + // Do NOT suppress warnings about the use of `==null` comparisons. + // (please be explicit-- use Lodash or `require('util')` and call + // either `.isNull()` or `.isUndefined()`) + "eqnull": false, + + // Strictly enforce the use of curly braces with `if`, `else`, and `switch` + // as well as, much less commonly, `for` and `while` statements. + // (this is just so that all of our code is consistent, and to avoid bugs) + "curly": true, + + // Strictly enforce the use of `===` and `!==`. + // (this is always a good idea. Check out "Truth, Equality, and JavaScript" + // by Angus Croll [the author of "If Hemmingway Wrote JavaScript"] for more + // explanation as to why.) + "eqeqeq": true, + + // Allow initializing variables to `undefined`. + // For more information, see: + // • https://jslinterrors.com/it-is-not-necessary-to-initialize-a-to-undefined + // • https://github.com/jshint/jshint/issues/1484 + // + // (it is often very helpful to explicitly clarify the initial value of + // a local variable-- especially for folks new to more advanced JavaScript + // and who might not recognize the subtle, yet critically important differences between our seemingly + // between `null` and `undefined`, and the impact on `typeof` checks) + "-W080": true + +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..ff57020 --- /dev/null +++ b/.npmignore @@ -0,0 +1,21 @@ +*# +node_modules +ssl +.DS_STORE +*.swo +*.swp +*.swn +*.swm +*~ +.idea +nbproject +.git +.gitignore +.tmp +.jshintrc +.editorconfig +CONTRIBUTING.md +*.md +**/*.md +test +.github diff --git a/.travis.yml b/.travis.yml index add628c..5d5d571 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js node_js: - - "5.0" - - "4.0" - - "0.12" - "0.10" -sudo: false + - "0.12" + - "4" + - "5" + - "node" From 23c39fb64f5596334e185fd6e61727d804bb397c Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:40:03 -0500 Subject: [PATCH 35/37] Shrinkwrap. --- npm-shrinkwrap.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 npm-shrinkwrap.json diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json new file mode 100644 index 0000000..4c5cc7f --- /dev/null +++ b/npm-shrinkwrap.json @@ -0,0 +1,11 @@ +{ + "name": "waterline-sequel", + "version": "0.6.4", + "dependencies": { + "lodash": { + "version": "3.10.1", + "from": "lodash@3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + } + } +} From 89fb0b243556fce7b393c02ce8581c04c94992ad Mon Sep 17 00:00:00 2001 From: Mike McNeil Date: Sun, 9 Oct 2016 16:40:48 -0500 Subject: [PATCH 36/37] Actually, shrinkwrap is unnecessary since lodash doesn't have deps. This is similar to why it's omitted in waterline-criteria. --- npm-shrinkwrap.json | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 npm-shrinkwrap.json diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json deleted file mode 100644 index 4c5cc7f..0000000 --- a/npm-shrinkwrap.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "waterline-sequel", - "version": "0.6.4", - "dependencies": { - "lodash": { - "version": "3.10.1", - "from": "lodash@3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" - } - } -} From d8f1bf9b983f1af0cb244db782107093f48ebacb Mon Sep 17 00:00:00 2001 From: Rachael Shaw Date: Tue, 3 Jan 2017 16:02:07 -0600 Subject: [PATCH 37/37] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17b856c..67f2aa6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ To report a bug, [click here](http://sailsjs.com/bugs). ## Contributing   [![Build Status](https://travis-ci.org/balderdashy/waterline-sequel.svg?branch=master)](https://travis-ci.org/balderdashy/waterline-sequel) -Please observe the guidelines and conventions laid out in the [Sails project contribution guide](http://sailsjs.com/contribute) when opening issues or submitting pull requests. +Please observe the guidelines and conventions laid out in the [Sails project contribution guide](http://sailsjs.com/documentation/contributing) when opening issues or submitting pull requests. [![NPM package info](https://nodei.co/npm/waterline-sequel.png?downloads=true)](http://npmjs.com/package/waterline-sequel)