Browse Source

Add updateBatch method to query builder

Timothy J. Warren 10 months ago
parent
commit
4064a99419

+ 36
- 32
.eslintrc View File

@@ -1,39 +1,43 @@
1 1
 {
2 2
 	"env": {
3
-		"node": true,
4
-		"es6": true
3
+		"commonjs": true,
4
+		"es6": true,
5
+		"jest": true,
6
+		"node": true
5 7
 	},
8
+	"extends": ["eslint:recommended", "happiness"],
6 9
 	"rules": {
7
-		"arrow-parens": [2, "as-needed"],
8
-		"no-console": [1],
9
-		"no-constant-condition": [1],
10
-		"no-extra-semi": [1],
11
-		"no-func-assign": [1],
12
-		"no-obj-calls": [2],
13
-		"no-unexpected-multiline" : [2],
14
-		"no-unneeded-ternary": [2],
15
-		"radix": [2],
16
-		"no-with": [2],
17
-		"no-eval": [2],
18
-		"no-unreachable": [1],
19
-		"no-irregular-whitespace": [1],
20
-		"no-new-wrappers": [2],
21
-		"no-new-func": [2],
22
-		"curly" : [2, "multi-line"],
23
-		"no-implied-eval": [2],
24
-		"no-invalid-this": [2],
25
-		"constructor-super": [2],
26
-		"no-dupe-args": [2],
27
-		"no-dupe-keys": [2],
28
-		"no-dupe-class-members": [2],
29
-		"no-this-before-super": [2],
30
-		"prefer-arrow-callback": [1],
31
-		"no-var": [2],
32
-		"valid-jsdoc": [1],
33
-		"strict": [2, "global"],
34
-		"callback-return": [1],
35
-		"object-shorthand": [1, "methods"],
36
-		"prefer-template": [1]
10
+		"arrow-parens": ["error", "as-needed"],
11
+		"callback-return": ["warn"],
12
+		"constructor-super": ["error"],
13
+		"curly" : ["error", "multi-line"],
14
+		"no-case-declarations": "off",
15
+		"no-console": ["warn"],
16
+		"no-constant-condition": ["warn"],
17
+		"no-dupe-args": ["error"],
18
+		"no-dupe-class-members": ["error"],
19
+		"no-dupe-keys": ["error"],
20
+		"no-eval": ["error"],
21
+		"no-extra-semi": ["warn"],
22
+		"no-func-assign": ["warn"],
23
+		"no-implied-eval": ["error"],
24
+		"no-invalid-this": ["error"],
25
+		"no-irregular-whitespace": ["warn"],
26
+		"no-new-func": ["error"],
27
+		"no-new-wrappers": ["error"],
28
+		"no-obj-calls": ["error"],
29
+		"no-this-before-super": ["error"],
30
+		"no-unexpected-multiline" : ["error"],
31
+		"no-unneeded-ternary": ["error"],
32
+		"no-unreachable": ["warn"],
33
+		"no-var": ["error"],
34
+		"no-with": ["error"],
35
+		"object-shorthand": ["warn", "methods"],
36
+		"prefer-arrow-callback": ["warn"],
37
+		"prefer-template": ["warn"],
38
+		"radix": ["error"],
39
+		"strict": ["error", "global"],
40
+		"valid-jsdoc": ["warn"]
37 41
 	},
38 42
 	"parser": "babel-eslint"
39 43
 }

+ 81
- 15
lib/Driver.js View File

@@ -1,3 +1,4 @@
1
+const array = require('locutus/php/array');
1 2
 const Helpers = require('./Helpers');
2 3
 
3 4
 /**
@@ -64,36 +65,38 @@ const Driver = {
64 65
 	 * @return {String|Array} - Quoted identifier(s)
65 66
 	 */
66 67
 	quoteIdentifiers (str) {
67
-		let hiers, raw;
68
-		let pattern = new RegExp(
68
+		const pattern = new RegExp(
69 69
 			`${Driver.identifierStartChar}(` +
70 70
 				'([a-zA-Z0-9_]+)' + '(((.*?)))' +
71 71
 				`)${Driver.identifierEndChar}`, 'ig');
72 72
 
73
-		// Recurse for arrays of identifiiers
73
+		// Recurse for arrays of identifiers
74 74
 		if (Array.isArray(str)) {
75 75
 			return str.map(Driver.quoteIdentifiers);
76 76
 		}
77 77
 
78
+		// cast to string so that you don't have undefined method errors with junk data
79
+		str = String(str);
80
+
78 81
 		// Handle commas
79 82
 		if (str.includes(',')) {
80
-			let parts = str.split(',').map(Helpers.stringTrim);
83
+			const parts = str.split(',').map(Helpers.stringTrim);
81 84
 			str = parts.map(Driver.quoteIdentifiers).join(',');
82 85
 		}
83 86
 
84 87
 		// Split identifiers by period
85
-		hiers = str.split('.').map(Driver._quote);
86
-		raw = hiers.join('.');
88
+		const hierarchies = str.split('.').map(Driver._quote);
89
+		let raw = hierarchies.join('.');
87 90
 
88 91
 		// Fix functions
89 92
 		if (raw.includes('(') && raw.includes(')')) {
90
-			let funcs = pattern.exec(raw);
93
+			const functionCalls = pattern.exec(raw);
91 94
 
92 95
 			// Unquote the function
93
-			raw = raw.replace(funcs[0], funcs[1]);
96
+			raw = raw.replace(functionCalls[0], functionCalls[1]);
94 97
 
95 98
 			// Quote the identifiers inside of the parens
96
-			let inParens = funcs[3].substring(1, funcs[3].length - 1);
99
+			const inParens = functionCalls[3].substring(1, functionCalls[3].length - 1);
97 100
 			raw = raw.replace(inParens, Driver.quoteIdentifiers(inParens));
98 101
 		}
99 102
 
@@ -126,7 +129,7 @@ const Driver = {
126 129
 	 * @return {String} - Query and data to insert
127 130
 	 */
128 131
 	insertBatch (table, data) {
129
-		const vals = [];
132
+		const values = [];
130 133
 		const fields = Object.keys(data[0]);
131 134
 		let sql = '';
132 135
 
@@ -134,7 +137,7 @@ const Driver = {
134 137
 		// be parameterized
135 138
 		data.forEach(obj => {
136 139
 			Object.keys(obj).forEach(key => {
137
-				vals.push(obj[key]);
140
+				values.push(obj[key]);
138 141
 			});
139 142
 		});
140 143
 
@@ -145,16 +148,79 @@ const Driver = {
145 148
 		sql += `INSERT INTO ${table} (${Driver.quoteIdentifiers(fields).join(',')}) VALUES `;
146 149
 
147 150
 		// Create placeholder groups
148
-		let params = Array(fields.length).fill('?');
149
-		let paramString = `(${params.join(',')})`;
150
-		let paramList = Array(data.length).fill(paramString);
151
+		const params = Array(fields.length).fill('?');
152
+		const paramString = `(${params.join(',')})`;
153
+		const paramList = Array(data.length).fill(paramString);
151 154
 
152 155
 		sql += paramList.join(',');
153 156
 
154 157
 		return {
155 158
 			sql: sql,
156
-			values: vals
159
+			values: values
157 160
 		};
161
+	},
162
+
163
+	/**
164
+	 * Creates a batch update sql statement
165
+	 *
166
+	 * @private
167
+	 * @param {String} table
168
+	 * @param {Array<Object>} data
169
+	 * @param {String} updateKey
170
+	 * @return {Array<String,Object,Number>} array
171
+	 */
172
+	updateBatch (table, data, updateKey) {
173
+		let affectedRows = 0;
174
+		let insertData = [];
175
+		const fieldLines = [];
176
+
177
+		let sql = `UPDATE ${Driver.quoteTable(table)} SET `;
178
+
179
+		// get the keys of the current set of data, except the one used to
180
+		// set the update condition
181
+		const fields = data.reduce((previous, current) => {
182
+			affectedRows++;
183
+			const keys = Object.keys(current).filter(key => {
184
+				return key !== updateKey && !previous.includes(key);
185
+			});
186
+			return previous.concat(keys);
187
+		}, []);
188
+
189
+		// Create the CASE blocks for each data set
190
+		fields.forEach(field => {
191
+			let line = `${Driver.quoteIdentifiers(field)} = CASE\n`;
192
+			const cases = [];
193
+			data.forEach(currentCase => {
194
+				insertData.push(currentCase[updateKey]);
195
+				insertData.push(currentCase[field]);
196
+
197
+				const newCase = `WHEN ${Driver.quoteIdentifiers(updateKey)} =? THEN ? `;
198
+				cases.push(newCase);
199
+			});
200
+
201
+			line += `${cases.join('\n')}\n`;
202
+			line += `ELSE ${Driver.quoteIdentifiers(field)} END`;
203
+
204
+			fieldLines.push(line);
205
+		});
206
+
207
+		sql += `${fieldLines.join(',\n')}\n`;
208
+
209
+		const whereValues = [];
210
+		data.forEach(entry => {
211
+			const insertValue = entry[updateKey];
212
+			whereValues.push(insertValue);
213
+			insertData.push(insertValue);
214
+		});
215
+
216
+		// Create the placeholders for the WHERE IN clause
217
+		const placeholders = Array(whereValues.length);
218
+		placeholders.fill('?');
219
+
220
+		sql += `WHERE ${Driver.quoteIdentifiers(updateKey)} IN `;
221
+		sql += `( ${placeholders.join(',')} )`;
222
+
223
+		return [sql, insertData, affectedRows];
158 224
 	}
159 225
 };
160 226
 

+ 7
- 8
lib/Helpers.js View File

@@ -42,7 +42,7 @@ class Helpers {
42 42
 	 * @return {String} - Type of the object
43 43
 	 */
44 44
 	static type (o) {
45
-		let type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
45
+		const type = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
46 46
 
47 47
 		// handle NaN and Infinity
48 48
 		if (type === 'number') {
@@ -62,11 +62,10 @@ class Helpers {
62 62
 	 * Determine whether an object is scalar
63 63
 	 *
64 64
 	 * @param {mixed} obj - Object to test
65
-	 * @return {bool} - Is object scalar
65
+	 * @return {boolean} - Is object scalar
66 66
 	 */
67 67
 	static isScalar (obj) {
68
-		let scalar = ['string', 'number', 'boolean'];
69
-		return scalar.indexOf(Helpers.type(obj)) !== -1;
68
+		return ['string', 'number', 'boolean'].includes(Helpers.type(obj));
70 69
 	}
71 70
 
72 71
 	/**
@@ -77,7 +76,7 @@ class Helpers {
77 76
 	 * @return {Array} - The new array of plucked values
78 77
 	 */
79 78
 	static arrayPluck (arr, key) {
80
-		let output = [];
79
+		const output = [];
81 80
 
82 81
 		// Empty case
83 82
 		if (arr.length === 0) {
@@ -119,20 +118,20 @@ class Helpers {
119 118
 	}
120 119
 
121 120
 	/**
122
-	 * Make the first letter of the string uppercase
121
+	 * Make the first constter of the string uppercase
123 122
 	 *
124 123
 	 * @param {String} str - The string to modify
125 124
 	 * @return {String} - The modified string
126 125
 	 */
127 126
 	static upperCaseFirst (str) {
128 127
 		str += '';
129
-		let first = str.charAt(0).toUpperCase();
128
+		const first = str.charAt(0).toUpperCase();
130 129
 		return first + str.substr(1);
131 130
 	}
132 131
 }
133 132
 
134 133
 // Define an 'is' method for each type
135
-let types = [
134
+const types = [
136 135
 	'Null',
137 136
 	'Undefined',
138 137
 	'Object',

+ 5
- 6
lib/NodeQuery.js View File

@@ -50,17 +50,16 @@ class NodeQuery {
50 50
 		this.instance = null;
51 51
 
52 52
 		if (config !== undefined) {
53
-			let drivername = dbDriverMap.get(config.driver);
53
+			const driverName = dbDriverMap.get(config.driver);
54 54
 
55
-			if (!drivername) {
55
+			if (!driverName) {
56 56
 				throw new Error(`Selected driver (${config.driver}) does not exist!`);
57 57
 			}
58 58
 
59
-			const driver = require(`./drivers/${drivername}`);
60
-			const Adapter = require(`./adapters/${drivername}`);
59
+			const driver = require(`./drivers/${driverName}`);
60
+			const Adapter = require(`./adapters/${driverName}`);
61 61
 
62
-			let adapter = Adapter(config);
63
-			this.instance = new QueryBuilder(driver, adapter);
62
+			this.instance = new QueryBuilder(driver, Adapter(config));
64 63
 		}
65 64
 	}
66 65
 

+ 24
- 10
lib/QueryBuilder.js View File

@@ -107,7 +107,7 @@ class QueryBuilder extends QueryBuilderBase {
107 107
 			}
108 108
 		});
109 109
 
110
-		let safeArray = this.driver.quoteIdentifiers(fields);
110
+		const safeArray = this.driver.quoteIdentifiers(fields);
111 111
 
112 112
 		// Join the strings back together
113 113
 		safeArray.forEach((field, index) => {
@@ -378,8 +378,8 @@ class QueryBuilder extends QueryBuilderBase {
378 378
 		table = table.join(' ');
379 379
 
380 380
 		// Parse out the join condition
381
-		let parsedCondition = this.parser.compileJoin(cond);
382
-		let condition = `${table} ON ${parsedCondition}`;
381
+		const parsedCondition = this.parser.compileJoin(cond);
382
+		const condition = `${table} ON ${parsedCondition}`;
383 383
 
384 384
 		// Append the join condition to the query map
385 385
 		this._appendMap(`\n${type.toUpperCase()} JOIN `, condition, 'join');
@@ -395,7 +395,7 @@ class QueryBuilder extends QueryBuilderBase {
395 395
 	 */
396 396
 	groupBy (field) {
397 397
 		if (!Helpers.isScalar(field)) {
398
-			let newGroupArray = field.map(this.driver.quoteIdentifiers);
398
+			const newGroupArray = field.map(this.driver.quoteIdentifiers);
399 399
 			this.state.groupArray = this.state.groupArray.concat(newGroupArray);
400 400
 		} else {
401 401
 			this.state.groupArray.push(this.driver.quoteIdentifiers(field));
@@ -421,7 +421,7 @@ class QueryBuilder extends QueryBuilderBase {
421 421
 
422 422
 		this.state.orderArray[field] = type;
423 423
 
424
-		let orderClauses = [];
424
+		const orderClauses = [];
425 425
 
426 426
 		// Flatten key/val pairs into an array of space-separated pairs
427 427
 		Object.keys(this.state.orderArray).forEach(key => {
@@ -454,7 +454,7 @@ class QueryBuilder extends QueryBuilderBase {
454 454
 	 * @return {QueryBuilder} - The Query Builder object, for chaining
455 455
 	 */
456 456
 	groupStart () {
457
-		let conj = (this.state.queryMap.length < 1) ? ' WHERE ' : ' AND ';
457
+		const conj = (this.state.queryMap.length < 1) ? ' WHERE ' : ' AND ';
458 458
 		this._appendMap(conj, '(', 'groupStart');
459 459
 
460 460
 		return this;
@@ -549,7 +549,7 @@ class QueryBuilder extends QueryBuilderBase {
549 549
 	 * @return {Promise<Result>} - Promise containing the result of the query
550 550
 	 */
551 551
 	insertBatch (table, data) {
552
-		let batch = this.driver.insertBatch(table, data);
552
+		const batch = this.driver.insertBatch(table, data);
553 553
 
554 554
 		// Run the query
555 555
 		return this.query(batch.sql, batch.values);
@@ -571,6 +571,20 @@ class QueryBuilder extends QueryBuilderBase {
571 571
 		return this._run('update', this.driver.quoteTable(table));
572 572
 	}
573 573
 
574
+	/**
575
+	 * Creates a batch update sql statement
576
+	 *
577
+	 * @param {String} table - The table to update
578
+	 * @param {Object} data - Batch insert data
579
+	 * @param {String} updateKey - The field in the table to compare against for updating
580
+	 * @return {Number} Number of rows updated
581
+	 */
582
+	updateBatch (table, data, updateKey) {
583
+		const [sql, insertData, affectedRows] = this.driver.updateBatch(table, data, updateKey);
584
+		this._run('', table, sql, insertData);
585
+		return affectedRows;
586
+	}
587
+
574 588
 	/**
575 589
 	 * Run the generated delete query
576 590
 	 *
@@ -613,7 +627,7 @@ class QueryBuilder extends QueryBuilderBase {
613 627
 	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
614 628
 	 * @return {String} - The compiled sql statement
615 629
 	 */
616
-	getCompiledInsert (table, reset) {
630
+	getCompiledInsert (table, reset = true) {
617 631
 		return this._getCompile('insert', this.driver.quoteTable(table), reset);
618 632
 	}
619 633
 
@@ -624,7 +638,7 @@ class QueryBuilder extends QueryBuilderBase {
624 638
 	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
625 639
 	 * @return {String} - The compiled sql statement
626 640
 	 */
627
-	getCompiledUpdate (table, reset) {
641
+	getCompiledUpdate (table, reset = true) {
628 642
 		return this._getCompile('update', this.driver.quoteTable(table), reset);
629 643
 	}
630 644
 
@@ -635,7 +649,7 @@ class QueryBuilder extends QueryBuilderBase {
635 649
 	 * @param {Boolean} [reset=true] - Whether to reset the query builder so another query can be built
636 650
 	 * @return {String} - The compiled sql statement
637 651
 	 */
638
-	getCompiledDelete (table, reset) {
652
+	getCompiledDelete (table, reset = true) {
639 653
 		return this._getCompile('delete', this.driver.quoteTable(table), reset);
640 654
 	}
641 655
 }

+ 76
- 76
lib/QueryBuilderBase.js View File

@@ -16,74 +16,6 @@ class QueryBuilderBase {
16 16
 		this.state = new State();
17 17
 	}
18 18
 
19
-	/**
20
-	 * Complete the sql building based on the type provided
21
-	 *
22
-	 * @private
23
-	 * @param {String} type - Type of SQL query
24
-	 * @param {String} table - The table to run the query on
25
-	 * @return {String} - The compiled sql
26
-	 */
27
-	_compile (type, table) {
28
-		// Put together the basic query
29
-		let sql = this._compileType(type, table);
30
-
31
-		// Set each subClause
32
-		['queryMap', 'groupString', 'orderString', 'havingMap'].forEach(clause => {
33
-			let param = this.state[clause];
34
-
35
-			if (!Helpers.isScalar(param)) {
36
-				Object.keys(param).forEach(part => {
37
-					sql += param[part].conjunction + param[part].string;
38
-				});
39
-			} else {
40
-				sql += param;
41
-			}
42
-		});
43
-
44
-		// Append the limit, if it exists
45
-		if (Helpers.isNumber(this.state.limit)) {
46
-			sql = this.driver.limit(sql, this.state.limit, this.state.offset);
47
-		}
48
-
49
-		return sql;
50
-	}
51
-
52
-	_compileType (type, table) {
53
-		let sql = '';
54
-
55
-		switch (type) {
56
-			case 'insert':
57
-				let params = Array(this.state.setArrayKeys.length).fill('?');
58
-
59
-				sql = `INSERT INTO ${table} (`;
60
-				sql += this.state.setArrayKeys.join(',');
61
-				sql += `) VALUES (${params.join(',')})`;
62
-				break;
63
-
64
-			case 'update':
65
-				sql = `UPDATE ${table} SET ${this.state.setString}`;
66
-				break;
67
-
68
-			case 'delete':
69
-				sql = `DELETE FROM ${table}`;
70
-				break;
71
-
72
-			default:
73
-				sql = `SELECT * FROM ${this.state.fromString}`;
74
-
75
-				// Set the select string
76
-				if (this.state.selectString.length > 0) {
77
-					// Replace the star with the selected fields
78
-					sql = sql.replace('*', this.state.selectString);
79
-				}
80
-
81
-				break;
82
-		}
83
-
84
-		return sql;
85
-	}
86
-
87 19
 	_like (field, val, pos, like, conj) {
88 20
 		field = this.driver.quoteIdentifiers(field);
89 21
 
@@ -147,7 +79,7 @@ class QueryBuilderBase {
147 79
 		Object.keys(obj).forEach(k => {
148 80
 			// If a single value for the return
149 81
 			if (['key', 'value'].indexOf(valType) !== -1) {
150
-				let pushVal = (valType === 'key') ? k : obj[k];
82
+				const pushVal = (valType === 'key') ? k : obj[k];
151 83
 				this.state[letName].push(pushVal);
152 84
 			} else {
153 85
 				this.state[letName][k] = obj[k];
@@ -166,8 +98,8 @@ class QueryBuilderBase {
166 98
 	}
167 99
 
168 100
 	_fixConjunction (conj) {
169
-		let lastItem = this.state.queryMap[this.state.queryMap.length - 1];
170
-		let conjunctionList = Helpers.arrayPluck(this.state.queryMap, 'conjunction');
101
+		const lastItem = this.state.queryMap[this.state.queryMap.length - 1];
102
+		const conjunctionList = Helpers.arrayPluck(this.state.queryMap, 'conjunction');
171 103
 
172 104
 		if (this.state.queryMap.length === 0 || (!Helpers.regexInArray(conjunctionList, /^ ?WHERE/i))) {
173 105
 			conj = ' WHERE ';
@@ -189,7 +121,7 @@ class QueryBuilderBase {
189 121
 		this.state = this.parser.parseWhere(this.driver, this.state);
190 122
 
191 123
 		this.state.whereMap.forEach(clause => {
192
-			let conj = this._fixConjunction(defaultConj);
124
+			const conj = this._fixConjunction(defaultConj);
193 125
 			this._appendMap(conj, clause, 'where');
194 126
 		});
195 127
 
@@ -198,7 +130,7 @@ class QueryBuilderBase {
198 130
 
199 131
 	_whereNull (field, stmt, conj) {
200 132
 		field = this.driver.quoteIdentifiers(field);
201
-		let item = `${field} ${stmt}`;
133
+		const item = `${field} ${stmt}`;
202 134
 
203 135
 		this._appendMap(this._fixConjunction(conj), item, 'whereNull');
204 136
 	}
@@ -225,7 +157,7 @@ class QueryBuilderBase {
225 157
 
226 158
 	_whereIn (key, val, inClause, conj) {
227 159
 		key = this.driver.quoteIdentifiers(key);
228
-		let params = Array(val.length);
160
+		const params = Array(val.length);
229 161
 		params.fill('?');
230 162
 
231 163
 		val.forEach(value => {
@@ -233,7 +165,7 @@ class QueryBuilderBase {
233 165
 		});
234 166
 
235 167
 		conj = (this.state.queryMap.length > 0) ? ` ${conj} ` : ' WHERE ';
236
-		let str = `${key} ${inClause} (${params.join(',')}) `;
168
+		const str = `${key} ${inClause} (${params.join(',')}) `;
237 169
 
238 170
 		this._appendMap(conj, str, 'whereIn');
239 171
 	}
@@ -257,7 +189,7 @@ class QueryBuilderBase {
257 189
 	_getCompile (type, table, reset) {
258 190
 		reset = reset || false;
259 191
 
260
-		let sql = this._compile(type, table);
192
+		const sql = this._compile(type, table);
261 193
 
262 194
 		if (reset) {
263 195
 			this._resetState();
@@ -266,6 +198,74 @@ class QueryBuilderBase {
266 198
 		return sql;
267 199
 	}
268 200
 
201
+	/**
202
+	 * Complete the sql building based on the type provided
203
+	 *
204
+	 * @private
205
+	 * @param {String} type - Type of SQL query
206
+	 * @param {String} table - The table to run the query on
207
+	 * @return {String} - The compiled sql
208
+	 */
209
+	_compile (type, table) {
210
+		// Put together the basic query
211
+		let sql = this._compileType(type, table);
212
+
213
+		// Set each subClause
214
+		['queryMap', 'groupString', 'orderString', 'havingMap'].forEach(clause => {
215
+			const param = this.state[clause];
216
+
217
+			if (!Helpers.isScalar(param)) {
218
+				Object.keys(param).forEach(part => {
219
+					sql += param[part].conjunction + param[part].string;
220
+				});
221
+			} else {
222
+				sql += param;
223
+			}
224
+		});
225
+
226
+		// Append the limit, if it exists
227
+		if (Helpers.isNumber(this.state.limit)) {
228
+			sql = this.driver.limit(sql, this.state.limit, this.state.offset);
229
+		}
230
+
231
+		return sql;
232
+	}
233
+
234
+	_compileType (type, table) {
235
+		let sql = '';
236
+
237
+		switch (type) {
238
+			case 'insert':
239
+				const params = Array(this.state.setArrayKeys.length).fill('?');
240
+
241
+				sql = `INSERT INTO ${table} (`;
242
+				sql += this.state.setArrayKeys.join(',');
243
+				sql += `) VALUES (${params.join(',')})`;
244
+				break;
245
+
246
+			case 'update':
247
+				sql = `UPDATE ${table} SET ${this.state.setString}`;
248
+				break;
249
+
250
+			case 'delete':
251
+				sql = `DELETE FROM ${table}`;
252
+				break;
253
+
254
+			default:
255
+				sql = `SELECT * FROM ${this.state.fromString}`;
256
+
257
+				// Set the select string
258
+				if (this.state.selectString.length > 0) {
259
+					// Replace the star with the selected fields
260
+					sql = sql.replace('*', this.state.selectString);
261
+				}
262
+
263
+				break;
264
+		}
265
+
266
+		return sql;
267
+	}
268
+
269 269
 	_resetState () {
270 270
 		this.state = new State();
271 271
 	}

+ 18
- 18
lib/QueryParser.js View File

@@ -54,7 +54,7 @@ class QueryParser {
54 54
 	 * @return {Array|null} - Filtered set of possible matches
55 55
 	 */
56 56
 	filterMatches (array) {
57
-		let output = [];
57
+		const output = [];
58 58
 
59 59
 		// Return non-array matches
60 60
 		if (Helpers.isNull(array)) {
@@ -85,8 +85,8 @@ class QueryParser {
85 85
 	 * @return {Object} - Join condition components
86 86
 	 */
87 87
 	parseJoin (sql) {
88
-		let matches = {};
89
-		let output = {
88
+		const matches = {};
89
+		const output = {
90 90
 			functions: [],
91 91
 			identifiers: [],
92 92
 			operators: [],
@@ -117,7 +117,7 @@ class QueryParser {
117 117
 	 * @return {String} - The parsed/escaped join condition
118 118
 	 */
119 119
 	compileJoin (condition) {
120
-		let parts = this.parseJoin(condition);
120
+		const parts = this.parseJoin(condition);
121 121
 
122 122
 		// Quote the identifiers
123 123
 		parts.combined.forEach((part, i) => {
@@ -137,11 +137,11 @@ class QueryParser {
137 137
 	 * @return {String} - The parsed/escaped where condition
138 138
 	 */
139 139
 	parseWhere (driver, state) {
140
-		let whereMap = state.whereMap;
140
+		const whereMap = state.whereMap;
141 141
 		let	whereValues = state.rawWhereValues;
142 142
 
143
-		let outputMap = [];
144
-		let outputValues = [];
143
+		const outputMap = [];
144
+		const outputValues = [];
145 145
 
146 146
 		Object.keys(whereMap).forEach(key => {
147 147
 			// Combine fields, operators, functions and values into a full clause
@@ -158,16 +158,16 @@ class QueryParser {
158 158
 			}
159 159
 
160 160
 			// Separate the clause into separate pieces
161
-			let parts = this.parseJoin(fullClause);
161
+			const parts = this.parseJoin(fullClause);
162 162
 
163 163
 			// Filter explicit literals from lists of matches
164 164
 			if (whereValues.indexOf(whereMap[key]) !== -1) {
165
-				let value = whereMap[key];
166
-				let identIndex = parts.identifiers.indexOf(value);
167
-				let litIndex = (Helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1;
168
-				let combIndex = parts.combined.indexOf(value);
169
-				let funcIndex = (Helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1;
170
-				let inOutputArray = outputValues.indexOf(value) !== -1;
165
+				const value = whereMap[key];
166
+				const identIndex = parts.identifiers.indexOf(value);
167
+				const litIndex = (Helpers.isArray(parts.literals)) ? parts.literals.indexOf(value) : -1;
168
+				const combIndex = parts.combined.indexOf(value);
169
+				const funcIndex = (Helpers.isArray(parts.functions)) ? parts.functions.indexOf(value) : -1;
170
+				let inOutputArray = outputValues.includes(value);
171 171
 
172 172
 				// Remove the identifier in question,
173 173
 				// and add to the output values array
@@ -201,8 +201,8 @@ class QueryParser {
201 201
 
202 202
 			// Filter false positive identifiers
203 203
 			parts.identifiers = parts.identifiers.filter(item => {
204
-				let isInCombinedMatches = parts.combined.indexOf(item) !== -1;
205
-				let isNotInBlackList = this.identifierBlacklist.indexOf(item.toLowerCase()) === -1;
204
+				const isInCombinedMatches = parts.combined.indexOf(item) !== -1;
205
+				const isNotInBlackList = this.identifierBlacklist.indexOf(item.toLowerCase()) === -1;
206 206
 
207 207
 				return isInCombinedMatches && isNotInBlackList;
208 208
 			}, this);
@@ -210,7 +210,7 @@ class QueryParser {
210 210
 			// Quote identifiers
211 211
 			if (Helpers.isArray(parts.identifiers)) {
212 212
 				parts.identifiers.forEach(ident => {
213
-					let index = parts.combined.indexOf(ident);
213
+					const index = parts.combined.indexOf(ident);
214 214
 					if (index !== -1) {
215 215
 						parts.combined[index] = driver.quoteIdentifiers(ident);
216 216
 					}
@@ -224,7 +224,7 @@ class QueryParser {
224 224
 			// a where condition,
225 225
 			if (Helpers.isArray(parts.literals)) {
226 226
 				parts.literals.forEach(lit => {
227
-					let litIndex = parts.combined.indexOf(lit);
227
+					const litIndex = parts.combined.indexOf(lit);
228 228
 
229 229
 					if (litIndex !== -1) {
230 230
 						parts.combined[litIndex] = '?';

+ 0
- 2
lib/adapters/MSSQLServer/index.js View File

@@ -1,5 +1,3 @@
1
-'use strict';
2
-
3 1
 module.exports = config => {
4 2
 
5 3
 };

+ 1
- 1
lib/adapters/Mysql/mysql2.js View File

@@ -36,7 +36,7 @@ class Mysql extends Adapter {
36 36
 	 * Run the sql query as a prepared statement
37 37
 	 *
38 38
 	 * @param {String} sql - The sql with placeholders
39
-	 * @param {Array|undefined} params - The values to insert into the query
39
+	 * @param {Array} params - The values to insert into the query
40 40
 	 * @return {Promise} Result of query
41 41
 	 */
42 42
 	execute (sql, params) {

+ 32
- 19
lib/adapters/Pg/Pg.js View File

@@ -7,14 +7,38 @@ const url = require('url');
7 7
 class Pg extends Adapter {
8 8
 	constructor (config) {
9 9
 		let instance = null;
10
+		let connectionString = Pg.formatConnectionString(config);
11
+
12
+		if (connectionString !== '') {
13
+			const conn = new pg.Client(connectionString);
14
+			conn.connect(err => {
15
+				if (err) {
16
+					throw new Error(err);
17
+				}
18
+			});
19
+
20
+			instance = Promise.resolve(conn);
21
+		}
22
+
23
+		super(instance);
24
+	}
25
+
26
+	/**
27
+	 * Convert the connection object to a connection string
28
+	 *
29
+	 * @param {Object} config - the configuration object
30
+	 * @return {String} - the connection string
31
+	 */
32
+	static formatConnectionString (config) {
10 33
 		let connectionString = '';
34
+
11 35
 		if (Helpers.isObject(config)) {
12
-			let host = config.host || 'localhost';
13
-			let user = config.user || 'postgres';
14
-			let password = `:${config.password}` || '';
15
-			let port = config.port || 5432;
36
+			const host = config.host || 'localhost';
37
+			const user = config.user || 'postgres';
38
+			const password = `:${config.password}` || '';
39
+			const port = config.port || 5432;
16 40
 
17
-			let conn = {
41
+			const conn = {
18 42
 				protocol: 'postgres',
19 43
 				slashes: true,
20 44
 				host: `${host}:${port}`,
@@ -27,18 +51,7 @@ class Pg extends Adapter {
27 51
 			connectionString = config;
28 52
 		}
29 53
 
30
-		if (connectionString !== '') {
31
-			let conn = new pg.Client(connectionString);
32
-			conn.connect(err => {
33
-				if (err) {
34
-					throw new Error(err);
35
-				}
36
-			});
37
-
38
-			instance = Promise.resolve(conn);
39
-		}
40
-
41
-		super(instance);
54
+		return connectionString;
42 55
 	}
43 56
 
44 57
 	/**
@@ -52,9 +65,9 @@ class Pg extends Adapter {
52 65
 			return new Result();
53 66
 		}
54 67
 
55
-		let cols = [];
68
+		const cols = [];
56 69
 		result.fields.forEach(field => {
57
-			cols = field.name;
70
+			cols.push(field.name);
58 71
 		});
59 72
 
60 73
 		return new Result(result.rows, cols);

+ 0
- 25
lib/adapters/Pg/PgNative.js View File

@@ -1,25 +0,0 @@
1
-const Pg = require('./Pg');
2
-const pg = require('pg').native;
3
-
4
-class PgNative extends Pg {
5
-	constructor (config) {
6
-		super(config);
7
-		let instance = null;
8
-		let connectionString = Pg._formatConnectionString(config);
9
-
10
-		if (connectionString !== '') {
11
-			let conn = new pg.Client(connectionString);
12
-			conn.connect(err => {
13
-				if (err) {
14
-					throw new Error(err);
15
-				}
16
-			});
17
-
18
-			instance = Promise.resolve(conn);
19
-		}
20
-
21
-		super.instance = instance;
22
-	}
23
-}
24
-
25
-module.exports = PgNative;

+ 1
- 7
lib/adapters/Pg/index.js View File

@@ -1,8 +1,2 @@
1 1
 const Pg = require('./Pg');
2
-const PgNative = require('./PgNative');
3
-
4
-module.exports = config => {
5
-	return (config.native)
6
-		? new PgNative(config.connection)
7
-		: new Pg(config.connection);
8
-};
2
+module.exports = config => new Pg(config.connection);

+ 2
- 2
lib/adapters/Sqlite/dblite.js View File

@@ -5,10 +5,10 @@ const dbliteAdapter = require('dblite');
5 5
 
6 6
 class SqliteDblite extends Adapter {
7 7
 	constructor (config) {
8
-		let file = (Helpers.isString(config)) ? config : config.file;
8
+		const file = (Helpers.isString(config)) ? config : config.file;
9 9
 
10 10
 		const instance = new Promise((resolve, reject) => {
11
-			let conn = dbliteAdapter(file);
11
+			const conn = dbliteAdapter(file);
12 12
 
13 13
 			// Stop the stupid 'bye bye' message being output
14 14
 			conn.on('close', () => {});

+ 2
- 2
lib/adapters/Sqlite/sqlite3.js View File

@@ -5,10 +5,10 @@ const sqlite3 = require('sqlite3').verbose();
5 5
 
6 6
 class SqliteSqlite3 extends Adapter {
7 7
 	constructor (config) {
8
-		let file = (Helpers.isString(config)) ? config : config.file;
8
+		const file = (Helpers.isString(config)) ? config : config.file;
9 9
 
10 10
 		const instance = new Promise((resolve, reject) => {
11
-			let conn = new sqlite3.Database(file, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, err => {
11
+			const conn = new sqlite3.Database(file, sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, err => {
12 12
 				if (err) {
13 13
 					reject(err);
14 14
 				}

+ 0
- 3
lib/drivers/MSSQLDriver.js View File

@@ -1,5 +1,3 @@
1
-'use strict';
2
-
3 1
 /**
4 2
  * Driver for Microsoft SQL Server databases
5 3
  *
@@ -8,7 +6,6 @@
8 6
 module.exports = (() => {
9 7
 	delete require.cache[require.resolve('../Driver')];
10 8
 	const driver = require('../Driver');
11
-	const Helpers = require('../Helpers');
12 9
 
13 10
 	driver.identifierStartChar = '[';
14 11
 	driver.identifierEndChar = ']';

+ 1
- 3
lib/drivers/Pg.js View File

@@ -5,7 +5,5 @@
5 5
  */
6 6
 module.exports = (() => {
7 7
 	delete require.cache[require.resolve('../Driver')];
8
-	let driver = require('../Driver');
9
-
10
-	return driver;
8
+	return require('../Driver');
11 9
 })();

+ 7
- 7
lib/drivers/Sqlite.js View File

@@ -5,7 +5,7 @@
5 5
  */
6 6
 module.exports = (() => {
7 7
 	delete require.cache[require.resolve('../Driver')];
8
-	let driver = require('../Driver');
8
+	const driver = require('../Driver');
9 9
 
10 10
 	// Sqlite doesn't have a truncate command
11 11
 	driver.hasTruncate = false;
@@ -22,11 +22,11 @@ module.exports = (() => {
22 22
 		// Get the data values to insert, so they can
23 23
 		// be parameterized
24 24
 		let sql = '';
25
-		let first = data.shift();
25
+		const first = data.shift();
26 26
 
27
-		let vals = [];
27
+		const vals = [];
28 28
 		data.forEach(obj => {
29
-			let row = [];
29
+			const row = [];
30 30
 			Object.keys(obj).forEach(key => {
31 31
 				row.push(obj[key]);
32 32
 			});
@@ -37,8 +37,8 @@ module.exports = (() => {
37 37
 
38 38
 		// Get the field names from the keys of the first
39 39
 		// object to be inserted
40
-		let fields = Object.keys(first);
41
-		let cols = [];
40
+		const fields = Object.keys(first);
41
+		const cols = [];
42 42
 		fields.forEach(key => {
43 43
 			cols.push(`'${driver._quote(first[key])}' AS ${driver.quoteIdentifiers(key)}`);
44 44
 		});
@@ -46,7 +46,7 @@ module.exports = (() => {
46 46
 		sql += `SELECT ${cols.join(', ')}\n`;
47 47
 
48 48
 		vals.forEach(rowValues => {
49
-			let quoted = rowValues.map(value => String(value).replace('\'', '\'\''));
49
+			const quoted = rowValues.map(value => String(value).replace('\'', '\'\''));
50 50
 			sql += `UNION ALL SELECT '${quoted.join('\', \'')}'\n`;
51 51
 		});
52 52
 

+ 12
- 18
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
 	"name": "ci-node-query",
3
-	"version": "6.0.0",
3
+	"version": "5.0.0",
4 4
 	"description": "A query builder for node based on the one in CodeIgniter",
5 5
 	"author": "Timothy J Warren <tim@timshomepage.net>",
6 6
 	"engines": {
@@ -42,27 +42,31 @@
42 42
 		"glob": "^7.0.3",
43 43
 		"mysql2": "^1.2.0",
44 44
 		"pg": "^7.4",
45
-		"require-reload": "~0.2.2",
46 45
 		"sqlite3": "^3.1.8",
47 46
 		"tedious": "^2.0.0",
48 47
 		"xregexp": "^4.0.0"
49 48
 	},
50 49
 	"devDependencies": {
51 50
 		"babel-eslint": "^8.2.1",
52
-		"chai": "^4.1",
53
-		"chai-as-promised": "^7.1",
54 51
 		"documentation": "latest",
55 52
 		"eslint": "^4.16.0",
53
+		"eslint-config-happiness": "^10.2.1",
54
+		"eslint-plugin-import": "^2.8.0",
55
+		"eslint-plugin-node": "^5.2.1",
56
+		"eslint-plugin-promise": "^3.6.0",
57
+		"eslint-plugin-standard": "^3.0.1",
56 58
 		"globstar": "^1.0.0",
57
-		"happiness": "^10.0",
58 59
 		"jest": "^22.0.0",
59 60
 		"jsdoc": "^3.4.3",
60 61
 		"npm-run-all": "^4.0.2",
61 62
 		"nsp": "^3.1",
62
-		"pg-native": "^2.2"
63
+		"require-reload": "~0.2.2"
63 64
 	},
64 65
 	"license": "MIT",
65 66
 	"jest": {
67
+		"collectCoverageFrom": [
68
+			"lib/**/*.js"
69
+		],
66 70
 		"coverageDirectory": "coverage",
67 71
 		"coverageReporters": [
68 72
 			"html",
@@ -82,21 +86,11 @@
82 86
 		"default": "npm-run-all --parallel audit lint:src lint:tests && npm run test",
83 87
 		"predocs": "globstar -- documentation build -f md -o API.md \"lib/*.js\"",
84 88
 		"docs": "globstar -- documentation build -f html -o docs \"lib/*.js\"",
85
-		"fix": "happiness --fix \"lib/**/*.js\" \"test/**/*.js\"",
89
+		"fix": "eslint --fix ./lib ./test",
86 90
 		"postdocs": "jsdoc lib -r -d documentation",
87
-		"happy": "happiness \"lib/**/*.js\" \"test/**/*.js\"",
88
-		"happy:src": "happiness \"lib/**/*.js\"",
89
-		"happy:tests": "happiness \"test/**/*.js\"",
90
-		"lint": "npm-run-all lint:tests lint:src happy",
91
+		"lint": "npm-run-all lint:src lint:tests",
91 92
 		"lint:src": "eslint ./lib",
92 93
 		"lint:tests": "eslint ./test",
93 94
 		"test": "jest"
94
-	},
95
-	"happiness": {
96
-		"env": {
97
-			"es6": true,
98
-			"jest": true
99
-		},
100
-		"parser": "babel-eslint"
101 95
 	}
102 96
 }

+ 11
- 0
test/adapters/__snapshots__/dblite_test.js.snap View File

@@ -0,0 +1,11 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`Dblite adapter tests - Get compiled -  getCompiledDelete 1`] = `"DELETE FROM \\"create_test\\" WHERE \\"id\\" = ?"`;
4
+
5
+exports[`Dblite adapter tests - Get compiled -  getCompiledInsert 1`] = `"INSERT INTO \\"create_test\\" (\\"id\\",\\"key\\",\\"val\\") VALUES (?,?,?)"`;
6
+
7
+exports[`Dblite adapter tests - Get compiled -  getCompiledSelect 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
8
+
9
+exports[`Dblite adapter tests - Get compiled -  getCompiledSelect 2 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
10
+
11
+exports[`Dblite adapter tests - Get compiled -  getCompiledUpdate 1`] = `"UPDATE \\"create_test\\" SET \\"id\\"=?,\\"key\\"=?,\\"val\\"=? WHERE \\"id\\" = ?"`;

+ 11
- 0
test/adapters/__snapshots__/mysql2_test.js.snap View File

@@ -0,0 +1,11 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`Mysql2 adapter tests - Get compiled -  getCompiledDelete 1`] = `"DELETE FROM \`create_test\` WHERE \`id\` = ?"`;
4
+
5
+exports[`Mysql2 adapter tests - Get compiled -  getCompiledInsert 1`] = `"INSERT INTO \`create_test\` (\`id\`,\`key\`,\`val\`) VALUES (?,?,?)"`;
6
+
7
+exports[`Mysql2 adapter tests - Get compiled -  getCompiledSelect 1`] = `"SELECT \`id\`, \`key\` AS \`k\`, \`val\` FROM \`create_test\` WHERE (\`id\` > ? AND \`id\` < ?) LIMIT 1,2"`;
8
+
9
+exports[`Mysql2 adapter tests - Get compiled -  getCompiledSelect 2 1`] = `"SELECT \`id\`, \`key\` AS \`k\`, \`val\` FROM \`create_test\` WHERE (\`id\` > ? AND \`id\` < ?) LIMIT 1,2"`;
10
+
11
+exports[`Mysql2 adapter tests - Get compiled -  getCompiledUpdate 1`] = `"UPDATE \`create_test\` SET \`id\`=?,\`key\`=?,\`val\`=? WHERE \`id\` = ?"`;

+ 11
- 0
test/adapters/__snapshots__/pg_test.js.snap View File

@@ -0,0 +1,11 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`Pg adapter tests - Get compiled -  getCompiledDelete 1`] = `"DELETE FROM \\"create_test\\" WHERE \\"id\\" = ?"`;
4
+
5
+exports[`Pg adapter tests - Get compiled -  getCompiledInsert 1`] = `"INSERT INTO \\"create_test\\" (\\"id\\",\\"key\\",\\"val\\") VALUES (?,?,?)"`;
6
+
7
+exports[`Pg adapter tests - Get compiled -  getCompiledSelect 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
8
+
9
+exports[`Pg adapter tests - Get compiled -  getCompiledSelect 2 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
10
+
11
+exports[`Pg adapter tests - Get compiled -  getCompiledUpdate 1`] = `"UPDATE \\"create_test\\" SET \\"id\\"=?,\\"key\\"=?,\\"val\\"=? WHERE \\"id\\" = ?"`;

+ 11
- 0
test/adapters/__snapshots__/sqlite3_test.js.snap View File

@@ -0,0 +1,11 @@
1
+// Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+exports[`Sqlite3 adapter tests - Get compiled -  getCompiledDelete 1`] = `"DELETE FROM \\"create_test\\" WHERE \\"id\\" = ?"`;
4
+
5
+exports[`Sqlite3 adapter tests - Get compiled -  getCompiledInsert 1`] = `"INSERT INTO \\"create_test\\" (\\"id\\",\\"key\\",\\"val\\") VALUES (?,?,?)"`;
6
+
7
+exports[`Sqlite3 adapter tests - Get compiled -  getCompiledSelect 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
8
+
9
+exports[`Sqlite3 adapter tests - Get compiled -  getCompiledSelect 2 1`] = `"SELECT \\"id\\", \\"key\\" AS \\"k\\", \\"val\\" FROM \\"create_test\\" WHERE (\\"id\\" > ? AND \\"id\\" < ?) LIMIT 2 OFFSET 1"`;
10
+
11
+exports[`Sqlite3 adapter tests - Get compiled -  getCompiledUpdate 1`] = `"UPDATE \\"create_test\\" SET \\"id\\"=?,\\"key\\"=?,\\"val\\"=? WHERE \\"id\\" = ?"`;

+ 1
- 21
test/adapters/dblite_test.js View File

@@ -19,7 +19,7 @@ describe('Dblite adapter tests -', () => {
19 19
 	});
20 20
 
21 21
 	testRunner(qb);
22
-	it('Promise - Select with function and argument in WHERE clause', async () => {
22
+	it('Select with function and argument in WHERE clause', async () => {
23 23
 		let promise = await qb.select('id')
24 24
 			.from('create_test')
25 25
 			.where('id', 'ABS(-88)')
@@ -27,26 +27,6 @@ describe('Dblite adapter tests -', () => {
27 27
 
28 28
 		expect(promise).toEqual(expect.anything());
29 29
 	});
30
-	it('Promise - Test Insert Batch', async () => {
31
-		let data = [
32
-			{
33
-				id: 544,
34
-				key: 3,
35
-				val: Buffer.from('7')
36
-			}, {
37
-				id: 89,
38
-				key: 34,
39
-				val: Buffer.from('10 o\'clock')
40
-			}, {
41
-				id: 48,
42
-				key: 403,
43
-				val: Buffer.from('97')
44
-			}
45
-		];
46
-
47
-		let promise = await qb.insertBatch('create_test', data);
48
-		expect(promise).toEqual(expect.anything());
49
-	});
50 30
 	afterAll(() => {
51 31
 		qb.end();
52 32
 	});

+ 3
- 24
test/adapters/mysql2_test.js View File

@@ -24,7 +24,7 @@ describe('Mysql2 adapter tests -', () => {
24 24
 	});
25 25
 
26 26
 	testRunner(qb);
27
-	it('Promise - Select with function and argument in WHERE clause', async () => {
27
+	it('Select with function and argument in WHERE clause', async () => {
28 28
 		let promise = await qb.select('id')
29 29
 			.from('create_test')
30 30
 			.where('id', 'CEILING(SQRT(88))')
@@ -36,28 +36,7 @@ describe('Mysql2 adapter tests -', () => {
36 36
 		let promise = await qb.truncate('create_test');
37 37
 		expect(promise).toEqual(expect.anything());
38 38
 	});
39
-	it('Test Insert Batch', async () => {
40
-		let data = [
41
-			{
42
-				id: 5442,
43
-				key: 4,
44
-				val: Buffer.from('7')
45
-			}, {
46
-				id: 892,
47
-				key: 35,
48
-				val: Buffer.from('10 o\'clock')
49
-			}, {
50
-				id: 482,
51
-				key: 404,
52
-				val: 97
53
-			}
54
-		];
55
-
56
-		const promise = await qb.insertBatch('create_test', data);
57
-		expect(promise).toEqual(expect.anything());
58
-	});
59
-
60
-	/* describeTeardown(() => {
39
+	afterAll(() => {
61 40
 		qb.end();
62
-	}); */
41
+	});
63 42
 });

+ 4
- 24
test/adapters/pg_test.js View File

@@ -45,36 +45,16 @@ describe('Pg adapter tests -', () => {
45 45
 	});
46 46
 
47 47
 	testRunner(qb);
48
-	it('Promise - Select with function and argument in WHERE clause', async () => {
49
-		let promise = await qb.select('id')
48
+	it('Select with function and argument in WHERE clause', async () => {
49
+		const promise = await qb.select('id')
50 50
 			.from('create_test')
51 51
 			.where('id', 'CEILING(SQRT(88))')
52 52
 			.get();
53 53
 
54 54
 		expect(promise).toEqual(expect.anything());
55 55
 	});
56
-	it('Promise - Test Truncate', async () => {
57
-		let promise = await qb.truncate('create_test');
58
-		expect(promise).toEqual(expect.anything());
59
-	});
60
-	it('Promise - Test Insert Batch', async () => {
61
-		let data = [
62
-			{
63
-				id: 544,
64
-				key: 3,
65
-				val: Buffer.from('7')
66
-			}, {
67
-				id: 89,
68
-				key: 34,
69
-				val: Buffer.from('10 o\'clock')
70
-			}, {
71
-				id: 48,
72
-				key: 403,
73
-				val: Buffer.from('97')
74
-			}
75
-		];
76
-
77
-		let promise = await qb.insertBatch('create_test', data);
56
+	it('Test Truncate', async () => {
57
+		const promise = await qb.truncate('create_test');
78 58
 		expect(promise).toEqual(expect.anything());
79 59
 	});
80 60
 	afterAll(() => {

+ 1
- 21
test/adapters/sqlite3_test.js View File

@@ -20,7 +20,7 @@ describe('Sqlite3 adapter tests -', () => {
20 20
 	});
21 21
 
22 22
 	testRunner(qb);
23
-	it('Promise - Select with function and argument in WHERE clause', async () => {
23
+	it('Select with function and argument in WHERE clause', async () => {
24 24
 		let promise = await qb.select('id')
25 25
 			.from('create_test')
26 26
 			.where('id', 'ABS(-88)')
@@ -28,26 +28,6 @@ describe('Sqlite3 adapter tests -', () => {
28 28
 
29 29
 		expect(promise).toEqual(expect.anything());
30 30
 	});
31
-	it('Promise - Test Insert Batch', async () => {
32
-		let data = [
33
-			{
34
-				id: 544,
35
-				key: 3,
36
-				val: Buffer.from('7')
37
-			}, {
38
-				id: 89,
39
-				key: 34,
40
-				val: Buffer.from('10 o\'clock')
41
-			}, {
42
-				id: 48,
43
-				key: 403,
44
-				val: Buffer.from('97')
45
-			}
46
-		];
47
-
48
-		let promise = await qb.insertBatch('create_test', data);
49
-		expect(promise).toEqual(expect.anything());
50
-	});
51 31
 	afterAll(() => {
52 32
 		qb.end();
53 33
 	});

+ 0
- 5
test/base.js View File

@@ -1,13 +1,8 @@
1
-const chai = require('chai');
2
-const chaiAsPromised = require('chai-as-promised');
3
-chai.use(chaiAsPromised);
4
-
5 1
 // Load the test config file
6 2
 const configFile = './config.json';
7 3
 
8 4
 module.exports = {
9 5
 	config: require(configFile),
10
-	expect: chai.expect,
11 6
 	tests: require('./base/tests'),
12 7
 	promiseTestRunner: require('./base/adapterPromiseTestRunner')
13 8
 };

+ 101
- 15
test/base/adapterPromiseTestRunner.js View File

@@ -37,13 +37,14 @@ module.exports = function promiseTestRunner (qb) {
37 37
 			});
38 38
 		});
39 39
 	});
40
-	describe('DB update tests -', async () => {
40
+
41
+	describe('DB update tests -', () => {
41 42
 		beforeAll(done => {
42 43
 			let sql = qb.driver.truncate('create_test');
43
-			qb.query(sql).then(res => done())
44
+			qb.query(sql).then(() => done())
44 45
 				.catch(err => done(err));
45 46
 		});
46
-		it('Promise - Test Insert', async () => {
47
+		it('Test Insert', async () => {
47 48
 			const promise = await qb.set('id', 98)
48 49
 				.set('key', '84')
49 50
 				.set('val', Buffer.from('120'))
@@ -51,7 +52,7 @@ module.exports = function promiseTestRunner (qb) {
51 52
 
52 53
 			expect(promise).toEqual(expect.anything());
53 54
 		});
54
-		it('Promise - Test Insert Object', async () => {
55
+		it('Test Insert Object', async () => {
55 56
 			const promise = await qb.insert('create_test', {
56 57
 				id: 587,
57 58
 				key: 1,
@@ -60,7 +61,7 @@ module.exports = function promiseTestRunner (qb) {
60 61
 
61 62
 			expect(promise).toEqual(expect.anything());
62 63
 		});
63
-		it('Promise - Test Update', async () => {
64
+		it('Test Update', async () => {
64 65
 			const promise = await qb.where('id', 7)
65 66
 				.update('create_test', {
66 67
 					id: 7,
@@ -70,7 +71,7 @@ module.exports = function promiseTestRunner (qb) {
70 71
 
71 72
 			expect(promise).toEqual(expect.anything());
72 73
 		});
73
-		it('Promise - Test set Array Update', async () => {
74
+		it('Test set Array Update', async () => {
74 75
 			let object = {
75 76
 				id: 22,
76 77
 				key: 'gogle',
@@ -83,7 +84,7 @@ module.exports = function promiseTestRunner (qb) {
83 84
 
84 85
 			expect(promise).toEqual(expect.anything());
85 86
 		});
86
-		it('Promise - Test where set update', async () => {
87
+		it('Test where set update', async () => {
87 88
 			const promise = await qb.where('id', 36)
88 89
 				.set('id', 36)
89 90
 				.set('key', 'gogle')
@@ -92,17 +93,17 @@ module.exports = function promiseTestRunner (qb) {
92 93
 
93 94
 			expect(promise).toEqual(expect.anything());
94 95
 		});
95
-		it('Promise - Test delete', async () => {
96
+		it('Test delete', async () => {
96 97
 			const promise = await qb.delete('create_test', {id: 5});
97 98
 			expect(promise).toEqual(expect.anything());
98 99
 		});
99
-		it('Promise - Delete with where', async () => {
100
+		it('Delete with where', async () => {
100 101
 			const promise = await qb.where('id', 5)
101 102
 				.delete('create_test');
102 103
 
103 104
 			expect(promise).toEqual(expect.anything());
104 105
 		});
105
-		it('Promise - Delete multiple where values', async () => {
106
+		it('Delete multiple where values', async () => {
106 107
 			const promise = await qb.delete('create_test', {
107 108
 				id: 5,
108 109
 				key: 'gogle'
@@ -111,8 +112,46 @@ module.exports = function promiseTestRunner (qb) {
111 112
 			expect(promise).toEqual(expect.anything());
112 113
 		});
113 114
 	});
114
-	describe('Grouping tests -', async () => {
115
-		it('Promise - Using grouping method', async () => {
115
+
116
+	describe('Batch tests -', () => {
117
+		it('Test Insert Batch', async () => {
118
+			const data = [
119
+				{
120
+					id: 544,
121
+					key: 3,
122
+					val: Buffer.from('7')
123
+				}, {
124
+					id: 89,
125
+					key: 34,
126
+					val: Buffer.from('10 o\'clock')
127
+				}, {
128
+					id: 48,
129
+					key: 403,
130
+					val: Buffer.from('97')
131
+				}
132
+			];
133
+
134
+			const promise = await qb.insertBatch('create_test', data);
135
+			expect(promise).toEqual(expect.anything());
136
+		});
137
+		it('Test Update Batch', async () => {
138
+			const data = [{
139
+				id: 480,
140
+				key: 49,
141
+				val: '7x7'
142
+			}, {
143
+				id: 890,
144
+				key: 100,
145
+				val: '10x10'
146
+			}];
147
+
148
+			const affectedRows = qb.updateBatch('create_test', data, 'id');
149
+			expect(affectedRows).toBe(2);
150
+		});
151
+	});
152
+
153
+	describe('Grouping tests -', () => {
154
+		it('Using grouping method', async () => {
116 155
 			const promise = await qb.select('id, key as k, val')
117 156
 				.from('create_test')
118 157
 				.groupStart()
@@ -124,7 +163,7 @@ module.exports = function promiseTestRunner (qb) {
124 163
 
125 164
 			expect(promise).toEqual(expect.anything());
126 165
 		});
127
-		it('Promise - Using where first grouping', async () => {
166
+		it('Using where first grouping', async () => {
128 167
 			const promise = await qb.select('id, key as k, val')
129 168
 				.from('create_test')
130 169
 				.where('id !=', 5)
@@ -137,7 +176,7 @@ module.exports = function promiseTestRunner (qb) {
137 176
 
138 177
 			expect(promise).toEqual(expect.anything());
139 178
 		});
140
-		it('Promise - Using or grouping method', async () => {
179
+		it('Using or grouping method', async () => {
141 180
 			const promise = await qb.select('id, key as k, val')
142 181
 				.from('create_test')
143 182
 				.groupStart()
@@ -152,7 +191,7 @@ module.exports = function promiseTestRunner (qb) {
152 191
 
153 192
 			expect(promise).toEqual(expect.anything());
154 193
 		});
155
-		it('Promise - Using or not grouping method', async () => {
194
+		it('Using or not grouping method', async () => {
156 195
 			const promise = await qb.select('id, key as k, val')
157 196
 				.from('create_test')
158 197
 				.groupStart()
@@ -168,4 +207,51 @@ module.exports = function promiseTestRunner (qb) {
168 207
 			expect(promise).toEqual(expect.anything());
169 208
 		});
170 209
 	});
210
+	describe('Get compiled - ', () => {
211
+		it('getCompiledSelect', () => {
212
+			const sql = qb.select('id, key as k, val')
213
+				.from('create_test')
214
+				.groupStart()
215
+				.where('id >', 1)
216
+				.where('id <', 900)
217
+				.groupEnd()
218
+				.limit(2, 1)
219
+				.getCompiledSelect();
220
+
221
+			expect(sql).toMatchSnapshot();
222
+		});
223
+		it('getCompiledSelect 2', () => {
224
+			const sql = qb.select('id, key as k, val')
225
+				.groupStart()
226
+				.where('id >', 1)
227
+				.where('id <', 900)
228
+				.groupEnd()
229
+				.limit(2, 1)
230
+				.getCompiledSelect('create_test');
231
+
232
+			expect(sql).toMatchSnapshot();
233
+		});
234
+		it('getCompiledInsert', () => {
235
+			const sql = qb.set({
236
+				id: 587,
237
+				key: 1,
238
+				val: Buffer.from('2')
239
+			}).getCompiledInsert('create_test');
240
+
241
+			expect(sql).toMatchSnapshot();
242
+		});
243
+		it('getCompiledUpdate', () => {
244
+			const sql = qb.where('id', 36)
245
+				.set('id', 36)
246
+				.set('key', 'gogle')
247
+				.set('val', Buffer.from('non-word'))
248
+				.getCompiledUpdate('create_test');
249
+
250
+			expect(sql).toMatchSnapshot();
251
+		});
252
+		it('getCompiledDelete', () => {
253
+			const sql = qb.where({id: 5}).getCompiledDelete('create_test');
254
+			expect(sql).toMatchSnapshot();
255
+		});
256
+	});
171 257
 };

+ 12
- 9
test/config-ci.json View File

@@ -18,6 +18,18 @@
18 18
 			"database": "test"
19 19
 		}
20 20
 	},
21
+	"pg-native": {
22
+		"driver": "pg",
23
+		"native": true,
24
+		"connection": "postgres://test:test@posgres/test"
25
+	},
26
+	"pg-object-native": {
27
+		"driver": "pg",
28
+		"native": true,
29
+		"connection": {
30
+			"database": "test"
31
+		}
32
+	},
21 33
 	"dblite": {
22 34
 		"adapter": "dblite",
23 35
 		"driver": "sqlite",
@@ -26,14 +38,5 @@
26 38
 	"sqlite3": {
27 39
 		"driver": "sqlite",
28 40
 		"connection": ":memory:"
29
-	},
30
-	"node-firebird": {
31
-		"driver": "firebird",
32
-		"connection": {
33
-			"host": "127.0.0.1",
34
-			"database": "/../FB_TEST_DB.FDB",
35
-			"user": "SYSDBA",
36
-			"password": "masterkey"
37
-		}
38 41
 	}
39 42
 }