Skip to content

Commit edf05de

Browse files
authored
Merge pull request #212 from strongloop/refactor-discovery
Refactor discovery models
2 parents 6e33b93 + c6922c8 commit edf05de

File tree

2 files changed

+53
-106
lines changed

2 files changed

+53
-106
lines changed

lib/discovery.js

Lines changed: 39 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module.exports = mixinDiscovery;
1111
function mixinDiscovery(PostgreSQL) {
1212
var async = require('async');
1313

14-
function paginateSQL(sql, orderBy, options) {
14+
PostgreSQL.prototype.paginateSQL = function(sql, orderBy, options) {
1515
options = options || {};
1616
var limit = '';
1717
if (options.offset || options.skip || options.limit) {
@@ -24,102 +24,72 @@ function mixinDiscovery(PostgreSQL) {
2424
sql += ' ORDER BY ' + orderBy;
2525
}
2626
return sql + limit;
27-
}
27+
};
2828

2929
/*!
3030
* Build sql for listing tables
3131
* @param options {all: for all owners, owner: for a given owner}
3232
* @returns {string} The sql statement
3333
*/
34-
function queryTables(options) {
34+
PostgreSQL.prototype.buildQueryTables = function(options) {
3535
var sqlTables = null;
3636
var owner = options.owner || options.schema;
3737

3838
if (options.all && !owner) {
39-
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
39+
sqlTables = this.paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
4040
+ ' FROM information_schema.tables', 'table_schema, table_name', options);
4141
} else if (owner) {
42-
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
42+
sqlTables = this.paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
4343
+ ' FROM information_schema.tables WHERE table_schema=\'' + owner + '\'', 'table_schema, table_name', options);
4444
} else {
45-
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name",'
45+
sqlTables = this.paginateSQL('SELECT \'table\' AS "type", table_name AS "name",'
4646
+ ' table_schema AS "owner" FROM information_schema.tables WHERE table_schema=current_schema()',
4747
'table_name', options);
4848
}
4949
return sqlTables;
50-
}
50+
};
5151

5252
/*!
5353
* Build sql for listing views
5454
* @param options {all: for all owners, owner: for a given owner}
5555
* @returns {string} The sql statement
5656
*/
57-
function queryViews(options) {
57+
PostgreSQL.prototype.buildQueryViews = function(options) {
5858
var sqlViews = null;
5959
if (options.views) {
6060
var owner = options.owner || options.schema;
6161

6262
if (options.all && !owner) {
63-
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
63+
sqlViews = this.paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
6464
+ ' table_schema AS "owner" FROM information_schema.views',
6565
'table_schema, table_name', options);
6666
} else if (owner) {
67-
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
67+
sqlViews = this.paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
6868
+ ' table_schema AS "owner" FROM information_schema.views WHERE table_schema=\'' + owner + '\'',
6969
'table_schema, table_name', options);
7070
} else {
71-
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
71+
sqlViews = this.paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
7272
+ ' current_schema() AS "owner" FROM information_schema.views',
7373
'table_name', options);
7474
}
7575
}
7676
return sqlViews;
77-
}
77+
};
7878

7979
/**
8080
* Discover model definitions
8181
*
8282
* @param {Object} options Options for discovery
8383
* @param {Function} [cb] The callback function
8484
*/
85-
PostgreSQL.prototype.discoverModelDefinitions = function(options, cb) {
86-
if (!cb && typeof options === 'function') {
87-
cb = options;
88-
options = {};
89-
}
90-
options = options || {};
91-
92-
var self = this;
93-
var calls = [function(callback) {
94-
self.execute(queryTables(options), callback);
95-
}];
96-
97-
if (options.views) {
98-
calls.push(function(callback) {
99-
self.execute(queryViews(options), callback);
100-
});
101-
}
102-
async.parallel(calls, function(err, data) {
103-
if (err) {
104-
cb(err, data);
105-
} else {
106-
var merged = [];
107-
merged = merged.concat(data.shift());
108-
if (data.length) {
109-
merged = merged.concat(data.shift());
110-
}
111-
cb(err, merged);
112-
}
113-
});
114-
};
11585

11686
/*!
11787
* Normalize the arguments
11888
* @param table string, required
11989
* @param options object, optional
12090
* @param cb function, optional
12191
*/
122-
function getArgs(table, options, cb) {
92+
PostgreSQL.prototype.getArgs = function(table, options, cb) {
12393
if ('string' !== typeof table || !table) {
12494
throw new Error(g.f('{{table}} is a required string argument: %s' + table));
12595
}
@@ -133,38 +103,40 @@ function mixinDiscovery(PostgreSQL) {
133103
}
134104
return {
135105
owner: options.owner || options.schema,
106+
schema: options.owner || options.schema,
136107
table: table,
137108
options: options,
138109
cb: cb,
139110
};
140-
}
111+
};
141112

142113
/*!
143114
* Build the sql statement to query columns for a given table
144115
* @param owner
145116
* @param table
146117
* @returns {String} The sql statement
147118
*/
148-
function queryColumns(owner, table) {
119+
PostgreSQL.prototype.buildQueryColumns = function(owner, table) {
149120
var sql = null;
150121
if (owner) {
151-
sql = paginateSQL('SELECT table_schema AS "owner", table_name AS "tableName", column_name AS "columnName",'
122+
sql = this.paginateSQL('SELECT table_schema AS "owner", table_name AS "tableName", column_name AS "columnName",'
152123
+ 'data_type AS "dataType", character_maximum_length AS "dataLength", numeric_precision AS "dataPrecision",'
153124
+ ' numeric_scale AS "dataScale", is_nullable AS "nullable"'
154125
+ ' FROM information_schema.columns'
155126
+ ' WHERE table_schema=\'' + owner + '\''
156127
+ (table ? ' AND table_name=\'' + table + '\'' : ''),
157128
'table_name, ordinal_position', {});
158129
} else {
159-
sql = paginateSQL('SELECT current_schema() AS "owner", table_name AS "tableName", column_name AS "columnName",'
130+
sql = this.paginateSQL('SELECT current_schema() AS "owner", table_name AS "tableName",'
131+
+ ' column_name AS "columnName",'
160132
+ ' data_type AS "dataType", character_maximum_length AS "dataLength", numeric_precision AS "dataPrecision",'
161133
+ ' numeric_scale AS "dataScale", is_nullable AS "nullable"'
162134
+ ' FROM information_schema.columns'
163135
+ (table ? ' WHERE table_name=\'' + table + '\'' : ''),
164136
'table_name, ordinal_position', {});
165137
}
166138
return sql;
167-
}
139+
};
168140

169141
/**
170142
* Discover model properties from a table
@@ -173,26 +145,6 @@ function mixinDiscovery(PostgreSQL) {
173145
* @param {Function} [cb] The callback function
174146
*
175147
*/
176-
PostgreSQL.prototype.discoverModelProperties = function(table, options, cb) {
177-
var args = getArgs(table, options, cb);
178-
var owner = args.owner;
179-
table = args.table;
180-
options = args.options;
181-
cb = args.cb;
182-
183-
var sql = queryColumns(owner, table);
184-
var callback = function(err, results) {
185-
if (err) {
186-
cb(err, results);
187-
} else {
188-
results.map(function(r) {
189-
r.type = mysqlDataTypeToJSONType(r.dataType, r.dataLength);
190-
});
191-
cb(err, results);
192-
}
193-
};
194-
this.execute(sql, callback);
195-
};
196148

197149
// http://docs.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String)
198150

@@ -212,7 +164,7 @@ function mixinDiscovery(PostgreSQL) {
212164
* @param table
213165
* @returns {string}
214166
*/
215-
function queryForPrimaryKeys(owner, table) {
167+
PostgreSQL.prototype.buildQueryPrimaryKeys = function(owner, table) {
216168
var sql = 'SELECT kc.table_schema AS "owner", '
217169
+ 'kc.table_name AS "tableName", kc.column_name AS "columnName",'
218170
+ ' kc.ordinal_position AS "keySeq",'
@@ -231,24 +183,14 @@ function mixinDiscovery(PostgreSQL) {
231183
}
232184
sql += ' ORDER BY kc.table_schema, kc.table_name, kc.ordinal_position';
233185
return sql;
234-
}
186+
};
235187

236188
/**
237189
* Discover primary keys for a given table
238190
* @param {String} table The table name
239191
* @param {Object} options The options for discovery
240192
* @param {Function} [cb] The callback function
241193
*/
242-
PostgreSQL.prototype.discoverPrimaryKeys = function(table, options, cb) {
243-
var args = getArgs(table, options, cb);
244-
var owner = args.owner;
245-
table = args.table;
246-
options = args.options;
247-
cb = args.cb;
248-
249-
var sql = queryForPrimaryKeys(owner, table);
250-
this.execute(sql, cb);
251-
};
252194

253195
/*
254196
SELECT
@@ -270,7 +212,7 @@ function mixinDiscovery(PostgreSQL) {
270212
* @param table
271213
* @returns {string}
272214
*/
273-
function queryForeignKeys(owner, table) {
215+
PostgreSQL.prototype.buildQueryForeignKeys = function(owner, table) {
274216
var sql =
275217
'SELECT tc.table_schema AS "fkOwner", tc.constraint_name AS "fkName", tc.table_name AS "fkTableName",'
276218
+ ' kcu.column_name AS "fkColumnName", kcu.ordinal_position AS "keySeq",'
@@ -289,24 +231,14 @@ function mixinDiscovery(PostgreSQL) {
289231
sql += ' AND tc.table_name=\'' + table + '\'';
290232
}
291233
return sql;
292-
}
234+
};
293235

294236
/**
295237
* Discover foreign keys for a given table
296238
* @param {String} table The table name
297239
* @param {Object} options The options for discovery
298240
* @param {Function} [cb] The callback function
299241
*/
300-
PostgreSQL.prototype.discoverForeignKeys = function(table, options, cb) {
301-
var args = getArgs(table, options, cb);
302-
var owner = args.owner;
303-
table = args.table;
304-
options = args.options;
305-
cb = args.cb;
306-
307-
var sql = queryForeignKeys(owner, table);
308-
this.execute(sql, cb);
309-
};
310242

311243
/*!
312244
* Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
@@ -315,7 +247,7 @@ function mixinDiscovery(PostgreSQL) {
315247
* @param table
316248
* @returns {string}
317249
*/
318-
function queryExportedForeignKeys(owner, table) {
250+
PostgreSQL.prototype.buildQueryExportedForeignKeys = function(owner, table) {
319251
var sql = 'SELECT kcu.constraint_name AS "fkName", kcu.table_schema AS "fkOwner", kcu.table_name AS "fkTableName",'
320252
+ ' kcu.column_name AS "fkColumnName", kcu.ordinal_position AS "keySeq",'
321253
+ ' \'PK\' AS "pkName", ccu.table_schema AS "pkOwner",'
@@ -334,26 +266,17 @@ function mixinDiscovery(PostgreSQL) {
334266
sql += ' order by kcu.table_schema, kcu.table_name, kcu.ordinal_position';
335267

336268
return sql;
337-
}
269+
};
338270

339271
/**
340272
* Discover foreign keys that reference to the primary key of this table
341273
* @param {String} table The table name
342274
* @param {Object} options The options for discovery
343275
* @param {Function} [cb] The callback function
344276
*/
345-
PostgreSQL.prototype.discoverExportedForeignKeys = function(table, options, cb) {
346-
var args = getArgs(table, options, cb);
347-
var owner = args.owner;
348-
table = args.table;
349-
options = args.options;
350-
cb = args.cb;
351277

352-
var sql = queryExportedForeignKeys(owner, table);
353-
this.execute(sql, cb);
354-
};
355-
356-
function mysqlDataTypeToJSONType(mysqlType, dataLength) {
278+
PostgreSQL.prototype.buildPropertyType = function(columnDefinition, dataLength) {
279+
var mysqlType = columnDefinition.dataType;
357280
var type = mysqlType.toUpperCase();
358281
switch (type) {
359282
case 'BOOLEAN':
@@ -384,7 +307,7 @@ function mixinDiscovery(PostgreSQL) {
384307
default:
385308
return 'String';
386309
}
387-
}
310+
};
388311

389312
/**
390313
* Discover database indexes for the specified table
@@ -401,4 +324,14 @@ function mixinDiscovery(PostgreSQL) {
401324
cb(err, indexData);
402325
});
403326
};
327+
328+
PostgreSQL.prototype.setDefaultOptions = function(options) {
329+
};
330+
331+
PostgreSQL.prototype.setNullableProperty = function(property) {
332+
};
333+
334+
PostgreSQL.prototype.getDefaultSchema = function() {
335+
return '';
336+
};
404337
}

test/postgresql.discover.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,17 @@ before(function() {
1919
});
2020

2121
describe('discoverModels', function() {
22+
describe('Discover database schemas', function() {
23+
it('should return an array of db schemas', function(done) {
24+
db.connector.discoverDatabaseSchemas(function(err, schemas) {
25+
if (err) return done(err);
26+
schemas.should.be.an.array;
27+
schemas.length.should.be.above(0);
28+
done();
29+
});
30+
});
31+
});
32+
2233
describe('Discover models including views', function() {
2334
it('should return an array of tables and views', function(done) {
2435
db.discoverModelDefinitions({
@@ -181,6 +192,8 @@ describe('Discover model foreign keys', function() {
181192
describe('Discover LDL schema from a table', function() {
182193
it('should return an LDL schema for inventory', function(done) {
183194
db.discoverSchema('inventory', {owner: 'strongloop'}, function(err, schema) {
195+
console.log('This is our err: ', err);
196+
console.log('This is our schema: ', schema);
184197
assert(schema.name === 'Inventory');
185198
assert(schema.options.postgresql.schema === 'strongloop');
186199
assert(schema.options.postgresql.table === 'inventory');
@@ -203,6 +216,7 @@ describe('Discover and build models', function() {
203216
it('should build a model from discovery', function(done) {
204217
db.discoverAndBuildModels('GeoPoint', {schema: 'strongloop'}, function(err, schema) {
205218
schema.Geopoint.find(function(err, data) {
219+
console.log('This is our err: ', err);
206220
assert(!err);
207221
assert(Array.isArray(data));
208222
assert(data[0].location);

0 commit comments

Comments
 (0)