Skip to content

Commit c99ae65

Browse files
author
Matin Movassate
committed
Add first-class Array support to Postgres dialect.
1 parent 6e0d36e commit c99ae65

6 files changed

Lines changed: 120 additions & 0 deletions

File tree

lib/dialect/postgres.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,14 @@ Postgres.prototype.visit = function(node) {
131131
case 'CREATE INDEX' : return this.visitCreateIndex(node);
132132
case 'DROP INDEX' : return this.visitDropIndex(node);
133133
case 'FUNCTION CALL' : return this.visitFunctionCall(node);
134+
case 'ARRAY CALL' : return this.visitArrayCall(node);
134135

135136
case 'POSTFIX UNARY' : return this.visitPostfixUnary(node);
136137
case 'PREFIX UNARY' : return this.visitPrefixUnary(node);
137138
case 'BINARY' : return this.visitBinary(node);
138139
case 'TERNARY' : return this.visitTernary(node);
140+
case 'AT' : return this.visitAt(node);
141+
case 'SLICE' : return this.visitSlice(node);
139142

140143
case 'LIMIT' :
141144
case 'OFFSET':
@@ -356,6 +359,17 @@ Postgres.prototype.visitTernary = function(ternary) {
356359
return [text];
357360
};
358361

362+
Postgres.prototype.visitAt = function(at) {
363+
var text = '(' + this.visit(at.value) + ')[' + this.visit(at.index) + ']';
364+
return [text];
365+
};
366+
367+
Postgres.prototype.visitSlice = function(slice) {
368+
var text = '(' + this.visit(slice.value) + ')';
369+
text += '[' + this.visit(slice.start) + ':' + this.visit(slice.end) + ']';
370+
return [text];
371+
};
372+
359373
Postgres.prototype.visitQuery = function(queryNode) {
360374
this._queryNode = queryNode;
361375
// need to sort the top level query nodes on visitation priority
@@ -509,6 +523,11 @@ Postgres.prototype.visitFunctionCall = function(functionCall) {
509523
return [txt];
510524
};
511525

526+
Postgres.prototype.visitArrayCall = function(arrayCall) {
527+
var txt = 'ARRAY[' + arrayCall.nodes.map(this.visit.bind(this)).join(', ') + ']';
528+
return [txt];
529+
};
530+
512531
Postgres.prototype.visitParameter = function(parameter) {
513532
// save the value into the parameters array
514533
var value = parameter.value();

lib/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var _ = require('lodash');
44
var FunctionCall = require('./node/functionCall');
5+
var ArrayCall = require('./node/arrayCall');
56
var functions = require('./functions');
67
var getDialect = require('./dialect');
78
var Query = require('./node/query');
@@ -37,6 +38,13 @@ Sql.prototype.functionCallCreator = function(name) {
3738
};
3839
};
3940

41+
// Returns a bracketed call creator literal
42+
Sql.prototype.array = function() {
43+
var arrayCall = new ArrayCall(sliced(arguments));
44+
arrayCall.sql = this;
45+
return arrayCall;
46+
};
47+
4048
// Returns a select statement
4149
Sql.prototype.select = function() {
4250
var query = new Query({sql: this});

lib/node/arrayCall.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
var _ = require('lodash');
4+
var Node = require(__dirname);
5+
var ParameterNode = require(__dirname + '/parameter');
6+
var valueExpressionMixin = require(__dirname + '/valueExpression');
7+
8+
var ArrayCallNode = Node.define({
9+
type: 'ARRAY CALL',
10+
constructor: function(args) {
11+
Node.call(this);
12+
args = _.flatten(args);
13+
this.addAll(args.map(ParameterNode.getNodeOrParameterNode));
14+
}
15+
});
16+
17+
// mix in value expression
18+
_.extend(ArrayCallNode.prototype, valueExpressionMixin());
19+
20+
// allow aliasing
21+
var AliasNode = require(__dirname + '/alias');
22+
_.extend(ArrayCallNode.prototype, AliasNode.AliasMixin);
23+
24+
module.exports = ArrayCallNode;

lib/node/at.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 AtNode = Node.define({
9+
type: 'AT',
10+
constructor: function(value, index) {
11+
Node.call(this);
12+
this.value = value;
13+
this.index = index;
14+
// Delay mixin to runtime, when all nodes have been defined, and
15+
// mixin only once. ValueExpressionMixin has circular dependencies.
16+
if (!valueExpressionMixed) {
17+
valueExpressionMixed = true;
18+
_.extend(AtNode.prototype, valueExpressionMixin());
19+
}
20+
}
21+
});
22+
23+
// allow aliasing
24+
var AliasNode = require(__dirname + '/alias');
25+
_.extend(AtNode.prototype, AliasNode.AliasMixin);
26+
27+
module.exports = AtNode;

lib/node/slice.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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 SliceNode = Node.define({
9+
type: 'SLICE',
10+
constructor: function(value, start, end) {
11+
Node.call(this);
12+
this.value = value;
13+
this.start = start;
14+
this.end = end;
15+
// Delay mixin to runtime, when all nodes have been defined, and
16+
// mixin only once. ValueExpressionMixin has circular dependencies.
17+
if (!valueExpressionMixed) {
18+
valueExpressionMixed = true;
19+
_.extend(SliceNode.prototype, valueExpressionMixin());
20+
}
21+
}
22+
});
23+
24+
// allow aliasing
25+
var AliasNode = require(__dirname + '/alias');
26+
_.extend(SliceNode.prototype, AliasNode.AliasMixin);
27+
28+
module.exports = SliceNode;

lib/node/valueExpression.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ var ValueExpressionMixin = function() {
1717
var CastNode = require('./cast');
1818
var PostfixUnaryNode = require('./postfixUnary');
1919
var TernaryNode = require('./ternary');
20+
var AtNode = require('./at');
21+
var SliceNode = require('./slice');
2022

2123
var postfixUnaryMethod = function(operator) {
2224
/*jshint unused: false */
@@ -50,6 +52,14 @@ var ValueExpressionMixin = function() {
5052
};
5153
};
5254

55+
var atMethod = function(index) {
56+
return new AtNode(this.toNode(), processParams(index));
57+
};
58+
59+
var sliceMethod = function(start, end) {
60+
return new SliceNode(this.toNode(), processParams(start), processParams(end));
61+
};
62+
5363
var castMethod = function(dataType) {
5464
return new CastNode(this.toNode(), dataType);
5565
};
@@ -87,11 +97,15 @@ var ValueExpressionMixin = function() {
8797
bitwiseNot : binaryMethod('~'),
8898
bitwiseOr : binaryMethod('|'),
8999
bitwiseXor : binaryMethod('#'),
100+
concat : binaryMethod('||'),
101+
key : binaryMethod('->'),
90102
like : binaryMethod('LIKE'),
91103
notLike : binaryMethod('NOT LIKE'),
92104
in : binaryMethod('IN'),
93105
notIn : binaryMethod('NOT IN'),
94106
between : ternaryMethod('BETWEEN', 'AND'),
107+
at : atMethod,
108+
slice : sliceMethod,
95109
cast : castMethod,
96110
descending : orderMethod('DESC')
97111
};

0 commit comments

Comments
 (0)