Allow custom name mapping for discovered models
This commit is contained in:
parent
2bdcce0d96
commit
1e70678fa7
|
@ -1190,7 +1190,32 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
}
|
||||
|
||||
var self = this;
|
||||
var schemaName = this.connector.name || this.name;
|
||||
var dbType = this.connector.name || this.name;
|
||||
|
||||
var nameMapper;
|
||||
if (options.nameMapper === null) {
|
||||
// No mapping
|
||||
nameMapper = function(type, name) {
|
||||
return name;
|
||||
};
|
||||
} else if (typeof options.nameMapper === 'function') {
|
||||
// Custom name mapper
|
||||
nameMapper = options.nameMapper;
|
||||
} else {
|
||||
// Default name mapper
|
||||
nameMapper = function mapName(type, name) {
|
||||
if (type === 'table' || type === 'model') {
|
||||
return fromDBName(name, false);
|
||||
} else {
|
||||
return fromDBName(name, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (this.connector.discoverSchemas) {
|
||||
// Delegate to the connector implementation
|
||||
return this.connector.discoverSchemas(modelName, options, cb);
|
||||
}
|
||||
|
||||
var tasks = [
|
||||
this.discoverModelProperties.bind(this, modelName, options),
|
||||
|
@ -1215,7 +1240,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
}
|
||||
|
||||
// Handle primary keys
|
||||
var primaryKeys = results[1];
|
||||
var primaryKeys = results[1] || [];
|
||||
var pks = {};
|
||||
primaryKeys.forEach(function (pk) {
|
||||
pks[pk.columnName] = pk.keySeq;
|
||||
|
@ -1226,14 +1251,14 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
}
|
||||
|
||||
var schema = {
|
||||
name: fromDBName(modelName, false),
|
||||
name: nameMapper('table', modelName),
|
||||
options: {
|
||||
idInjection: false // DO NOT add id property
|
||||
},
|
||||
properties: {}
|
||||
};
|
||||
|
||||
schema.options[schemaName] = {
|
||||
schema.options[dbType] = {
|
||||
schema: columns[0].owner,
|
||||
table: modelName
|
||||
};
|
||||
|
@ -1241,7 +1266,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
columns.forEach(function (item) {
|
||||
var i = item;
|
||||
|
||||
var propName = fromDBName(item.columnName, true);
|
||||
var propName = nameMapper('column', item.columnName);
|
||||
schema.properties[propName] = {
|
||||
type: item.type,
|
||||
required: (item.nullable === 'N' || item.nullable === 'NO'
|
||||
|
@ -1254,7 +1279,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
if (pks[item.columnName]) {
|
||||
schema.properties[propName].id = pks[item.columnName];
|
||||
}
|
||||
schema.properties[propName][schemaName] = {
|
||||
schema.properties[propName][dbType] = {
|
||||
columnName: i.columnName,
|
||||
dataType: i.dataType,
|
||||
dataLength: i.dataLength,
|
||||
|
@ -1278,7 +1303,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
if (followingRelations) {
|
||||
// Handle foreign keys
|
||||
var fks = {};
|
||||
var foreignKeys = results[2];
|
||||
var foreignKeys = results[2] || [];
|
||||
foreignKeys.forEach(function (fk) {
|
||||
var fkInfo = {
|
||||
keySeq: fk.keySeq,
|
||||
|
@ -1299,11 +1324,11 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
|
||||
schema.options.relations = {};
|
||||
foreignKeys.forEach(function (fk) {
|
||||
var propName = fromDBName(fk.pkTableName, true);
|
||||
var propName = nameMapper('column', fk.pkTableName);
|
||||
schema.options.relations[propName] = {
|
||||
model: fromDBName(fk.pkTableName, false),
|
||||
model: nameMapper('table', fk.pkTableName),
|
||||
type: 'belongsTo',
|
||||
foreignKey: fromDBName(fk.fkColumnName, true)
|
||||
foreignKey: nameMapper('column', fk.fkColumnName)
|
||||
};
|
||||
|
||||
var key = fk.pkOwner + '.' + fk.pkTableName;
|
||||
|
@ -1349,13 +1374,21 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
|||
*/
|
||||
DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||
var self = this;
|
||||
var schemaName = this.name || this.connector.name;
|
||||
var dbType = this.name || this.connector.name;
|
||||
|
||||
var columns = this.discoverModelPropertiesSync(modelName, options);
|
||||
if (!columns || columns.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var nameMapper = options.nameMapper || function mapName(type, name) {
|
||||
if (type === 'table' || type === 'model') {
|
||||
return fromDBName(name, false);
|
||||
} else {
|
||||
return fromDBName(name, true);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle primary keys
|
||||
var primaryKeys = this.discoverPrimaryKeysSync(modelName, options);
|
||||
var pks = {};
|
||||
|
@ -1368,14 +1401,14 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
|||
}
|
||||
|
||||
var schema = {
|
||||
name: fromDBName(modelName, false),
|
||||
name: nameMapper('table', modelName),
|
||||
options: {
|
||||
idInjection: false // DO NOT add id property
|
||||
},
|
||||
properties: {}
|
||||
};
|
||||
|
||||
schema.options[schemaName] = {
|
||||
schema.options[dbType] = {
|
||||
schema: columns.length > 0 && columns[0].owner,
|
||||
table: modelName
|
||||
};
|
||||
|
@ -1383,7 +1416,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
|||
columns.forEach(function (item) {
|
||||
var i = item;
|
||||
|
||||
var propName = fromDBName(item.columnName, true);
|
||||
var propName = nameMapper('column', item.columnName);
|
||||
schema.properties[propName] = {
|
||||
type: item.type,
|
||||
required: (item.nullable === 'N'),
|
||||
|
@ -1395,7 +1428,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
|||
if (pks[item.columnName]) {
|
||||
schema.properties[propName].id = pks[item.columnName];
|
||||
}
|
||||
schema.properties[propName][schemaName] = {
|
||||
schema.properties[propName][dbType] = {
|
||||
columnName: i.columnName,
|
||||
dataType: i.dataType,
|
||||
dataLength: i.dataLength,
|
||||
|
@ -1441,11 +1474,11 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
|||
|
||||
schema.options.relations = {};
|
||||
foreignKeys.forEach(function (fk) {
|
||||
var propName = fromDBName(fk.pkTableName, true);
|
||||
var propName = nameMapper('column', fk.pkTableName);
|
||||
schema.options.relations[propName] = {
|
||||
model: fromDBName(fk.pkTableName, false),
|
||||
model: nameMapper('table', fk.pkTableName),
|
||||
type: 'belongsTo',
|
||||
foreignKey: fromDBName(fk.fkColumnName, true)
|
||||
foreignKey: nameMapper('column', fk.fkColumnName)
|
||||
};
|
||||
|
||||
var key = fk.pkOwner + '.' + fk.pkTableName;
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
var jdb = require('../');
|
||||
var DataSource = jdb.DataSource;
|
||||
var should = require('./init.js');
|
||||
|
||||
describe('Memory connector with mocked discovery', function() {
|
||||
var ds;
|
||||
|
||||
before(function() {
|
||||
ds = new DataSource({connector: 'memory'});
|
||||
|
||||
var models = [{type: 'table', name: 'CUSTOMER', owner: 'STRONGLOOP'},
|
||||
{type: 'table', name: 'INVENTORY', owner: 'STRONGLOOP'},
|
||||
{type: 'table', name: 'LOCATION', owner: 'STRONGLOOP'}];
|
||||
|
||||
ds.discoverModelDefinitions = function(options, cb) {
|
||||
process.nextTick(function() {
|
||||
cb(null, models);
|
||||
});
|
||||
};
|
||||
|
||||
var modelProperties = [{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'PRODUCT_ID',
|
||||
dataType: 'varchar',
|
||||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'LOCATION_ID',
|
||||
dataType: 'varchar',
|
||||
dataLength: 20,
|
||||
dataPrecision: null,
|
||||
dataScale: null,
|
||||
nullable: 0
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'AVAILABLE',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
},
|
||||
{
|
||||
owner: 'STRONGLOOP',
|
||||
tableName: 'INVENTORY',
|
||||
columnName: 'TOTAL',
|
||||
dataType: 'int',
|
||||
dataLength: null,
|
||||
dataPrecision: 10,
|
||||
dataScale: 0,
|
||||
nullable: 1
|
||||
}];
|
||||
|
||||
ds.discoverModelProperties = function(modelName, options, cb) {
|
||||
process.nextTick(function() {
|
||||
cb(null, modelProperties);
|
||||
});
|
||||
};
|
||||
});
|
||||
|
||||
it('should convert table/column names to camel cases', function(done) {
|
||||
ds.discoverSchemas('INVENTORY', {}, function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
schemas.should.have.property('STRONGLOOP.INVENTORY');
|
||||
var s = schemas['STRONGLOOP.INVENTORY'];
|
||||
s.name.should.be.eql('Inventory');
|
||||
Object.keys(s.properties).should.be.eql(
|
||||
['productId', 'locationId', 'available', 'total']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert table/column names with custom mapper', function(done) {
|
||||
ds.discoverSchemas('INVENTORY', {
|
||||
nameMapper: function(type, name) {
|
||||
// Convert all names to lower case
|
||||
return name.toLowerCase();
|
||||
}
|
||||
}, function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
schemas.should.have.property('STRONGLOOP.INVENTORY');
|
||||
var s = schemas['STRONGLOOP.INVENTORY'];
|
||||
s.name.should.be.eql('inventory');
|
||||
Object.keys(s.properties).should.be.eql(
|
||||
['product_id', 'location_id', 'available', 'total']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not convert table/column names with null custom mapper',
|
||||
function(done) {
|
||||
ds.discoverSchemas('INVENTORY', {nameMapper: null}, function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
schemas.should.have.property('STRONGLOOP.INVENTORY');
|
||||
var s = schemas['STRONGLOOP.INVENTORY'];
|
||||
s.name.should.be.eql('INVENTORY');
|
||||
Object.keys(s.properties).should.be.eql(
|
||||
['PRODUCT_ID', 'LOCATION_ID', 'AVAILABLE', 'TOTAL']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should honor connector\'s discoverSchemas implementation',
|
||||
function(done) {
|
||||
var models = {
|
||||
inventory: {
|
||||
product: {type: 'string'},
|
||||
location: {type: 'string'}
|
||||
}
|
||||
};
|
||||
ds.connector.discoverSchemas = function(modelName, options, cb) {
|
||||
process.nextTick(function() {
|
||||
cb(null, models);
|
||||
});
|
||||
};
|
||||
ds.discoverSchemas('INVENTORY', {nameMapper: null}, function(err, schemas) {
|
||||
if (err) return done(err);
|
||||
schemas.should.be.eql(models);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue