1 | 'use strict';
|
2 |
|
3 | var util = require('util');
|
4 | var lodash = require('lodash');
|
5 |
|
6 | var Query = require('./node/query');
|
7 | var Column = require('./column');
|
8 | var TableNode = require('./node/table');
|
9 | var JoinNode = require('./node/join');
|
10 | var LiteralNode = require('./node/literal');
|
11 | var Joiner = require('./joiner');
|
12 | var ForeignKeyNode = require('./node/foreignKey');
|
13 |
|
14 | var Table = function(config) {
|
15 | this._schema = config.schema;
|
16 | this._name = config.name;
|
17 | this._initialConfig = config;
|
18 | this.columnWhiteList = !!config.columnWhiteList;
|
19 | this.isTemporary=!!config.isTemporary;
|
20 | this.snakeToCamel = !!config.snakeToCamel;
|
21 | this.columns = [];
|
22 | this.foreignKeys = [];
|
23 | this.table = this;
|
24 | if (!config.sql) {
|
25 | config.sql = require('./index');
|
26 | }
|
27 | this.sql = config.sql;
|
28 | };
|
29 |
|
30 | Table.define = function(config) {
|
31 | var table = new Table(config);
|
32 |
|
33 | if (config.columns && !util.isArray(config.columns)) {
|
34 | var cols = [];
|
35 |
|
36 | for (var key in config.columns) {
|
37 | if (config.columns.hasOwnProperty(key)) {
|
38 | var col = config.columns[key];
|
39 | col.name = key;
|
40 | cols.push(col);
|
41 | }
|
42 | }
|
43 |
|
44 | config.columns = cols;
|
45 | }
|
46 |
|
47 | for (var i = 0; i < config.columns.length; i++) {
|
48 | table.addColumn(config.columns[i]);
|
49 | }
|
50 |
|
51 | if(config.foreignKeys !== undefined) {
|
52 | if(util.isArray(config.foreignKeys)) {
|
53 | for(i = 0; i < config.foreignKeys.length; i++) {
|
54 | table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys[i]));
|
55 | }
|
56 | } else {
|
57 | table.foreignKeys.push(new ForeignKeyNode(config.foreignKeys));
|
58 | }
|
59 | }
|
60 | return table;
|
61 | };
|
62 |
|
63 | Table.prototype.clone = function(config) {
|
64 | return Table.define(lodash.extend({
|
65 | schema: this._schema,
|
66 | name: this._name,
|
67 | sql: this.sql,
|
68 | columnWhiteList: !!this.columnWhiteList,
|
69 | snakeToCamel: !!this.snakeToCamel,
|
70 | columns: this.columns,
|
71 | foreignKeys: this.foreignKeys
|
72 | }, config || {}));
|
73 | };
|
74 |
|
75 | Table.prototype.createColumn = function(col) {
|
76 | if(!(col instanceof Column)) {
|
77 | if(typeof col === 'string') {
|
78 | col = { name: col };
|
79 | }
|
80 |
|
81 | col.table = this;
|
82 | col = new Column(col);
|
83 |
|
84 |
|
85 | if(util.isArray(col.subfields)) {
|
86 | col.subfields = lodash.chain(col.subfields)
|
87 | .map(lodash.bind(function (subfield) {
|
88 | return [subfield, new Column({
|
89 | table: this,
|
90 | subfieldContainer: col,
|
91 | name: subfield
|
92 | })];
|
93 | }, this))
|
94 | .fromPairs()
|
95 | .value();
|
96 | }
|
97 | }
|
98 |
|
99 | return col;
|
100 | };
|
101 |
|
102 | Table.prototype.addColumn = function(col, options) {
|
103 | col = this.createColumn(col);
|
104 | options = lodash.extend({
|
105 | noisy: true
|
106 | }, options || {});
|
107 |
|
108 | if(this.hasColumn(col)) {
|
109 | if (options.noisy) {
|
110 | throw new Error('Table ' + this._name + ' already has column or property by the name of ' + col.name);
|
111 | } else {
|
112 | return this;
|
113 | }
|
114 | } else if(!!this[col.name] && (process.env.NODE_ENV === 'debug')) {
|
115 | console.log('Please notice that you have just defined the column "' + col.name + '". In order to access it, you need to use "table.getColumn(\'' + col.name + '\');"!');
|
116 | }
|
117 | this.columns.push(col);
|
118 |
|
119 | function snakeToCamel(snakeName) {
|
120 | return snakeName.replace(/[\-_]([a-z])/g, function(m, $1){ return $1.toUpperCase(); });
|
121 | }
|
122 |
|
123 | var property = col.property = col.property || (this.snakeToCamel ? snakeToCamel(col.name) : col.name);
|
124 | this[property] = this[property] || col;
|
125 | return this;
|
126 | };
|
127 |
|
128 | Table.prototype.hasColumn = function(col) {
|
129 | var columnName = col instanceof Column ? col.name : col;
|
130 | return this.columns.some(function(column) {
|
131 | return column.property === columnName || column.name === columnName;
|
132 | });
|
133 | };
|
134 |
|
135 | Table.prototype.getColumn =
|
136 | Table.prototype.get =
|
137 | function(colName) {
|
138 | for(var i = 0; i < this.columns.length; i++) {
|
139 | var col = this.columns[i];
|
140 | if (colName === col.property || colName === col.name) {
|
141 | return col;
|
142 | }
|
143 | }
|
144 | if(this.columnWhiteList)
|
145 | return null;
|
146 | throw new Error('Table ' + this._name + ' does not have a column or property named ' + colName);
|
147 | };
|
148 |
|
149 | Table.prototype.getSchema = function() {
|
150 | return this._schema;
|
151 | };
|
152 |
|
153 | Table.prototype.setSchema = function(schema) {
|
154 | this._schema = schema;
|
155 | };
|
156 |
|
157 | Table.prototype.getName = function() {
|
158 | if (this.sql && this.sql.dialectName=="mssql" && this.isTemporary) return "#"+this._name;
|
159 | return this._name;
|
160 | };
|
161 |
|
162 | Table.prototype.star = function(options) {
|
163 | options = options || {};
|
164 | if (options.prefix) {
|
165 | return this.columns.map(function(column) {
|
166 | return this[column.name].as(options.prefix + column.name);
|
167 | }.bind(this));
|
168 | }
|
169 |
|
170 | return new Column({table: this, star: true});
|
171 | };
|
172 |
|
173 | Table.prototype.literal = function(literal) {
|
174 | return new LiteralNode(literal);
|
175 | };
|
176 |
|
177 | Table.prototype.count = function(alias) {
|
178 | var name = this.alias || this._name,
|
179 | col = new Column({table: this, star: true});
|
180 |
|
181 | return col.count(alias || name + '_count');
|
182 | };
|
183 |
|
184 | Table.prototype.select = function() {
|
185 |
|
186 | var query = new Query(this);
|
187 | if (arguments.length === 0) {
|
188 | query.select.call(query, this.star());
|
189 | } else {
|
190 | query.select.apply(query, arguments);
|
191 | }
|
192 | return query;
|
193 | };
|
194 |
|
195 | Table.prototype.subQuery = function(alias) {
|
196 |
|
197 | var query = new Query(this);
|
198 | query.type = 'SUBQUERY';
|
199 | query.alias = alias;
|
200 | query.join = function(other) {
|
201 | return new JoinNode('INNER', this.toNode(), other.toNode(), other);
|
202 | };
|
203 | return query;
|
204 | };
|
205 |
|
206 | Table.prototype.insert = function() {
|
207 | var query = new Query(this);
|
208 | if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){
|
209 | query.select.call(query, this.star());
|
210 | query.where.apply(query,["1=2"]);
|
211 | } else {
|
212 | query.insert.apply(query, arguments);
|
213 | }
|
214 | return query;
|
215 | };
|
216 |
|
217 | Table.prototype.replace = function() {
|
218 | var query = new Query(this);
|
219 | if(!arguments[0] || (util.isArray(arguments[0]) && arguments[0].length === 0)){
|
220 | query.select.call(query, this.star());
|
221 | query.where.apply(query,["1=2"]);
|
222 | } else {
|
223 | query.replace.apply(query, arguments);
|
224 | }
|
225 | return query;
|
226 | };
|
227 |
|
228 | Table.prototype.toNode = function() {
|
229 | return new TableNode(this);
|
230 | };
|
231 |
|
232 | Table.prototype.join = function(other) {
|
233 | return new JoinNode('INNER', this.toNode(), other.toNode(), other);
|
234 | };
|
235 |
|
236 | Table.prototype.leftJoin = function(other) {
|
237 | return new JoinNode('LEFT', this.toNode(), other.toNode());
|
238 | };
|
239 |
|
240 |
|
241 | Table.prototype.joinTo = function(other) {
|
242 | return Joiner.leftJoin(this, other);
|
243 | };
|
244 |
|
245 | Table.prototype.as = function(alias) {
|
246 |
|
247 | var t = Table.define(this._initialConfig);
|
248 | t.alias = alias;
|
249 | return t;
|
250 | };
|
251 |
|
252 |
|
253 | Table.prototype.__defineGetter__("nodes", function() {
|
254 | return this.select(this.star()).nodes;
|
255 | });
|
256 |
|
257 | Table.prototype.and = function() {
|
258 | var query = new Query(this);
|
259 | query.where.apply(query, arguments);
|
260 | return query;
|
261 | };
|
262 |
|
263 | Table.prototype.indexes = function() {
|
264 | return new Query(this).indexes();
|
265 | };
|
266 |
|
267 | var queryMethods = [
|
268 | 'alter',
|
269 | 'create',
|
270 | 'delete',
|
271 | 'drop',
|
272 | 'from',
|
273 | 'limit',
|
274 | 'offset',
|
275 | 'or',
|
276 | 'order',
|
277 | 'truncate',
|
278 | 'update',
|
279 | 'where'
|
280 | ];
|
281 |
|
282 | queryMethods.forEach(function (method) {
|
283 | Table.prototype[method] = function () {
|
284 | var query = new Query(this);
|
285 | query[method].apply(query, arguments);
|
286 | return query;
|
287 | };
|
288 | });
|
289 |
|
290 | module.exports = Table;
|