Enable discovery
This commit is contained in:
parent
1329b40073
commit
fb375fdcc8
|
@ -0,0 +1,48 @@
|
|||
var DataSource = require('loopback-data').DataSource;
|
||||
|
||||
var ds = new DataSource(require('../'), {
|
||||
host: '127.0.0.1',
|
||||
port: 3306,
|
||||
database: 'test',
|
||||
username: 'strongloop',
|
||||
password: 'password',
|
||||
debug: false
|
||||
});
|
||||
|
||||
function show(err, models) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
} else {
|
||||
console.log(models);
|
||||
if (models) {
|
||||
models.forEach(function (m) {
|
||||
console.dir(m);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ds.discoverModelDefinitions({views: true, limit: 20}, show);
|
||||
|
||||
ds.discoverModelProperties('User', show);
|
||||
|
||||
ds.discoverModelProperties('Post', {owner: 'test'}, show);
|
||||
|
||||
ds.discoverPrimaryKeys('User', show);
|
||||
// ds.discoverForeignKeys('User', show);
|
||||
|
||||
// ds.discoverExportedForeignKeys('User', show);
|
||||
|
||||
|
||||
ds.discoverAndBuildModels('User', {owner: 'test', visited: {}, associations: true}, function (err, models) {
|
||||
|
||||
for (var m in models) {
|
||||
models[m].all(show);
|
||||
}
|
||||
;
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
717
lib/discovery.js
717
lib/discovery.js
|
@ -1,375 +1,424 @@
|
|||
var MySQL = require('./mysql').MySQL;
|
||||
module.exports = mixinDiscovery;
|
||||
|
||||
function paginateSQL(sql, options) {
|
||||
options = options || {};
|
||||
var limit = '';
|
||||
if(options.offset || options.skip || options.limit) {
|
||||
limit = 'LIMIT '+ (options.offset || options.skip || 1);
|
||||
if(options.limit) {
|
||||
limit = limit + ' ' + options.limit;
|
||||
function mixinDiscovery(MySQL) {
|
||||
var async = require('async');
|
||||
|
||||
function paginateSQL(sql, options) {
|
||||
options = options || {};
|
||||
var limit = '';
|
||||
if (options.offset || options.skip || options.limit) {
|
||||
limit = 'LIMIT ' + (options.offset || options.skip || 1);
|
||||
if (options.limit) {
|
||||
limit = limit + ' ' + options.limit;
|
||||
}
|
||||
}
|
||||
return sql + limit;
|
||||
}
|
||||
return sql + limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build sql for listing tables
|
||||
* @param options {all: for all owners, owner: for a given owner}
|
||||
* @returns {string} The sql statement
|
||||
*/
|
||||
function queryTables(options) {
|
||||
var sqlTables = null;
|
||||
var owner = options.owner || options.schema;
|
||||
|
||||
if (options.all && !owner) {
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
|
||||
+ ' FROM information_schema.tables', 'table_schema, table_name', options);
|
||||
} else if (owner) {
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
|
||||
+ ' FROM information_schema.tables WHERE table_schema=\'' + owner + '\'', 'table_schema, table_name', options);
|
||||
} else {
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name",'
|
||||
+ ' USER() AS "owner" FROM information_schema.tables',
|
||||
'table_name', options);
|
||||
}
|
||||
return sqlTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build sql for listing views
|
||||
* @param options {all: for all owners, owner: for a given owner}
|
||||
* @returns {string} The sql statement
|
||||
*/
|
||||
function queryViews(options) {
|
||||
var sqlViews = null;
|
||||
if (options.views) {
|
||||
|
||||
/**
|
||||
* Build sql for listing tables
|
||||
* @param options {all: for all owners, owner: for a given owner}
|
||||
* @returns {string} The sql statement
|
||||
*/
|
||||
function queryTables(options) {
|
||||
var sqlTables = null;
|
||||
var owner = options.owner || options.schema;
|
||||
|
||||
if (options.all && !owner) {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' table_schema AS "owner" FROM information_schema.views',
|
||||
'table_schema, table_name', options);
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
|
||||
+ ' FROM information_schema.tables', 'table_schema, table_name', options);
|
||||
} else if (owner) {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' table_schema AS "owner" FROM information_schema.views WHERE table_schema=\'' + owner + '\'',
|
||||
'owner, table_name', options);
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name", table_schema AS "owner"'
|
||||
+ ' FROM information_schema.tables WHERE table_schema=\'' + owner + '\'', 'table_schema, table_name', options);
|
||||
} else {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' USER() AS "owner" FROM information_schema.views',
|
||||
sqlTables = paginateSQL('SELECT \'table\' AS "type", table_name AS "name",'
|
||||
+ ' SUBSTRING_INDEX(USER(), \'@\', 1) AS "owner" FROM information_schema.tables',
|
||||
'table_name', options);
|
||||
}
|
||||
return sqlTables;
|
||||
}
|
||||
return sqlViews;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover the models
|
||||
*/
|
||||
MySQL.prototype.discoverModelDefinitions = function (options, cb) {
|
||||
if (!cb && typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
/**
|
||||
* Build sql for listing views
|
||||
* @param options {all: for all owners, owner: for a given owner}
|
||||
* @returns {string} The sql statement
|
||||
*/
|
||||
function queryViews(options) {
|
||||
var sqlViews = null;
|
||||
if (options.views) {
|
||||
|
||||
var owner = options.owner || options.schema;
|
||||
|
||||
if (options.all && !owner) {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' table_schema AS "owner" FROM information_schema.views',
|
||||
'table_schema, table_name', options);
|
||||
} else if (owner) {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' table_schema AS "owner" FROM information_schema.views WHERE table_schema=\'' + owner + '\'',
|
||||
'owner, table_name', options);
|
||||
} else {
|
||||
sqlViews = paginateSQL('SELECT \'view\' AS "type", table_name AS "name",'
|
||||
+ ' SUBSTRING_INDEX(USER(), \'@\', 1) AS "owner" FROM information_schema.views',
|
||||
'table_name', options);
|
||||
}
|
||||
}
|
||||
return sqlViews;
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
var self = this;
|
||||
var calls = [function (callback) {
|
||||
self.query(queryTables(options), callback);
|
||||
}];
|
||||
/**
|
||||
* Discover the models
|
||||
*/
|
||||
MySQL.prototype.discoverModelDefinitions = function (options, cb) {
|
||||
if (!cb && typeof options === 'function') {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
options = options || {};
|
||||
|
||||
if (options.views) {
|
||||
calls.push(function (callback) {
|
||||
self.query(queryViews(options), callback);
|
||||
var self = this;
|
||||
var calls = [function (callback) {
|
||||
self.query(queryTables(options), callback);
|
||||
}];
|
||||
|
||||
if (options.views) {
|
||||
calls.push(function (callback) {
|
||||
self.query(queryViews(options), callback);
|
||||
});
|
||||
}
|
||||
async.parallel(calls, function (err, data) {
|
||||
if (err) {
|
||||
cb(err, data);
|
||||
} else {
|
||||
var merged = [];
|
||||
merged = merged.concat(data.shift());
|
||||
if (data.length) {
|
||||
merged = merged.concat(data.shift());
|
||||
}
|
||||
cb(err, merged);
|
||||
}
|
||||
});
|
||||
}
|
||||
async.parallel(calls, function (err, data) {
|
||||
if (err) {
|
||||
cb(err, data);
|
||||
|
||||
/**
|
||||
* Discover the tables/views synchronously
|
||||
*/
|
||||
MySQL.prototype.discoverModelDefinitionsSync = function (options) {
|
||||
options = options || {};
|
||||
var sqlTables = queryTables(options);
|
||||
var tables = this.querySync(sqlTables);
|
||||
var sqlViews = queryViews(options);
|
||||
if (sqlViews) {
|
||||
var views = this.querySync(sqlViews);
|
||||
tables = tables.concat(views);
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the arguments
|
||||
* @param table string, required
|
||||
* @param options object, optional
|
||||
* @param cb function, optional
|
||||
*/
|
||||
function getArgs(table, options, cb) {
|
||||
if ('string' !== typeof table || !table) {
|
||||
throw new Error('table is a required string argument: ' + table);
|
||||
}
|
||||
options = options || {};
|
||||
if (!cb && 'function' === typeof options) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
if (typeof options !== 'object') {
|
||||
throw new Error('options must be an object: ' + options);
|
||||
}
|
||||
return {
|
||||
owner: options.owner || options.schema,
|
||||
table: table,
|
||||
options: options,
|
||||
cb: cb
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the sql statement to query columns for a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {String} The sql statement
|
||||
*/
|
||||
function queryColumns(owner, table) {
|
||||
var sql = null;
|
||||
if (owner) {
|
||||
sql = paginateSQL('SELECT table_schema AS "owner", table_name AS "tableName", column_name AS "columnName", data_type AS "dataType",'
|
||||
+ ' character_octet_length AS "dataLength", is_nullable AS "nullable"'
|
||||
+ ' FROM information_schema.columns'
|
||||
+ ' WHERE table_schema=\'' + owner + '\''
|
||||
+ (table ? ' AND table_name=\'' + table + '\'' : ''),
|
||||
'table_name, ordinal_position', {});
|
||||
} else {
|
||||
var merged = [];
|
||||
merged = merged.concat(data.shift());
|
||||
if (data.length) {
|
||||
merged = merged.concat(data.shift());
|
||||
sql = paginateSQL('SELECT SUBSTRING_INDEX(USER(), \'@\', 1) AS "owner", table_name AS "tableName", column_name AS "columnName", data_type AS "dataType",'
|
||||
+ ' character_octet_length AS "dataLength", is_nullable AS "nullable"'
|
||||
+ ' FROM information_schema.columns'
|
||||
+ (table ? ' WHERE table_name=\'' + table + '\'' : ''),
|
||||
'table_name, ordinal_position', {});
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
MySQL.prototype.discoverModelProperties = function (table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
var sql = queryColumns(owner, table);
|
||||
var callback = function (err, results) {
|
||||
if (err) {
|
||||
cb(err, results);
|
||||
} else {
|
||||
results.map(function (r) {
|
||||
r.type = mysqlDataTypeToJSONType(r.dataType, r.dataLength);
|
||||
});
|
||||
cb(err, results);
|
||||
}
|
||||
cb(err, merged);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover the tables/views synchronously
|
||||
*/
|
||||
MySQL.prototype.discoverModelDefinitionsSync = function (options) {
|
||||
options = options || {};
|
||||
var sqlTables = queryTables(options);
|
||||
var tables = this.querySync(sqlTables);
|
||||
var sqlViews = queryViews(options);
|
||||
if(sqlViews) {
|
||||
var views = this.querySync(sqlViews);
|
||||
tables = tables.concat(views);
|
||||
};
|
||||
this.query(sql, callback);
|
||||
}
|
||||
return tables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the arguments
|
||||
* @param table string, required
|
||||
* @param options object, optional
|
||||
* @param cb function, optional
|
||||
*/
|
||||
function getArgs(table, options, cb) {
|
||||
if('string' !== typeof table || !table) {
|
||||
throw new Error('table is a required string argument: ' + table);
|
||||
MySQL.prototype.discoverModelPropertiesSync = function (table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
|
||||
var sql = queryColumns(owner, table);
|
||||
var results = this.querySync(sql);
|
||||
results.map(function (r) {
|
||||
r.type = mysqlDataTypeToJSONType(r.dataType, r.dataLength);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
options = options || {};
|
||||
if(!cb && 'function' === typeof options) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
if(typeof options !== 'object') {
|
||||
throw new Error('options must be an object: ' + options);
|
||||
}
|
||||
return {
|
||||
owner: options.owner || options.schema,
|
||||
table: table,
|
||||
options: options,
|
||||
cb: cb
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Build the sql statement to query columns for a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {String} The sql statement
|
||||
*/
|
||||
function queryColumns(owner, table) {
|
||||
var sql = null;
|
||||
if (owner) {
|
||||
sql = paginateSQL('SELECT table_schema AS "owner", table_name AS "tableName", column_name AS "columnName", data_type AS "dataType",'
|
||||
+ ' data_length AS "dataLength", is_nullable AS "nullable"'
|
||||
+ ' FROM information_schema.columns'
|
||||
+ ' WHERE table_schema=\'' + owner + '\''
|
||||
+ (table ? ' AND table_name=\'' + table + '\'' : ''),
|
||||
'table_name, column_name', {});
|
||||
} else {
|
||||
sql = paginateSQL('SELECT USER() AS "owner", table_name AS "tableName", column_name AS "columnName", data_type AS "dataType",'
|
||||
+ ' data_length AS "dataLength", is_nullable AS "nullable"'
|
||||
+ ' FROM information_schema.columns'
|
||||
+ (table ? ' WHERE table_name=\'' + table + '\'' : ''),
|
||||
'table_name, column_name', {});
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
MySQL.prototype.discoverModelProperties = function (table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
var sql = queryColumns(owner, table);
|
||||
var callback = function (err, results) {
|
||||
if (err) {
|
||||
cb(err, results);
|
||||
} else {
|
||||
results.map(function (r) {
|
||||
r.type = oracleDataTypeToJSONType(r.dataType, r.dataLength);
|
||||
});
|
||||
cb(err, results);
|
||||
}
|
||||
};
|
||||
this.query(sql, callback);
|
||||
}
|
||||
|
||||
MySQL.prototype.discoverModelPropertiesSync = function (table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
|
||||
var sql = queryColumns(owner, table);
|
||||
var results = this.querySync(sql);
|
||||
results.map(function (r) {
|
||||
r.type = oracleDataTypeToJSONType(r.dataType, r.dataLength);
|
||||
});
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the sql statement for querying primary keys of a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
/**
|
||||
* Build the sql statement for querying primary keys of a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
// http://docs.oracle.com/javase/6/docs/api/java/sql/DatabaseMetaData.html#getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String)
|
||||
function queryForPrimaryKeys(owner, table) {
|
||||
var sql = 'SELECT table_schema AS "owner", '
|
||||
+ 'table_name AS "tableName", column_name AS "columnName", ordinal_position AS "keySeq", constraint_name AS "pkName" FROM'
|
||||
+ ' information_schema.key_column_usage'
|
||||
+ ' WHERE constraint_name=\'PRIMARY\'';
|
||||
function queryForPrimaryKeys(owner, table) {
|
||||
var sql = 'SELECT table_schema AS "owner", '
|
||||
+ 'table_name AS "tableName", column_name AS "columnName", ordinal_position AS "keySeq", constraint_name AS "pkName" FROM'
|
||||
+ ' information_schema.key_column_usage'
|
||||
+ ' WHERE constraint_name=\'PRIMARY\'';
|
||||
|
||||
if (owner) {
|
||||
sql += ' AND table_schema=\'' + owner + '\'';
|
||||
if (owner) {
|
||||
sql += ' AND table_schema=\'' + owner + '\'';
|
||||
}
|
||||
if (table) {
|
||||
sql += ' AND table_name=\'' + table + '\'';
|
||||
}
|
||||
sql += ' ORDER BY table_schema, constraint_name, table_name, ordinal_position';
|
||||
return sql;
|
||||
}
|
||||
if (table) {
|
||||
sql += ' AND table_name=\'' + table + '\'';
|
||||
|
||||
/**
|
||||
* Discover primary keys for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @param cb
|
||||
*/
|
||||
MySQL.prototype.discoverPrimaryKeys = function (table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
var sql = queryForPrimaryKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
sql += ' ORDER BY table_schema, constraint_name, table_name, ordinal_position';
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover primary keys for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @param cb
|
||||
*/
|
||||
MySQL.prototype.discoverPrimaryKeys= function(table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
/**
|
||||
* Discover primary keys synchronously for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverPrimaryKeysSync = function (table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
var sql = queryForPrimaryKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
var sql = queryForPrimaryKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover primary keys synchronously for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverPrimaryKeysSync= function(table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
/**
|
||||
* Build the sql statement for querying foreign keys of a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
function queryForeignKeys(owner, table) {
|
||||
var sql =
|
||||
'SELECT table_schema AS "fkOwner", constraint_name AS "fkName", table_name AS "fkTableName",'
|
||||
+ ' column_name AS "fkColumnName", ordinal_position AS "keySeq",'
|
||||
+ ' referenced_table_schema AS "pkOwner", \'PRIMARY\' AS "pkName", '
|
||||
+ ' referenced_table_name AS "pkTableName", referenced_column_name AS "pkColumnName"'
|
||||
+ ' FROM information_schema.key_column_usage'
|
||||
+ ' WHERE'
|
||||
+ ' constraint_name!=\'PRIMARY\' and POSITION_IN_UNIQUE_CONSTRAINT IS NOT NULL';
|
||||
if (owner) {
|
||||
sql += ' AND table_schema=\'' + owner + '\'';
|
||||
}
|
||||
if (table) {
|
||||
sql += ' AND table_name=\'' + table + '\'';
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
var sql = queryForPrimaryKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
/**
|
||||
* Discover foreign kets for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @param cb
|
||||
*/
|
||||
MySQL.prototype.discoverForeignKeys = function (table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
/**
|
||||
* Build the sql statement for querying foreign keys of a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
function queryForeignKeys(owner, table) {
|
||||
var sql =
|
||||
'SELECT table_schema AS "fkOwner", constraint_name AS "fkName", table_name AS "fkTableName",'
|
||||
+ ' column_name AS "fkColumnName", ordinal_position AS "keySeq",'
|
||||
+ ' referenced_table_schema AS "pkOwner", \'PRIMARY\' AS "pkName", '
|
||||
+ ' referenced_table_name AS "pkTableName", referenced_column_name AS "pkColumnName"'
|
||||
+ ' FROM information_schema.key_column_usage'
|
||||
var sql = queryForeignKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover foreign keys synchronously for a given table
|
||||
* @param owner
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverForeignKeysSync = function (table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
var sql = queryForeignKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
|
||||
* They are ordered by fkTableOwner, fkTableName, and keySeq.
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
function queryExportedForeignKeys(owner, table) {
|
||||
var sql = 'SELECT a.constraint_name AS "fkName", a.owner AS "fkOwner", a.table_name AS "fkTableName",'
|
||||
+ ' a.column_name AS "fkColumnName", a.position AS "keySeq",'
|
||||
+ ' jcol.constraint_name AS "pkName", jcol.owner AS "pkOwner",'
|
||||
+ ' jcol.table_name AS "pkTableName", jcol.column_name AS "pkColumnName"'
|
||||
+ ' FROM'
|
||||
+ ' (SELECT'
|
||||
+ ' uc1.table_name, uc1.constraint_name, uc1.r_constraint_name, col.column_name, col.position, col.owner'
|
||||
+ ' FROM'
|
||||
+ ' information_schema.key_column_usage'
|
||||
+ ' WHERE'
|
||||
+ ' constraint_name!=\'PRIMARY\' and POSITION_IN_UNIQUE_CONSTRAINT IS NOT NULL';
|
||||
if (owner) {
|
||||
sql += ' AND table_schema=\'' + owner + '\'';
|
||||
+ ' uc.constraint_type=\'P\' and uc1.r_constraint_name = uc.constraint_name and uc1.constraint_type = \'R\''
|
||||
+ ' and uc1.constraint_name=col.constraint_name';
|
||||
if (owner) {
|
||||
sql += ' and col.owner=\'' + owner + '\'';
|
||||
}
|
||||
if (table) {
|
||||
sql += ' and uc.table_Name=\'' + table + '\'';
|
||||
}
|
||||
sql += ' ) a'
|
||||
+ ' INNER JOIN'
|
||||
+ ' USER_CONS_COLUMNS jcol'
|
||||
+ ' ON'
|
||||
+ ' a.r_constraint_name=jcol.constraint_name'
|
||||
+ ' order by a.owner, a.table_name, a.position';
|
||||
|
||||
return sql;
|
||||
}
|
||||
if (table) {
|
||||
sql += ' AND table_name=\'' + table + '\'';
|
||||
|
||||
MySQL.prototype.discoverExportedForeignKeys = function (table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
var sql = queryExportedForeignKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover foreign kets for a given table
|
||||
* @param table
|
||||
* @param options
|
||||
* @param cb
|
||||
*/
|
||||
MySQL.prototype.discoverForeignKeys= function(table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
/**
|
||||
* Discover foreign keys synchronously for a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverExportedForeignKeysSync = function (table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
var sql = queryForeignKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover foreign keys synchronously for a given table
|
||||
* @param owner
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverForeignKeysSync= function(table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
var sql = queryForeignKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
|
||||
* They are ordered by fkTableOwner, fkTableName, and keySeq.
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {string}
|
||||
*/
|
||||
function queryExportedForeignKeys(owner, table) {
|
||||
var sql = 'SELECT a.constraint_name AS "fkName", a.owner AS "fkOwner", a.table_name AS "fkTableName",'
|
||||
+ ' a.column_name AS "fkColumnName", a.position AS "keySeq",'
|
||||
+ ' jcol.constraint_name AS "pkName", jcol.owner AS "pkOwner",'
|
||||
+ ' jcol.table_name AS "pkTableName", jcol.column_name AS "pkColumnName"'
|
||||
+ ' FROM'
|
||||
+ ' (SELECT'
|
||||
+ ' uc1.table_name, uc1.constraint_name, uc1.r_constraint_name, col.column_name, col.position, col.owner'
|
||||
+ ' FROM'
|
||||
+ ' information_schema.key_column_usage'
|
||||
+ ' WHERE'
|
||||
+ ' uc.constraint_type=\'P\' and uc1.r_constraint_name = uc.constraint_name and uc1.constraint_type = \'R\''
|
||||
+ ' and uc1.constraint_name=col.constraint_name';
|
||||
if(owner) {
|
||||
sql += ' and col.owner=\'' + owner + '\'';
|
||||
var sql = queryExportedForeignKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
if(table) {
|
||||
sql += ' and uc.table_Name=\'' + table + '\'';
|
||||
|
||||
function mysqlDataTypeToJSONType(mysqlType, dataLength) {
|
||||
var type = mysqlType.toUpperCase();
|
||||
switch (type) {
|
||||
case 'CHAR':
|
||||
if (dataLength === 1) {
|
||||
// Treat char(1) as boolean
|
||||
return 'Boolean';
|
||||
} else {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
case 'VARCHAR':
|
||||
case 'TINYTEXT':
|
||||
case 'MEDIUMTEXT':
|
||||
case 'LONGTEXT':
|
||||
case 'TEXT':
|
||||
case 'ENUM':
|
||||
case 'SET':
|
||||
return 'String';
|
||||
case 'TINYBLOB':
|
||||
case 'MEDIUMBLOB':
|
||||
case 'LONGBLOB':
|
||||
case 'BLOB':
|
||||
case 'BINARY':
|
||||
case 'VARBINARY':
|
||||
case 'BIT':
|
||||
return 'Binary';
|
||||
case 'TINYINT':
|
||||
case 'SMALLINT':
|
||||
case 'INT':
|
||||
case 'MEDIUMINT':
|
||||
case 'YEAR':
|
||||
case 'FLOAT':
|
||||
case 'DOUBLE':
|
||||
return 'Number';
|
||||
case 'DATE':
|
||||
case 'TIMESTAMP':
|
||||
case 'DATETIME':
|
||||
return 'Date';
|
||||
default:
|
||||
return 'String';
|
||||
}
|
||||
}
|
||||
sql += ' ) a'
|
||||
+ ' INNER JOIN'
|
||||
+ ' USER_CONS_COLUMNS jcol'
|
||||
+ ' ON'
|
||||
+ ' a.r_constraint_name=jcol.constraint_name'
|
||||
+ ' order by a.owner, a.table_name, a.position';
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
MySQL.prototype.discoverExportedForeignKeys= function(table, options, cb) {
|
||||
var args = getArgs(table, options, cb);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
cb = args.cb;
|
||||
|
||||
var sql = queryExportedForeignKeys(owner, table);
|
||||
this.query(sql, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover foreign keys synchronously for a given table
|
||||
* @param owner
|
||||
* @param table
|
||||
* @returns {*}
|
||||
*/
|
||||
MySQL.prototype.discoverExportedForeignKeysSync= function(table, options) {
|
||||
var args = getArgs(table, options);
|
||||
var owner = args.owner;
|
||||
table = args.table;
|
||||
options = args.options;
|
||||
|
||||
var sql = queryExportedForeignKeys(owner, table);
|
||||
return this.querySync(sql);
|
||||
}
|
||||
|
|
16
lib/mysql.js
16
lib/mysql.js
|
@ -129,17 +129,17 @@ MySQL.prototype.updateOrCreate = function (model, data, callback) {
|
|||
var combined = [];
|
||||
var props = this._models[model].properties;
|
||||
Object.keys(data).forEach(function (key) {
|
||||
if (props[key] || key === 'id') {
|
||||
if (props[key] || mysql.id(model, key)) {
|
||||
var k = '`' + key + '`';
|
||||
var v;
|
||||
if (key !== 'id') {
|
||||
if (!mysql.id(model, key)) {
|
||||
v = mysql.toDatabase(props[key], data[key]);
|
||||
} else {
|
||||
v = data[key];
|
||||
}
|
||||
fieldsNames.push(k);
|
||||
fieldValues.push(v);
|
||||
if (key !== 'id') combined.push(k + ' = ' + v);
|
||||
if (!mysql.id(model, key)) combined.push(k + ' = ' + v);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -469,7 +469,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
|
|||
|
||||
// change/add new fields
|
||||
propNames.forEach(function (propName) {
|
||||
if (propName === 'id') return;
|
||||
if (self.id(model, key)) return;
|
||||
var found;
|
||||
if (actualFields) {
|
||||
actualFields.forEach(function (f) {
|
||||
|
@ -490,7 +490,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
|
|||
if (actualFields) {
|
||||
actualFields.forEach(function (f) {
|
||||
var notFound = !~propNames.indexOf(f.Field);
|
||||
if (f.Field === 'id') return;
|
||||
if (mysql.id(model, f.Field)) return;
|
||||
if (notFound || !m.properties[f.Field]) {
|
||||
sql.push('DROP COLUMN `' + f.Field + '`');
|
||||
}
|
||||
|
@ -499,7 +499,7 @@ MySQL.prototype.alterTable = function (model, actualFields, actualIndexes, done,
|
|||
|
||||
// remove indexes
|
||||
aiNames.forEach(function (indexName) {
|
||||
if (indexName === 'id' || indexName === 'PRIMARY') return;
|
||||
if (self.id(model, indexName) || indexName === 'PRIMARY') return;
|
||||
if (indexNames.indexOf(indexName) === -1 && !m.properties[indexName] || m.properties[indexName] && !m.properties[indexName].index) {
|
||||
sql.push('DROP INDEX `' + indexName + '`');
|
||||
} else {
|
||||
|
@ -605,7 +605,7 @@ MySQL.prototype.propertiesSQL = function (model) {
|
|||
var self = this;
|
||||
var sql = ['`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY'];
|
||||
Object.keys(this._models[model].properties).forEach(function (prop) {
|
||||
if (prop === 'id') return;
|
||||
if (self.id(model, prop)) return;
|
||||
sql.push('`' + prop + '` ' + self.propertySettingsSQL(model, prop));
|
||||
});
|
||||
// Declared in model index property indexes.
|
||||
|
@ -855,3 +855,5 @@ function unsigned(p, dt){
|
|||
return dt;
|
||||
}
|
||||
|
||||
require('./discovery')(MySQL);
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"loopback-data": "git+ssh://git@github.com:strongloop/loopback-data.git",
|
||||
"mysql": ">= 2.0.0-alpha3"
|
||||
"mysql": ">= 2.0.0-alpha8",
|
||||
"async": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coffee-script": "latest",
|
||||
|
|
Loading…
Reference in New Issue