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 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 = [
|
var tasks = [
|
||||||
this.discoverModelProperties.bind(this, modelName, options),
|
this.discoverModelProperties.bind(this, modelName, options),
|
||||||
|
@ -1215,7 +1240,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle primary keys
|
// Handle primary keys
|
||||||
var primaryKeys = results[1];
|
var primaryKeys = results[1] || [];
|
||||||
var pks = {};
|
var pks = {};
|
||||||
primaryKeys.forEach(function (pk) {
|
primaryKeys.forEach(function (pk) {
|
||||||
pks[pk.columnName] = pk.keySeq;
|
pks[pk.columnName] = pk.keySeq;
|
||||||
|
@ -1226,14 +1251,14 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var schema = {
|
var schema = {
|
||||||
name: fromDBName(modelName, false),
|
name: nameMapper('table', modelName),
|
||||||
options: {
|
options: {
|
||||||
idInjection: false // DO NOT add id property
|
idInjection: false // DO NOT add id property
|
||||||
},
|
},
|
||||||
properties: {}
|
properties: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema.options[schemaName] = {
|
schema.options[dbType] = {
|
||||||
schema: columns[0].owner,
|
schema: columns[0].owner,
|
||||||
table: modelName
|
table: modelName
|
||||||
};
|
};
|
||||||
|
@ -1241,7 +1266,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
columns.forEach(function (item) {
|
columns.forEach(function (item) {
|
||||||
var i = item;
|
var i = item;
|
||||||
|
|
||||||
var propName = fromDBName(item.columnName, true);
|
var propName = nameMapper('column', item.columnName);
|
||||||
schema.properties[propName] = {
|
schema.properties[propName] = {
|
||||||
type: item.type,
|
type: item.type,
|
||||||
required: (item.nullable === 'N' || item.nullable === 'NO'
|
required: (item.nullable === 'N' || item.nullable === 'NO'
|
||||||
|
@ -1254,7 +1279,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
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][schemaName] = {
|
schema.properties[propName][dbType] = {
|
||||||
columnName: i.columnName,
|
columnName: i.columnName,
|
||||||
dataType: i.dataType,
|
dataType: i.dataType,
|
||||||
dataLength: i.dataLength,
|
dataLength: i.dataLength,
|
||||||
|
@ -1278,7 +1303,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
if (followingRelations) {
|
if (followingRelations) {
|
||||||
// Handle foreign keys
|
// Handle foreign keys
|
||||||
var fks = {};
|
var fks = {};
|
||||||
var foreignKeys = results[2];
|
var foreignKeys = results[2] || [];
|
||||||
foreignKeys.forEach(function (fk) {
|
foreignKeys.forEach(function (fk) {
|
||||||
var fkInfo = {
|
var fkInfo = {
|
||||||
keySeq: fk.keySeq,
|
keySeq: fk.keySeq,
|
||||||
|
@ -1299,11 +1324,11 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
|
|
||||||
schema.options.relations = {};
|
schema.options.relations = {};
|
||||||
foreignKeys.forEach(function (fk) {
|
foreignKeys.forEach(function (fk) {
|
||||||
var propName = fromDBName(fk.pkTableName, true);
|
var propName = nameMapper('column', fk.pkTableName);
|
||||||
schema.options.relations[propName] = {
|
schema.options.relations[propName] = {
|
||||||
model: fromDBName(fk.pkTableName, false),
|
model: nameMapper('table', fk.pkTableName),
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
foreignKey: fromDBName(fk.fkColumnName, true)
|
foreignKey: nameMapper('column', fk.fkColumnName)
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = fk.pkOwner + '.' + fk.pkTableName;
|
var key = fk.pkOwner + '.' + fk.pkTableName;
|
||||||
|
@ -1349,13 +1374,21 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
|
||||||
*/
|
*/
|
||||||
DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var schemaName = this.name || this.connector.name;
|
var dbType = this.name || this.connector.name;
|
||||||
|
|
||||||
var columns = this.discoverModelPropertiesSync(modelName, options);
|
var columns = this.discoverModelPropertiesSync(modelName, options);
|
||||||
if (!columns || columns.length === 0) {
|
if (!columns || columns.length === 0) {
|
||||||
return [];
|
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
|
// Handle primary keys
|
||||||
var primaryKeys = this.discoverPrimaryKeysSync(modelName, options);
|
var primaryKeys = this.discoverPrimaryKeysSync(modelName, options);
|
||||||
var pks = {};
|
var pks = {};
|
||||||
|
@ -1368,14 +1401,14 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var schema = {
|
var schema = {
|
||||||
name: fromDBName(modelName, false),
|
name: nameMapper('table', modelName),
|
||||||
options: {
|
options: {
|
||||||
idInjection: false // DO NOT add id property
|
idInjection: false // DO NOT add id property
|
||||||
},
|
},
|
||||||
properties: {}
|
properties: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema.options[schemaName] = {
|
schema.options[dbType] = {
|
||||||
schema: columns.length > 0 && columns[0].owner,
|
schema: columns.length > 0 && columns[0].owner,
|
||||||
table: modelName
|
table: modelName
|
||||||
};
|
};
|
||||||
|
@ -1383,7 +1416,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
columns.forEach(function (item) {
|
columns.forEach(function (item) {
|
||||||
var i = item;
|
var i = item;
|
||||||
|
|
||||||
var propName = fromDBName(item.columnName, true);
|
var propName = nameMapper('column', item.columnName);
|
||||||
schema.properties[propName] = {
|
schema.properties[propName] = {
|
||||||
type: item.type,
|
type: item.type,
|
||||||
required: (item.nullable === 'N'),
|
required: (item.nullable === 'N'),
|
||||||
|
@ -1395,7 +1428,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
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][schemaName] = {
|
schema.properties[propName][dbType] = {
|
||||||
columnName: i.columnName,
|
columnName: i.columnName,
|
||||||
dataType: i.dataType,
|
dataType: i.dataType,
|
||||||
dataLength: i.dataLength,
|
dataLength: i.dataLength,
|
||||||
|
@ -1441,11 +1474,11 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
|
|
||||||
schema.options.relations = {};
|
schema.options.relations = {};
|
||||||
foreignKeys.forEach(function (fk) {
|
foreignKeys.forEach(function (fk) {
|
||||||
var propName = fromDBName(fk.pkTableName, true);
|
var propName = nameMapper('column', fk.pkTableName);
|
||||||
schema.options.relations[propName] = {
|
schema.options.relations[propName] = {
|
||||||
model: fromDBName(fk.pkTableName, false),
|
model: nameMapper('table', fk.pkTableName),
|
||||||
type: 'belongsTo',
|
type: 'belongsTo',
|
||||||
foreignKey: fromDBName(fk.fkColumnName, true)
|
foreignKey: nameMapper('column', fk.fkColumnName)
|
||||||
};
|
};
|
||||||
|
|
||||||
var key = fk.pkOwner + '.' + fk.pkTableName;
|
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