Add support to discover related schemas by foreign keys
This commit is contained in:
parent
ad14bd9dbc
commit
2d62b5ba6a
|
@ -415,100 +415,152 @@ function fromDBName(dbName, camelCase) {
|
|||
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
|
||||
* @param owner
|
||||
* @param table
|
||||
* @param cb
|
||||
*/
|
||||
DataSource.prototype.discoverSchema = function (owner, table, cb) {
|
||||
DataSource.prototype.discoverSchemas = function (owner, table, options, cb) {
|
||||
var self = this;
|
||||
var dataSourceName = this.name || this.adapter.name;
|
||||
|
||||
async.parallel(
|
||||
[
|
||||
this.discoverModelProperties.bind(this, owner, table),
|
||||
this.discoverPrimaryKeys.bind(this, owner, table),
|
||||
this.discoverForeignKeys.bind(this, owner, table)
|
||||
], function (err, results) {
|
||||
var tasks = [
|
||||
this.discoverModelProperties.bind(this, owner, table),
|
||||
this.discoverPrimaryKeys.bind(this, owner, table) ];
|
||||
|
||||
if (err) {
|
||||
cb && cb(err);
|
||||
return;
|
||||
if (options.associations) {
|
||||
tasks.push(this.discoverForeignKeys.bind(this, owner, table));
|
||||
}
|
||||
|
||||
async.parallel(tasks, function (err, results) {
|
||||
|
||||
if (err) {
|
||||
cb && cb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var columns = results[0];
|
||||
if (!columns) {
|
||||
cb && cb();
|
||||
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 = {
|
||||
name: fromDBName(table, false),
|
||||
options: {
|
||||
idInjection: false // DO NOT add id property
|
||||
},
|
||||
properties: {
|
||||
}
|
||||
};
|
||||
|
||||
var columns = results[0];
|
||||
var primaryKeys = results[1];
|
||||
var pks = {}, fks = {};
|
||||
primaryKeys.forEach(function(pk) {
|
||||
pks[pk.columnName] = pk.keySeq;
|
||||
});
|
||||
schema.options[dataSourceName] = {
|
||||
schema: columns[0].owner,
|
||||
table: table
|
||||
};
|
||||
|
||||
columns.forEach(function (item) {
|
||||
var i = item;
|
||||
|
||||
var propName = fromDBName(item.columnName, true);
|
||||
schema.properties[propName] = {
|
||||
type: item.type,
|
||||
required: (item.nullable === 'N'),
|
||||
length: item.dataLength
|
||||
};
|
||||
|
||||
if (pks[item.columnName]) {
|
||||
schema.properties[propName].id = pks[item.columnName];
|
||||
}
|
||||
schema.properties[propName][dataSourceName] = {
|
||||
columnName: i.columnName,
|
||||
dataType: i.dataType,
|
||||
dataLength: i.dataLength,
|
||||
nullable: i.nullable
|
||||
};
|
||||
});
|
||||
|
||||
// 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('Primary keys: ', pks);
|
||||
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];
|
||||
}
|
||||
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) {
|
||||
if (self.settings.debug) {
|
||||
console.log('Foreign keys: ', fks);
|
||||
}
|
||||
|
||||
if (!columns) {
|
||||
cb && cb();
|
||||
return;
|
||||
}
|
||||
var schema = {
|
||||
name: fromDBName(table, false),
|
||||
options: {
|
||||
idInjection: false // DO NOT add id property
|
||||
},
|
||||
properties: {
|
||||
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};
|
||||
}
|
||||
};
|
||||
|
||||
schema.options[dataSourceName] = {
|
||||
schema: owner,
|
||||
table: table
|
||||
};
|
||||
columns.forEach(function (item) {
|
||||
var i = item;
|
||||
|
||||
|
||||
var propName = fromDBName(item.columnName, true);
|
||||
schema.properties[propName] =
|
||||
{
|
||||
type: item.type,
|
||||
required: (item.nullable === 'N'),
|
||||
length: item.dataLength
|
||||
};
|
||||
|
||||
if(pks[item.columnName]) {
|
||||
schema.properties[propName].id = pks[item.columnName];
|
||||
}
|
||||
schema.properties[propName][dataSourceName] = {
|
||||
columnName: i.columnName,
|
||||
dataType: i.dataType,
|
||||
dataLength: i.dataLength,
|
||||
nullable: i.nullable
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
cb && cb(null, schema);
|
||||
});
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue