push column/idcolumn to connector level and renam
This commit is contained in:
parent
49e4c37ba7
commit
9d03b8cde8
|
@ -218,6 +218,62 @@ Connector.prototype.id = function(model, prop) {
|
|||
return p && p.id;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the database name of the property of the model if it exists.
|
||||
* Otherwise return the property name.
|
||||
* Some connectors allow the column/field name to be customized
|
||||
* at the model property definition level as `column`,
|
||||
* `columnName`, or `field`. For example,
|
||||
*
|
||||
* ```json
|
||||
* "name": {
|
||||
* "type": "string",
|
||||
* "mysql": {
|
||||
* "column": "NAME"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @param {String} model The target model name
|
||||
* @param {String} prop The property name
|
||||
*
|
||||
* @returns {String} The database mapping name of the property of the model if it exists
|
||||
*/
|
||||
Connector.prototype.getPropertyDbName = Connector.prototype.column =
|
||||
function(model, property) {
|
||||
const prop = this.getPropertyDefinition(model, property);
|
||||
let mappingName;
|
||||
if (prop && prop[this.name]) {
|
||||
mappingName = prop[this.name].column || prop[this.name].columnName ||
|
||||
prop[this.name].field || prop[this.name].fieldName;
|
||||
if (mappingName) {
|
||||
// Explicit column name, return as-is
|
||||
return mappingName;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if name attribute provided for column name
|
||||
if (prop && prop.name) {
|
||||
return prop.name;
|
||||
}
|
||||
mappingName = property;
|
||||
if (typeof this.dbName === 'function') {
|
||||
mappingName = this.dbName(mappingName);
|
||||
}
|
||||
return mappingName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the database name of the id property of the model if it exists.
|
||||
* Otherwise return the name of the id property.
|
||||
* @param {String} model The target model name
|
||||
* @param {String} prop The property name
|
||||
* @returns {String} the database mapping name of the id property of the model if it exists.
|
||||
*/
|
||||
Connector.prototype.getIdDbName = Connector.prototype.idColumn = function(model) {
|
||||
const idName = this.getDataSource(model).getModelDefinition(model).idName();
|
||||
return this.getPropertyDbName(model, idName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to be called by DataSource for defining a model
|
||||
* @param {Object} modelDefinition The model definition
|
||||
|
|
50
lib/sql.js
50
lib/sql.js
|
@ -354,46 +354,6 @@ SQLConnector.prototype.table = function(model) {
|
|||
return tableName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the column name for the given model property. The column name can be
|
||||
* customized at the model property definition level as `column` or
|
||||
* `columnName`. For example,
|
||||
*
|
||||
* ```json
|
||||
* "name": {
|
||||
* "type": "string",
|
||||
* "mysql": {
|
||||
* "column": "NAME"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {String} model The model name
|
||||
* @param {String} property The property name
|
||||
* @returns {String} The column name
|
||||
*/
|
||||
SQLConnector.prototype.column = function(model, property) {
|
||||
const prop = this.getPropertyDefinition(model, property);
|
||||
let columnName;
|
||||
if (prop && prop[this.name]) {
|
||||
columnName = prop[this.name].column || prop[this.name].columnName;
|
||||
if (columnName) {
|
||||
// Explicit column name, return as-is
|
||||
return columnName;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if name attribute provided for column name
|
||||
if (prop && prop.name) {
|
||||
return prop.name;
|
||||
}
|
||||
columnName = property;
|
||||
if (typeof this.dbName === 'function') {
|
||||
columnName = this.dbName(columnName);
|
||||
}
|
||||
return columnName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the column metadata for the given model property
|
||||
* @param {String} model The model name
|
||||
|
@ -420,16 +380,6 @@ SQLConnector.prototype.propertyName = function(model, column) {
|
|||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the id column name.
|
||||
* @param {String} model The model name
|
||||
* @returns {String} The id column name
|
||||
*/
|
||||
SQLConnector.prototype.idColumn = function(model) {
|
||||
const idName = this.getDataSource(model).getModelDefinition(model).idName();
|
||||
return this.column(model, idName);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the escaped id column name
|
||||
* @param {String} model The model name
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright IBM Corp. 2020. All Rights Reserved.
|
||||
// Node module: loopback-connector
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
'use strict';
|
||||
/*
|
||||
* A mockup connector that extends NoSQL/SQL connector
|
||||
* to check property name mapping.
|
||||
*/
|
||||
const util = require('util');
|
||||
const Connector = require('../../lib/connector');
|
||||
const debug = require('debug')('loopback:connector:test-connector');
|
||||
|
||||
exports.initialize = function initializeDataSource(dataSource, callback) {
|
||||
process.nextTick(function() {
|
||||
if (callback) {
|
||||
const connector = new TestConnector(dataSource.settings);
|
||||
connector.dataSource = dataSource;
|
||||
dataSource.connector = connector;
|
||||
callback(null, connector);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function TestConnector(settings) {
|
||||
Connector.call(this, 'testdb', settings);
|
||||
this._tables = {};
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
util.inherits(TestConnector, Connector);
|
||||
|
||||
TestConnector.prototype.dbName = function(name) {
|
||||
return name.toUpperCase();
|
||||
};
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright IBM Corp. 2020. All Rights Reserved.
|
||||
// Node module: loopback-connector
|
||||
// This file is licensed under the MIT License.
|
||||
// License text available at https://opensource.org/licenses/MIT
|
||||
|
||||
'use strict';
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const Connector = require('../lib/connector');
|
||||
const testConnector = require('./connectors/test-connector');
|
||||
|
||||
const juggler = require('loopback-datasource-juggler');
|
||||
const ds = new juggler.DataSource({
|
||||
connector: testConnector,
|
||||
debug: true,
|
||||
});
|
||||
|
||||
/* eslint-disable one-var */
|
||||
let connector;
|
||||
let Customer;
|
||||
let Order;
|
||||
/* eslint-enable one-var */
|
||||
|
||||
describe('Name mapping', function() {
|
||||
let connector, builder;
|
||||
|
||||
before(() => {
|
||||
connector = ds.connector;
|
||||
connector._tables = {};
|
||||
connector._models = {};
|
||||
Customer = ds.createModel(
|
||||
'Customer',
|
||||
{
|
||||
name: {
|
||||
id: true,
|
||||
type: String,
|
||||
testdb: {
|
||||
column: 'FIRSTNAME',
|
||||
dataType: 'VARCHAR',
|
||||
dataLength: 32,
|
||||
},
|
||||
},
|
||||
middleName: {
|
||||
type: Boolean,
|
||||
name: 'middle_name',
|
||||
postgresql: {
|
||||
column: 'MIDDLENAME',
|
||||
},
|
||||
},
|
||||
lastName: {
|
||||
type: Boolean,
|
||||
testdb: {
|
||||
column: 'LASTNAME',
|
||||
},
|
||||
},
|
||||
primaryAddress: {
|
||||
type: String,
|
||||
name: 'primary_address',
|
||||
},
|
||||
address: String,
|
||||
},
|
||||
{testdb: {table: 'CUSTOMER'}},
|
||||
);
|
||||
|
||||
// use field in this model to mock NoSQL DB
|
||||
Order = ds.createModel(
|
||||
'Order',
|
||||
{
|
||||
id: {
|
||||
id: true,
|
||||
type: Number,
|
||||
testdb: {
|
||||
field: 'my_id',
|
||||
dataType: 'ObjectId',
|
||||
},
|
||||
},
|
||||
des: {
|
||||
type: String,
|
||||
testdb: {
|
||||
field: 'DESCRIPTION',
|
||||
},
|
||||
},
|
||||
},
|
||||
{testdb: {table: 'ORDER'}},
|
||||
);
|
||||
});
|
||||
|
||||
context('getIdDbName', function() {
|
||||
it('should map id column name', function() {
|
||||
const idCol = connector.getIdDbName('Customer');
|
||||
expect(idCol).to.eql('FIRSTNAME');
|
||||
});
|
||||
|
||||
it('alias idColumn should map id column name', function() {
|
||||
const idCol = connector.idColumn('Customer');
|
||||
expect(idCol).to.eql('FIRSTNAME');
|
||||
});
|
||||
|
||||
it('should map id field name', function() {
|
||||
const idCol = connector.getIdDbName('Order');
|
||||
expect(idCol).to.eql('my_id');
|
||||
});
|
||||
});
|
||||
context('getPropertyDbName', function() {
|
||||
it('prefers property name if the database name is not matched', function() {
|
||||
const column = connector.getPropertyDbName('Customer', 'middleName');
|
||||
expect(column).to.eql('middle_name');
|
||||
});
|
||||
|
||||
it('prefers database-specific column name over property name', function() {
|
||||
const column = connector.getPropertyDbName('Customer', 'lastName');
|
||||
expect(column).to.eql('LASTNAME');
|
||||
});
|
||||
|
||||
it('alias column should map the column name', function() {
|
||||
const column = connector.column('Customer', 'lastName');
|
||||
expect(column).to.eql('LASTNAME');
|
||||
});
|
||||
|
||||
it('propertyMapping should map column name from name attribute', function() {
|
||||
const column = connector.getPropertyDbName('Customer', 'primaryAddress');
|
||||
expect(column).to.eql('primary_address');
|
||||
});
|
||||
|
||||
it('connector-preffered configuration (UPPERCASE) is applied if no columm/field name is provided', function() {
|
||||
const column = connector.getPropertyDbName('Customer', 'address');
|
||||
expect(column).to.eql('ADDRESS');
|
||||
});
|
||||
|
||||
it('prefers database-specific field name over property name', function() {
|
||||
const column = connector.getPropertyDbName('Order', 'des');
|
||||
expect(column).to.eql('DESCRIPTION');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -79,37 +79,13 @@ describe('sql connector', function() {
|
|||
{testdb: {table: 'ORDER'}});
|
||||
});
|
||||
|
||||
// tests for column names mapping are moved to name-mapping.test.js
|
||||
|
||||
it('should map table name', function() {
|
||||
const table = connector.table('customer');
|
||||
expect(table).to.eql('CUSTOMER');
|
||||
});
|
||||
|
||||
it('should map column name', function() {
|
||||
const column = connector.column('customer', 'name');
|
||||
expect(column).to.eql('NAME');
|
||||
});
|
||||
|
||||
it('should map column name from name attribute', function() {
|
||||
const column = connector.column('customer', 'primaryAddress');
|
||||
expect(column).to.eql('primary_address');
|
||||
});
|
||||
|
||||
it('prefers database-specific column name over property name', function() {
|
||||
const column = connector.column('customer', 'lastName');
|
||||
expect(column).to.eql('LASTNAME');
|
||||
});
|
||||
|
||||
it('uses database-specific column name over property name even if the column name \
|
||||
does not follow the connector-specific configuration (UPPERCASE)', function() {
|
||||
const column = connector.column('order', 'des');
|
||||
expect(column).to.eql('description');
|
||||
});
|
||||
|
||||
it('prefers property name when database is different', function() {
|
||||
const column = connector.column('customer', 'middleName');
|
||||
expect(column).to.eql('middle_name');
|
||||
});
|
||||
|
||||
it('should find column metadata', function() {
|
||||
const column = connector.columnMetadata('customer', 'name');
|
||||
expect(column).to.eql({
|
||||
|
@ -124,18 +100,6 @@ describe('sql connector', function() {
|
|||
expect(prop).to.eql('name');
|
||||
});
|
||||
|
||||
it('should map id column name', function() {
|
||||
const idCol = connector.idColumn('customer');
|
||||
expect(idCol).to.eql('NAME');
|
||||
});
|
||||
|
||||
it('should map id column name even if the column name does not \
|
||||
follow the connector-specific configuration (UPPERCASE)', function() {
|
||||
const idCol = connector.idColumn('order');
|
||||
// shouldn't be converted to ORDERID
|
||||
expect(idCol).to.eql('orderId');
|
||||
});
|
||||
|
||||
it('should find escaped id column name', function() {
|
||||
const idCol = connector.idColumnEscaped('customer');
|
||||
expect(idCol).to.eql('`NAME`');
|
||||
|
|
Loading…
Reference in New Issue