Skip to content

Commit b5fc980

Browse files
committed
Merge pull request #259 from edudutra/create-view
Adds Create View Support - closes #245
2 parents 2df38f8 + ac98e77 commit b5fc980

4 files changed

Lines changed: 133 additions & 3 deletions

File tree

lib/dialect/postgres.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,20 @@ Postgres.prototype.getQuery = function(queryNode) {
7171
queryNode = queryNode.select(queryNode.star());
7272
}
7373
this.output = this.visit(queryNode);
74-
74+
75+
//if is a create view, must replace paramaters with values
76+
if (this.output.indexOf('CREATE VIEW') > -1) {
77+
var previousFlagStatus = this._disableParameterPlaceholders;
78+
this._disableParameterPlaceholders = true;
79+
this.output = [];
80+
this.output = this.visit(queryNode);
81+
this.params = [];
82+
this._disableParameterPlaceholders = previousFlagStatus;
83+
}
84+
7585
// create the query object
7686
var query = { text: this.output.join(' '), values: this.params };
77-
87+
7888
// reset the internal state of this builder
7989
this.output = [];
8090
this.params = [];
@@ -143,7 +153,8 @@ Postgres.prototype.visit = function(node) {
143153
case 'DROP INDEX' : return this.visitDropIndex(node);
144154
case 'FUNCTION CALL' : return this.visitFunctionCall(node);
145155
case 'ARRAY CALL' : return this.visitArrayCall(node);
146-
156+
case 'CREATE VIEW' : return this.visitCreateView(node);
157+
147158
case 'POSTFIX UNARY' : return this.visitPostfixUnary(node);
148159
case 'PREFIX UNARY' : return this.visitPrefixUnary(node);
149160
case 'BINARY' : return this.visitBinary(node);
@@ -568,13 +579,16 @@ Postgres.prototype.visitQuery = function(queryNode) {
568579
// so select/insert/update/delete comes before from comes before where
569580
var missingFrom = true;
570581
var hasFrom = false;
582+
var createView;
583+
var isSelect = false;
571584
var actions = [];
572585
var targets = [];
573586
var filters = [];
574587
for(var i = 0; i < queryNode.nodes.length; i++) {
575588
var node = queryNode.nodes[i];
576589
switch(node.type) {
577590
case "SELECT":
591+
isSelect = true;
578592
case "DELETE":
579593
actions.push(node);
580594
break;
@@ -594,6 +608,9 @@ Postgres.prototype.visitQuery = function(queryNode) {
594608
missingFrom = false;
595609
targets.push(node);
596610
break;
611+
case "CREATE VIEW":
612+
createView = node;
613+
break;
597614
default:
598615
filters.push(node);
599616
break;
@@ -602,10 +619,18 @@ Postgres.prototype.visitQuery = function(queryNode) {
602619
if(!actions.length) {
603620
// if no actions are given, guess it's a select
604621
actions.push(new Select().add('*'));
622+
isSelect = true;
605623
}
606624
if(missingFrom) {
607625
targets.push(new From().add(queryNode.table));
608626
}
627+
if (createView) {
628+
if (isSelect) {
629+
actions.unshift(createView);
630+
} else {
631+
throw new Error('Create View requires a Select.');
632+
}
633+
}
609634
return this.visitQueryHelper(actions,targets,filters)
610635
};
611636

@@ -947,6 +972,12 @@ Postgres.prototype.visitDropIndex = function(node) {
947972
return result;
948973
};
949974

975+
Postgres.prototype.visitCreateView = function(createView) {
976+
//console.log('createView: ' + createView);
977+
var result = ['CREATE VIEW', this.quote(createView.options.viewName), 'AS'];
978+
return result;
979+
};
980+
950981
/**
951982
* Broken out as a separate function so that dialects that derive from this class can still use this functionality.
952983
*

lib/node/createView.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict';
2+
3+
var Node = require(__dirname);
4+
5+
module.exports = Node.define({
6+
type: 'CREATE VIEW',
7+
8+
constructor: function(viewName) {
9+
Node.call(this);
10+
11+
this.options = { viewName: viewName};
12+
}
13+
});

lib/node/query.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var Indexes = require('./indexes');
3939
var CreateIndex = require('./createIndex');
4040
var DropIndex = require('./dropIndex');
4141
var Table = require('./table');
42+
var CreateView = require('./createView');
4243

4344
var Modifier = Node.define({
4445
constructor: function(table, type, count) {
@@ -460,6 +461,11 @@ var Query = Node.define({
460461
table: this.table
461462
});
462463
return this.add(this.indexesClause);
464+
},
465+
466+
createView: function(viewName) {
467+
this.add(new CreateView(viewName));
468+
return this;
463469
}
464470
});
465471

test/dialects/create-view-tests.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use strict';
2+
3+
var Harness = require('./support');
4+
var user = Harness.defineUserTable();
5+
6+
//simple view create
7+
Harness.test({
8+
query: user.select(user.star()).createView('allUsersView'),
9+
pg: {
10+
text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"',
11+
string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"'
12+
},
13+
sqlite: {
14+
text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"',
15+
string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"'
16+
},
17+
mysql: {
18+
text : 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`',
19+
string: 'CREATE VIEW `allUsersView` AS SELECT `user`.* FROM `user`'
20+
},
21+
mssql: {
22+
text : 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]',
23+
string: 'CREATE VIEW [allUsersView] AS SELECT [user].* FROM [user]'
24+
},
25+
oracle: {
26+
text : 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"',
27+
string: 'CREATE VIEW "allUsersView" AS SELECT "user".* FROM "user"'
28+
}
29+
});
30+
31+
//create view with parameters
32+
Harness.test({
33+
query: user.select(user.star()).where(user.id.equals(1)).createView('oneUserView'),
34+
pg: {
35+
text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)',
36+
string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)'
37+
},
38+
sqlite: {
39+
text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)',
40+
string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)'
41+
},
42+
mysql: {
43+
text : 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)',
44+
string: 'CREATE VIEW `oneUserView` AS SELECT `user`.* FROM `user` WHERE (`user`.`id` = 1)'
45+
},
46+
mssql: {
47+
text : 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)',
48+
string: 'CREATE VIEW [oneUserView] AS SELECT [user].* FROM [user] WHERE ([user].[id] = 1)'
49+
},
50+
oracle: {
51+
text : 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)',
52+
string: 'CREATE VIEW "oneUserView" AS SELECT "user".* FROM "user" WHERE ("user"."id" = 1)'
53+
}
54+
});
55+
56+
//Tests error raised for non-SELECT create view attempts
57+
Harness.test({
58+
query: user.delete().where(user.id.equals(1)).createView('oneUserView'),
59+
pg: {
60+
text : 'Create View requires a Select.',
61+
throws: true
62+
},
63+
sqlite: {
64+
text : 'Create View requires a Select.',
65+
throws: true
66+
},
67+
mysql: {
68+
text : 'Create View requires a Select.',
69+
throws: true
70+
},
71+
mssql: {
72+
text : 'Create View requires a Select.',
73+
throws: true
74+
},
75+
oracle: {
76+
text : 'Create View requires a Select.',
77+
throws: true
78+
},
79+
params: []
80+
});

0 commit comments

Comments
 (0)