Skip to content

Commit fa9ed57

Browse files
author
Matin Movassate
committed
Merge remote-tracking branch 'upstream/master'
Conflicts: lib/dialect/postgres.js lib/node/valueExpression.js
2 parents c99ae65 + 47ddb42 commit fa9ed57

16 files changed

Lines changed: 505 additions & 50 deletions

lib/dialect/mysql.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ Mysql.prototype._getParameterPlaceholder = function() {
2222
return '?';
2323
};
2424

25+
Mysql.prototype._getParameterValue = function(value) {
26+
if (Buffer.isBuffer(value)) {
27+
value = 'x' + this._getParameterValue(value.toString('hex'));
28+
} else {
29+
value = Postgres.prototype._getParameterValue.call(this, value);
30+
}
31+
return value;
32+
};
33+
2534
Mysql.prototype.visitReturning = function() {
2635
throw new Error('MySQL does not allow returning clause.');
2736
};
@@ -58,7 +67,7 @@ Mysql.prototype.visitInsert = function(insert) {
5867
};
5968

6069
Mysql.prototype.visitIndexes = function(node) {
61-
var tableName = this.visit(this._queryNode.table.toNode());
70+
var tableName = this.visit(this._queryNode.table.toNode())[0];
6271

6372
return "SHOW INDEX FROM " + tableName;
6473
};

lib/dialect/postgres.js

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Postgres.prototype._getParameterValue = function(value) {
4646
// Date object's default toString format does not get parsed well
4747
// Handle date like objects using toISOString
4848
value = this._getParameterValue(value.toISOString());
49+
} else if (Buffer.isBuffer(value)) {
50+
value = this._getParameterValue('\\x' + value.toString('hex'));
4951
} else {
5052
// rich object represent with string
5153
value = this._getParameterValue(value.toString());
@@ -137,8 +139,9 @@ Postgres.prototype.visit = function(node) {
137139
case 'PREFIX UNARY' : return this.visitPrefixUnary(node);
138140
case 'BINARY' : return this.visitBinary(node);
139141
case 'TERNARY' : return this.visitTernary(node);
140-
case 'AT' : return this.visitAt(node);
141-
case 'SLICE' : return this.visitSlice(node);
142+
case 'CASE' : return this.visitCase(node);
143+
case 'AT' : return this.visitAt(node);
144+
case 'SLICE' : return this.visitSlice(node);
142145

143146
case 'LIMIT' :
144147
case 'OFFSET':
@@ -282,7 +285,9 @@ Postgres.prototype.visitFrom = function(from) {
282285
};
283286

284287
Postgres.prototype.visitWhere = function(where) {
288+
this._visitingWhere = true;
285289
var result = ['WHERE', where.nodes.map(this.visit.bind(this)).join(', ')];
290+
this._visitingWhere = false;
286291
return result;
287292
};
288293

@@ -359,6 +364,26 @@ Postgres.prototype.visitTernary = function(ternary) {
359364
return [text];
360365
};
361366

367+
Postgres.prototype.visitCase = function(caseExp) {
368+
assert(caseExp.whenList.length == caseExp.thenList.length);
369+
370+
var self = this;
371+
var text = '(CASE';
372+
373+
for (var i = 0; i < caseExp.whenList.length; i++) {
374+
var whenExp = ' WHEN ' + this.visit(caseExp.whenList[i]);
375+
var thenExp = ' THEN ' + this.visit(caseExp.thenList[i]);
376+
text += whenExp + thenExp;
377+
}
378+
379+
if (null != caseExp.else && undefined != caseExp.else) {
380+
text += ' ELSE ' + this.visit(caseExp.else);
381+
}
382+
383+
text += ' END)';
384+
return [text];
385+
}
386+
362387
Postgres.prototype.visitAt = function(at) {
363388
var text = '(' + this.visit(at.value) + ')[' + this.visit(at.index) + ']';
364389
return [text];
@@ -461,61 +486,76 @@ Postgres.prototype.visitTable = function(tableNode) {
461486

462487
Postgres.prototype.visitColumn = function(columnNode) {
463488
var table = columnNode.table;
464-
var inSelectClause = !this._selectOrDeleteEndIndex;
465-
var txt = "";
489+
var inInsertUpdateClause = this._visitedInsert || this._visitingUpdateTargetColumn;
490+
var inDdlClause = this._visitingAddColumn || this._visitingAlter || this._visitingCreate;
491+
var inSelectClause =
492+
!this._selectOrDeleteEndIndex
493+
&& !this._visitingWhere
494+
&& !inInsertUpdateClause
495+
&& !inDdlClause
496+
var txt = [];
466497
var closeParen = 0;
467498
if(inSelectClause && !table.alias) {
468499
if (columnNode.asArray) {
469500
closeParen++;
470-
txt += this._arrayAggFunctionName+'(';
501+
txt.push(this._arrayAggFunctionName+'(');
471502
}
472503

473504
if (!!columnNode.aggregator) {
474505
closeParen++;
475-
txt += columnNode.aggregator + '(';
506+
txt.push(columnNode.aggregator + '(');
476507
}
477508

478509
if (columnNode.distinct === true) {
479510
closeParen++;
480-
txt += 'DISTINCT(';
511+
txt.push('DISTINCT(');
481512
}
482513
}
483-
if(!this._visitedInsert && !this._visitingUpdateTargetColumn && !this._visitingCreate && !this._visitingAlter) {
514+
if(!inInsertUpdateClause && !this._visitingCreate && !this._visitingAlter) {
484515
if(table.alias) {
485-
txt += this.quote(table.alias);
516+
txt.push(this.quote(table.alias));
486517
} else {
487518
if(table.getSchema()) {
488-
txt += this.quote(table.getSchema());
489-
txt += '.';
519+
txt.push(this.quote(table.getSchema()));
520+
txt.push('.');
490521
}
491-
txt += this.quote(table.getName());
522+
txt.push(this.quote(table.getName()));
492523
}
493-
txt += '.';
524+
txt.push('.');
494525
}
495526
if (columnNode.star) {
496-
txt += '*';
497-
} else {
498-
txt += this.quote(columnNode.name);
527+
var allCols = [];
528+
var hasAliases = false;
529+
for(var i = 0; i < table.columns.length; ++i){
530+
var col = table.columns[i];
531+
var aliased = col.name !== (col.alias || col.property);
532+
hasAliases = hasAliases || aliased;
533+
allCols.push(this.quote(col.name) + (aliased ? ' AS ' + this.quote(col.alias || col.property) : ''));
534+
}
535+
txt.push(hasAliases ? allCols.join(', ') : '*');
536+
}
537+
else {
538+
txt.push(this.quote(columnNode.name));
499539
}
500540
if(closeParen) {
501541
for(var i = 0; i < closeParen; i++) {
502-
txt += ')';
542+
txt.push(')');
503543
}
504544
}
505-
if(inSelectClause && columnNode.alias) {
506-
txt += ' AS ' + this.quote(columnNode.alias);
545+
if(inSelectClause && (columnNode.alias || columnNode.property !== columnNode.name)) {
546+
txt.push(' AS ' + this.quote(columnNode.alias || columnNode.property));
507547
}
508548
if(this._visitingCreate || this._visitingAddColumn) {
509549
assert(columnNode.dataType, 'dataType missing for column ' + columnNode.name +
510550
' (CREATE TABLE and ADD COLUMN statements require a dataType)');
511-
txt += ' ' + columnNode.dataType;
551+
txt.push(' ' + columnNode.dataType);
512552

513553
if (this._visitingCreate && columnNode.primaryKey) {
514554
// creating a column as a primary key
515-
txt += ' PRIMARY KEY';
555+
txt.push(' PRIMARY KEY');
516556
}
517557
}
518-
return [txt];
558+
return [txt.join('')];
519559
};
520560

521561
Postgres.prototype.visitFunctionCall = function(functionCall) {
@@ -532,7 +572,7 @@ Postgres.prototype.visitParameter = function(parameter) {
532572
// save the value into the parameters array
533573
var value = parameter.value();
534574
this.params.push(value);
535-
return [this._getParameterText(this.params.length, value)];
575+
return parameter.isExplicit ? [] : [this._getParameterText(this.params.length, value)];
536576
};
537577

538578
Postgres.prototype.visitDefault = function(parameter) {
@@ -587,14 +627,14 @@ Postgres.prototype.visitModifier = function(node) {
587627

588628
Postgres.prototype.visitIndexes = function(node) {
589629
/* jshint unused: false */
590-
var tableName = this.visit(this._queryNode.table.toNode());
630+
var tableName = this.visit(this._queryNode.table.toNode())[0];
591631

592632
return [
593633
"SELECT relname",
594634
"FROM pg_class",
595635
"WHERE oid IN (",
596636
"SELECT indexrelid",
597-
"FROM pg_index, pg_class WHERE pg_class.relname=" + tableName,
637+
"FROM pg_index, pg_class WHERE pg_class.relname=" + tableName.replace(/"/g, "'"),
598638
"AND pg_class.oid=pg_index.indrelid)"
599639
].join(' ');
600640
};

lib/dialect/sqlite.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ Sqlite.prototype._myClass = Sqlite;
1717

1818
Sqlite.prototype._arrayAggFunctionName = 'GROUP_CONCAT';
1919

20+
Sqlite.prototype._getParameterValue = function(value) {
21+
if (Buffer.isBuffer(value)) {
22+
value = 'x' + this._getParameterValue(value.toString('hex'));
23+
} else {
24+
value = Postgres.prototype._getParameterValue.call(this, value);
25+
}
26+
return value;
27+
};
28+
2029
Sqlite.prototype.visitDefault = function() {
2130
throw new Error('SQLite requires that all rows of a multi-row insert are for the same columns.');
2231
};
@@ -41,7 +50,7 @@ Sqlite.prototype.visitAddColumn = function(addColumn) {
4150
};
4251

4352
Sqlite.prototype.visitIndexes = function(node) {
44-
var tableName = this.visit(this._queryNode.table.toNode());
53+
var tableName = this.visit(this._queryNode.table.toNode())[0];
4554
return "PRAGMA INDEX_LIST(" + tableName + ")";
4655
};
4756

lib/node/case.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use strict';
2+
3+
var _ = require('lodash');
4+
var Node = require(__dirname);
5+
var valueExpressionMixin = require(__dirname + '/valueExpression');
6+
7+
var valueExpressionMixed = false;
8+
var CaseNode = Node.define(_.extend({
9+
type: 'CASE',
10+
constructor: function(config) {
11+
Node.call(this);
12+
this.whenList = config.whenList;
13+
this.thenList = config.thenList;
14+
this.else = config.else;
15+
16+
// Delay mixin to runtime, when all nodes have been defined, and
17+
// mixin only once. ValueExpressionMixin has circular dependencies.
18+
if (!valueExpressionMixed) {
19+
valueExpressionMixed = true;
20+
_.extend(CaseNode.prototype, valueExpressionMixin());
21+
}
22+
},
23+
}));
24+
25+
// allow aliasing
26+
var AliasNode = require(__dirname + '/alias');
27+
_.extend(CaseNode.prototype, AliasNode.AliasMixin);
28+
29+
module.exports = CaseNode;

lib/node/column.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = Node.define({
77
constructor: function(config) {
88
Node.call(this);
99
this.name = config.name;
10+
this.property = config.property || config.name;
1011
this.alias = config.alias;
1112
this.star = config.star;
1213
this.asArray = config.asArray;
@@ -16,6 +17,7 @@ module.exports = Node.define({
1617
this.dataType = config.dataType;
1718
this.distinct = config.distinct;
1819
this.primaryKey = config.primaryKey;
20+
this.autoGenerated = !!config.autoGenerated;
1921
},
2022
as: function(alias) {
2123
this.alias = alias;

lib/node/parameter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ var ParameterNode = module.exports = Node.define({
77
constructor: function(val) {
88
Node.call(this);
99
this._val = val;
10+
this.isExplicit = false;
1011
},
1112
value: function() {
1213
return this._val;

lib/node/query.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ var Query = Node.define({
7474
var name = select.nodes[j].alias || select.nodes[j].name;
7575
var col = new Column(select.nodes[j]);
7676
col.name = name;
77+
col.property = name;
7778
col.table = this;
7879
if (this[name] === undefined) {
7980
this[name] = col;
@@ -146,8 +147,11 @@ var Query = Node.define({
146147
var args = sliced(arguments);
147148
// object literal
148149
if (arguments.length === 1 && !o.toNode && !o.forEach) {
149-
args = Object.keys(o).map(function(key) {
150-
return self.table.get(key).value(o[key]);
150+
args = [];
151+
Object.keys(o).forEach(function(key) {
152+
var col = self.table.get(key);
153+
if(col && !col.autoGenerated)
154+
args.push(col.value(o[key]));
151155
});
152156
} else if (o.forEach) {
153157
o.forEach(function(arg) {
@@ -170,11 +174,19 @@ var Query = Node.define({
170174
var self = this;
171175
var update = new Update();
172176
Object.keys(o).forEach(function(key) {
173-
var val = o[key];
174-
update.add(self.table.get(key).value(ParameterNode.getNodeOrParameterNode(val)));
177+
var col = self.table.get(key);
178+
if(col && !col.autoGenerated) {
179+
var val = o[key];
180+
update.add(col.value(ParameterNode.getNodeOrParameterNode(val)));
181+
}
175182
});
176183
return this.add(update);
177184
},
185+
parameter: function(v) {
186+
var param = ParameterNode.getNodeOrParameterNode(v);
187+
param.isExplicit = true;
188+
return this.add(param);
189+
},
178190
delete: function(params) {
179191
var result = this.add(new Delete());
180192
if (params) {

0 commit comments

Comments
 (0)