Add support to discover related schemas by foreign keys

This commit is contained in:
Raymond Feng 2013-05-30 23:13:04 -07:00
parent ad14bd9dbc
commit 2d62b5ba6a
1 changed files with 121 additions and 69 deletions

View File

@ -415,22 +415,37 @@ function fromDBName(dbName, camelCase) {
return parts.join(''); return parts.join('');
} }
DataSource.prototype.discoverSchema = function (owner, table, cb) {
this.discoverSchemas(owner, table, {visited: {}, associations: false}, function(err, schemas) {
if(err) {
cb && cb(err, schemas);
return;
}
for(var s in schemas) {
cb && cb(null, schemas[s]);
return;
}
});
}
/** /**
* Discover schema from a given table/view * Discover schema from a given table/view
* @param owner * @param owner
* @param table * @param table
* @param cb * @param cb
*/ */
DataSource.prototype.discoverSchema = function (owner, table, cb) { DataSource.prototype.discoverSchemas = function (owner, table, options, cb) {
var self = this; var self = this;
var dataSourceName = this.name || this.adapter.name; var dataSourceName = this.name || this.adapter.name;
async.parallel( var tasks = [
[
this.discoverModelProperties.bind(this, owner, table), this.discoverModelProperties.bind(this, owner, table),
this.discoverPrimaryKeys.bind(this, owner, table), this.discoverPrimaryKeys.bind(this, owner, table) ];
this.discoverForeignKeys.bind(this, owner, table)
], function (err, results) { if (options.associations) {
tasks.push(this.discoverForeignKeys.bind(this, owner, table));
}
async.parallel(tasks, function (err, results) {
if (err) { if (err) {
cb && cb(err); cb && cb(err);
@ -438,39 +453,22 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
} }
var columns = results[0]; var columns = results[0];
var primaryKeys = results[1];
var pks = {}, fks = {};
primaryKeys.forEach(function(pk) {
pks[pk.columnName] = pk.keySeq;
});
if(self.settings.debug) {
console.log('Primary keys: ', pks);
}
var foreignKeys = results[2];
foreignKeys.forEach(function(fk) {
var fkInfo = {
keySeq: fk.keySeq,
owner: fk.pkOwner,
tableName: fk.pkTableName,
columnName: fk.pkColumnName
};
if(fks[fk.fkName]) {
fks[fk.fkName].push(fkInfo);
} else {
fks[fk.fkName] = [fkInfo];
}
});
if(self.settings.debug) {
console.log('Foreign keys: ', fks);
}
if (!columns) { if (!columns) {
cb && cb(); cb && cb();
return; return;
} }
// Handle primary keys
var primaryKeys = results[1];
var pks = {};
primaryKeys.forEach(function (pk) {
pks[pk.columnName] = pk.keySeq;
});
if (self.settings.debug) {
console.log('Primary keys: ', pks);
}
var schema = { var schema = {
name: fromDBName(table, false), name: fromDBName(table, false),
options: { options: {
@ -481,22 +479,21 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
}; };
schema.options[dataSourceName] = { schema.options[dataSourceName] = {
schema: owner, schema: columns[0].owner,
table: table table: table
}; };
columns.forEach(function (item) { columns.forEach(function (item) {
var i = item; var i = item;
var propName = fromDBName(item.columnName, true); var propName = fromDBName(item.columnName, true);
schema.properties[propName] = schema.properties[propName] = {
{
type: item.type, type: item.type,
required: (item.nullable === 'N'), required: (item.nullable === 'N'),
length: item.dataLength length: item.dataLength
}; };
if(pks[item.columnName]) { if (pks[item.columnName]) {
schema.properties[propName].id = pks[item.columnName]; schema.properties[propName].id = pks[item.columnName];
} }
schema.properties[propName][dataSourceName] = { schema.properties[propName][dataSourceName] = {
@ -507,7 +504,62 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
}; };
}); });
cb && cb(null, schema); // Add current table to the visited tables
options.visited = options.visited || {};
var schemaKey = columns[0].owner + '.' + table;
if (!options.visited.hasOwnProperty(schemaKey)) {
if(self.settings.debug) {
console.log('Adding schema for ' + schemaKey);
}
options.visited[schemaKey] = schema;
}
var otherTables = {};
if (options.associations) {
// Handle foreign keys
var fks = {};
var foreignKeys = results[2];
foreignKeys.forEach(function (fk) {
var fkInfo = {
keySeq: fk.keySeq,
owner: fk.pkOwner,
tableName: fk.pkTableName,
columnName: fk.pkColumnName
};
if (fks[fk.fkName]) {
fks[fk.fkName].push(fkInfo);
} else {
fks[fk.fkName] = [fkInfo];
}
});
if (self.settings.debug) {
console.log('Foreign keys: ', fks);
}
foreignKeys.forEach(function (fk) {
var key = fk.pkOwner + '.' + fk.pkTableName;
if (!options.visited.hasOwnProperty(key) && !otherTables.hasOwnProperty(key)) {
otherTables[key] = {owner: fk.pkOwner, tableName: fk.pkTableName};
}
});
}
if (Object.keys(otherTables).length === 0) {
cb && cb(null, options.visited);
} else {
var moreTasks = [];
for (var t in otherTables) {
if(self.settings.debug) {
console.log('Discovering related schema for ' + schemaKey);
}
moreTasks.push(DataSource.prototype.discoverSchemas.bind(self, otherTables[t].owner, otherTables[t].tableName, options));
}
async.parallel(moreTasks, function (err, results) {
var result = results && results[0];
cb && cb(err, result);
});
}
}); });
} }