Refactor SQL discovery methods

This commit is contained in:
Loay 2017-02-13 15:28:59 -05:00 committed by loay
parent 292b90a6e4
commit 1b4409a39a
1 changed files with 297 additions and 0 deletions

View File

@ -1508,3 +1508,300 @@ SQLConnector.prototype.getInsertedId = function(model, info) {
SQLConnector.prototype.executeSQL = function(sql, params, options, callback) { SQLConnector.prototype.executeSQL = function(sql, params, options, callback) {
throw new Error(g.f('{{executeSQL()}} must be implemented by the connector')); throw new Error(g.f('{{executeSQL()}} must be implemented by the connector'));
}; };
// Refactored Discovery methods
/**
* Build sql for listing schemas
* @param {Object} options Options for discoverDatabaseSchemas
*/
SQLConnector.prototype.buildQuerySchemas = function(options) {
var sql = 'SELECT catalog_name as "catalog",' +
' schema_name as "schema"' +
' FROM information_schema.schemata';
return this.paginateSQL(sql, 'schema_name', options);
};
/**
* Paginate the results returned from database
* @param {String} sql The sql to execute
* @param {Object} orderBy The property name by which results are ordered
* @param {Object} options Options for discoverDatabaseSchemas
*/
SQLConnector.prototype.paginateSQL = function(sql, orderBy, options) {
throw new Error(g.f('{{paginateSQL}} must be implemented by the connector'));
};
/**
* Discover database schemas
*
// * @param {Object} options Options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverDatabaseSchemas = function(options, cb) {
if (!cb && typeof options === 'function') {
cb = options;
options = {};
}
options = options || {};
var self = this;
this.execute(self.buildQuerySchemas(options), cb);
};
/*!
* Build sql for listing tables
* @param options {all: for all owners, owner: for a given owner}
* @returns {string} The sql statement
*/
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryTables = function(options) {
throw new Error(g.f('{{buildQueryTables}} must be implemented by the connector'));
};
/*!
* Build sql for listing views
* @param options {all: for all owners, owner: for a given owner}
* @returns {string} The sql statement
*/
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryViews = function(options) {
throw new Error(g.f('{{buildQueryViews}} must be implemented by the connector'));
};
/**
* Discover model definitions
*
* @param {Object} options Options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverModelDefinitions = function(options, cb) {
if (!cb && typeof options === 'function') {
cb = options;
options = {};
}
options = options || {};
var self = this;
var calls = [function(callback) {
self.execute(self.buildQueryTables(options), callback);
}];
if (options.views) {
calls.push(function(callback) {
self.execute(self.buildQueryViews(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);
}
});
};
/**
* Build sql for listing columns
* @param {String} schema The schema name
* @param {String} table The table name
*/
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryColumns = function(schema, table) {
throw new Error(g.f('{{buildQueryColumns}} must be implemented by the connector'));
};
/**
* Map the property type from database to loopback
* @param {Object} columnDefinition The columnDefinition of the table/schema
* @param {Object} options The options for the connector
*/
SQLConnector.prototype.buildPropertyType = function(columnDefinition, options) {
throw new Error(g.f('{{buildPropertyType}} must be implemented by the connector'));
};
/*!
* Normalize the arguments
* @param table string, required
* @param options object, optional
* @param cb function, optional
*/
SQLConnector.prototype.getArgs = function(table, options, cb) {
throw new Error(g.f('{{getArgs}} must be implemented by the connector'));
};
/**
* Discover model properties from a table
* @param {String} table The table name
* @param {Object} options The options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverModelProperties = function(table, options, cb) {
var self = this;
var args = self.getArgs(table, options, cb);
var schema = args.schema;
table = args.table;
options = args.options;
if (!schema) {
schema = self.getDefaultSchema();
}
self.setDefaultOptions(options);
cb = args.cb;
var sql = self.buildQueryColumns(schema, table);
var callback = function(err, results) {
if (err) {
cb(err, results);
} else {
results.map(function(r) {
r.type = self.buildPropertyType(r, options);
self.setNullableProperty(r);
});
cb(err, results);
}
};
this.execute(sql, callback);
};
/*!
* Build the sql statement for querying primary keys of a given table
* @param schema
* @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)
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryPrimaryKeys = function(schema, table) {
throw new Error(g.f('{{buildQueryPrimaryKeys}} must be implemented by the connector'));
};
/**
* Discover primary keys for a given table
* @param {String} table The table name
* @param {Object} options The options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverPrimaryKeys = function(table, options, cb) {
var self = this;
var args = self.getArgs(table, options, cb);
var schema = args.schema;
if (typeof(self.getDefaultSchema) === 'function' && !schema) {
schema = self.getDefaultSchema();
}
table = args.table;
options = args.options;
cb = args.cb;
var sql = self.buildQueryPrimaryKeys(schema, table);
this.execute(sql, cb);
};
/*!
* Build the sql statement for querying foreign keys of a given table
* @param schema
* @param table
* @returns {string}
*/
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryForeignKeys = function(schema, table) {
throw new Error(g.f('{{buildQueryForeignKeys}} must be implemented by the connector'));
};
/**
* Discover foreign keys for a given table
* @param {String} table The table name
* @param {Object} options The options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverForeignKeys = function(table, options, cb) {
var self = this;
var args = self.getArgs(table, options, cb);
var schema = args.schema;
if (typeof(self.getDefaultSchema) === 'function' && !schema) {
schema = self.getDefaultSchema();
}
table = args.table;
options = args.options;
cb = args.cb;
var sql = self.buildQueryForeignKeys(schema, table);
this.execute(sql, cb);
};
/*!
* 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 schema
* @param table
* @returns {string}
*/
// Due to the different implementation structure of information_schema across
// connectors, each connector will have to generate its own query
SQLConnector.prototype.buildQueryExportedForeignKeys = function(schema, table) {
throw new Error(g.f('{{buildQueryExportedForeignKeys}} must be implemented by' +
'the connector'));
};
/**
* Discover foreign keys that reference to the primary key of this table
* @param {String} table The table name
* @param {Object} options The options for discovery
* @param {Function} [cb] The callback function
*/
SQLConnector.prototype.discoverExportedForeignKeys = function(table, options, cb) {
var self = this;
var args = self.getArgs(table, options, cb);
var schema = args.schema;
if (typeof(self.getDefaultSchema) === 'function' && !schema) {
schema = self.getDefaultSchema();
}
table = args.table;
options = args.options;
cb = args.cb;
var sql = self.buildQueryExportedForeignKeys(schema, table);
this.execute(sql, cb);
};
/**
* Discover default schema of a database
* @param {Object} options The options for discovery
*/
SQLConnector.prototype.getDefaultSchema = function(options) {
throw new Error(g.f('{{getDefaultSchema}} must be implemented by' +
'the connector'));
};
/**
* Set default options for the connector
* @param {Object} options The options for discovery
*/
SQLConnector.prototype.setDefaultOptions = function(options) {
throw new Error(g.f('{{setDefaultOptions}} must be implemented by' +
'the connector'));
};
/**
* Set the nullable value for the property
* @param {Object} property The property to set nullable
*/
SQLConnector.prototype.setNullableProperty = function(property) {
throw new Error(g.f('{{setNullableProperty}} must be implemented by' +
'the connector'));
};