Merge branch 'master' of github.com:strongloop/jugglingdb
This commit is contained in:
commit
1bb8047b57
|
@ -16,7 +16,7 @@ function loadSchemasSync(schemaFile, dataSource) {
|
|||
// Read the schema JSON file
|
||||
var schemas = JSON.parse(fs.readFileSync(schemaFile));
|
||||
|
||||
return DataSource.buildModels(dataSource, schemas);
|
||||
return dataSource.buildModels(schemas);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -415,21 +415,37 @@ 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(
|
||||
[
|
||||
var tasks = [
|
||||
this.discoverModelProperties.bind(this, owner, table),
|
||||
this.discoverPrimaryKeys.bind(this, owner, table),
|
||||
this.discoverForeignKeys.bind(this, owner, table)
|
||||
], function (err, results) {
|
||||
this.discoverPrimaryKeys.bind(this, owner, table) ];
|
||||
|
||||
if (options.associations) {
|
||||
tasks.push(this.discoverForeignKeys.bind(this, owner, table));
|
||||
}
|
||||
|
||||
async.parallel(tasks, function (err, results) {
|
||||
|
||||
if (err) {
|
||||
cb && cb(err);
|
||||
|
@ -437,30 +453,22 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
|
|||
}
|
||||
|
||||
var columns = results[0];
|
||||
var primaryKeys = results[1];
|
||||
var pks = {}, fks = {};
|
||||
primaryKeys.forEach(function(pk) {
|
||||
pks[pk.columnName] = pk.keySeq;
|
||||
});
|
||||
|
||||
console.log(pks);
|
||||
|
||||
var foreignKeys = results[2];
|
||||
foreignKeys.forEach(function(fk) {
|
||||
fks[fk.fkColumnName] = {
|
||||
keySeq: fk.keySeq,
|
||||
owner: fk.pkOwner,
|
||||
tableName: fk.pkTableName,
|
||||
columnName: fk.pkColumnName
|
||||
};
|
||||
});
|
||||
|
||||
console.log(fks);
|
||||
|
||||
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: {
|
||||
|
@ -471,16 +479,15 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
|
|||
};
|
||||
|
||||
schema.options[dataSourceName] = {
|
||||
schema: owner,
|
||||
schema: columns[0].owner,
|
||||
table: table
|
||||
};
|
||||
|
||||
columns.forEach(function (item) {
|
||||
var i = item;
|
||||
|
||||
|
||||
var propName = fromDBName(item.columnName, true);
|
||||
schema.properties[propName] =
|
||||
{
|
||||
schema.properties[propName] = {
|
||||
type: item.type,
|
||||
required: (item.nullable === 'N'),
|
||||
length: item.dataLength
|
||||
|
@ -492,11 +499,76 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) {
|
|||
schema.properties[propName][dataSourceName] = {
|
||||
columnName: i.columnName,
|
||||
dataType: i.dataType,
|
||||
dataLength: i.dataLength,
|
||||
nullable: i.nullable
|
||||
};
|
||||
});
|
||||
|
||||
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 propName = fromDBName(fk.pkTableName, true);
|
||||
schema.properties[propName] = {
|
||||
type: fromDBName(fk.pkTableName, false),
|
||||
association: {
|
||||
type: 'belongsTo',
|
||||
foreignKey: fromDBName(fk.pkColumnName, true)
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -609,9 +681,9 @@ DataSource.prototype.idColumnName = function(modelName) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Find the ID column name
|
||||
* Find the ID property name
|
||||
* @param modelName
|
||||
* @returns {String} columnName for ID
|
||||
* @returns {String} property for ID
|
||||
*/
|
||||
DataSource.prototype.idName = function(modelName) {
|
||||
var props = this.definitions[modelName].properties;
|
||||
|
@ -623,6 +695,28 @@ DataSource.prototype.idName = function(modelName) {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the ID property names sorted by the index
|
||||
* @param modelName
|
||||
* @returns {[String]} property names for IDs
|
||||
*/
|
||||
DataSource.prototype.idNames = function (modelName) {
|
||||
var ids = [];
|
||||
var props = this.definitions[modelName].properties;
|
||||
for (var key in props) {
|
||||
if (props[key].id && props[key].id > 0) {
|
||||
ids.push({name: key, id: props[key].id});
|
||||
}
|
||||
}
|
||||
ids.sort(function (a, b) {
|
||||
return a.key - b.key;
|
||||
});
|
||||
var names = ids.map(function (id) {
|
||||
return id.name;
|
||||
});
|
||||
return names;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Define foreign key
|
||||
|
|
|
@ -433,14 +433,13 @@ function buildSchema(name, properties, associations) {
|
|||
|
||||
/**
|
||||
* Build models from schema definitions
|
||||
* @param modelBuilder The model builder
|
||||
* @param schemas The schemas can be one of the following three formats:
|
||||
* 1. An array of named schema definition JSON objects
|
||||
* 2. A schema definition JSON object
|
||||
* 3. A list of property definitions (anonymous)
|
||||
* @returns {Object} A map of model constructors keyed by model name
|
||||
*/
|
||||
function buildModels(modelBuilder, schemas) {
|
||||
ModelBuilder.prototype.buildModels = function (schemas) {
|
||||
var models = {};
|
||||
|
||||
if (Array.isArray(schemas)) {
|
||||
|
@ -462,15 +461,15 @@ function buildModels(modelBuilder, schemas) {
|
|||
for (var s in schemas) {
|
||||
var name = schemas[s].name;
|
||||
var schema = buildSchema(name, schemas[s].properties, associations);
|
||||
var model = modelBuilder.define(name, schema);
|
||||
models[name.toLowerCase()] = model;
|
||||
var model = this.define(name, schema);
|
||||
models[name] = model;
|
||||
}
|
||||
|
||||
// Connect the models based on the associations
|
||||
for (var i = 0; i < associations.length; i++) {
|
||||
var association = associations[i];
|
||||
var sourceModel = models[association.source.toLowerCase()];
|
||||
var targetModel = models[association.target.toLowerCase()];
|
||||
var sourceModel = models[association.source];
|
||||
var targetModel = models[association.target];
|
||||
if (sourceModel && targetModel) {
|
||||
if(typeof sourceModel[association.relation] === 'function') {
|
||||
sourceModel[association.relation](targetModel, {as: association.as});
|
||||
|
@ -480,5 +479,5 @@ function buildModels(modelBuilder, schemas) {
|
|||
return models;
|
||||
}
|
||||
|
||||
ModelBuilder.buildModels = buildModels;
|
||||
|
||||
|
||||
|
|
13
lib/sql.js
13
lib/sql.js
|
@ -29,7 +29,7 @@ BaseSQL.prototype.queryOne = function (sql, callback) {
|
|||
BaseSQL.prototype.dataSource = function(model) {
|
||||
var m = this._models[model];
|
||||
if(!m) {
|
||||
console.log(new Error('Model not found: ' + model).stack);
|
||||
console.trace('Model not found: ' + model);
|
||||
}
|
||||
return m.model.schema;
|
||||
}
|
||||
|
@ -98,6 +98,15 @@ BaseSQL.prototype.idName = function (model) {
|
|||
return this.dataSource(model).idName(model);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the id property names
|
||||
* @param model The model name
|
||||
* @returns {[String]} The id property names
|
||||
*/
|
||||
BaseSQL.prototype.idNames = function (model) {
|
||||
return this.dataSource(model).idNames(model);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the id column name
|
||||
* @param model The model name
|
||||
|
@ -130,7 +139,7 @@ BaseSQL.prototype.idColumnEscaped = function (model) {
|
|||
BaseSQL.prototype.id = function (model, prop) {
|
||||
var p = this._models[model].properties[prop];
|
||||
if(!p) {
|
||||
console.log(new Error('Property not found: ' + model +'.' + prop).stack);
|
||||
console.trace('Property not found: ' + model +'.' + prop);
|
||||
}
|
||||
return p.id;
|
||||
};
|
||||
|
|
|
@ -168,23 +168,23 @@ describe('Load models from json', function () {
|
|||
// Read the schema JSON file
|
||||
var schemas = JSON.parse(fs.readFileSync(schemaFile));
|
||||
|
||||
return DataSource.buildModels(dataSource, schemas);
|
||||
return dataSource.buildModels(schemas);
|
||||
|
||||
}
|
||||
|
||||
var models = loadSchemasSync(path.join(__dirname, 'test1-schemas.json'));
|
||||
|
||||
models.should.have.property('anonymous');
|
||||
models.anonymous.should.have.property('modelName', 'Anonymous');
|
||||
models.should.have.property('Anonymous');
|
||||
models.Anonymous.should.have.property('modelName', 'Anonymous');
|
||||
|
||||
var m1 = new models.anonymous({title: 'Test'});
|
||||
var m1 = new models.Anonymous({title: 'Test'});
|
||||
m1.should.have.property('title', 'Test');
|
||||
m1.should.have.property('author', 'Raymond');
|
||||
|
||||
models = loadSchemasSync(path.join(__dirname, 'test2-schemas.json'));
|
||||
models.should.have.property('address');
|
||||
models.should.have.property('account');
|
||||
models.should.have.property('customer');
|
||||
models.should.have.property('Address');
|
||||
models.should.have.property('Account');
|
||||
models.should.have.property('Customer');
|
||||
for (var s in models) {
|
||||
var m = models[s];
|
||||
console.log(m.modelName, new m());
|
||||
|
|
Loading…
Reference in New Issue