From a2da90867f5cb11a2142a73c067ca62dd517c64d Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Sat, 1 Jun 2013 23:03:25 -0700 Subject: [PATCH] Add sync versions of discovery --- lib/datasource.js | 226 +++++++++++++++++++++++++++++++++++++++++-- lib/model-builder.js | 1 + 2 files changed, 217 insertions(+), 10 deletions(-) diff --git a/lib/datasource.js b/lib/datasource.js index 77bdfe9f..eb740fbd 100644 --- a/lib/datasource.js +++ b/lib/datasource.js @@ -327,6 +327,15 @@ DataSource.prototype.discoverModels = function (options, cb) { } }; + +DataSource.prototype.discoverModelsSync = function (options) { + this.freeze(); + if (this.adapter.discoverModelsSync) { + return this.adapter.discoverModelsSync(options); + } + return null; +}; + /** * Discover properties for a given model. * @param owner The owner @@ -343,6 +352,14 @@ DataSource.prototype.discoverModelProperties = function (owner, table, cb) { } }; +DataSource.prototype.discoverModelPropertiesSync = function (owner, table) { + this.freeze(); + if (this.adapter.discoverModelPropertiesSync) { + return this.adapter.discoverModelPropertiesSync(owner, table); + } + return null; +}; + /** * Discover primary keys for a given owner/table * @@ -366,6 +383,14 @@ DataSource.prototype.discoverPrimaryKeys= function(owner, table, cb) { } } +DataSource.prototype.discoverPrimaryKeysSync= function(owner, table) { + this.freeze(); + if (this.adapter.discoverPrimaryKeysSync) { + return this.adapter.discoverPrimaryKeysSync(owner, table); + } + return null; +} + /** * Discover foreign keys for a given owner/table * @@ -393,6 +418,14 @@ DataSource.prototype.discoverForeignKeys= function(owner, table, cb) { } } +DataSource.prototype.discoverForeignKeysSync= function(owner, table) { + this.freeze(); + if (this.adapter.discoverForeignKeysSync) { + return this.adapter.discoverForeignKeysSync(owner, table); + } + return null; +} + function capitalize(str) { if (!str) { return str; @@ -413,8 +446,8 @@ function fromDBName(dbName, camelCase) { return parts.join(''); } -DataSource.prototype.discoverSchema = function (owner, table, cb) { - this.discoverSchemas(owner, table, {visited: {}, associations: false}, function(err, schemas) { +DataSource.prototype.discoverSchema = function (owner, tableOrView, cb) { + this.discoverSchemas(owner, tableOrView, {visited: {}, associations: false}, function(err, schemas) { if(err) { cb && cb(err, schemas); return; @@ -425,22 +458,23 @@ DataSource.prototype.discoverSchema = function (owner, table, cb) { } }); } + /** * Discover schema from a given table/view * @param owner * @param table * @param cb */ -DataSource.prototype.discoverSchemas = function (owner, table, options, cb) { +DataSource.prototype.discoverSchemas = function (owner, tableOrView, options, cb) { var self = this; var dataSourceName = this.name || this.adapter.name; var tasks = [ - this.discoverModelProperties.bind(this, owner, table), - this.discoverPrimaryKeys.bind(this, owner, table) ]; + this.discoverModelProperties.bind(this, owner, tableOrView), + this.discoverPrimaryKeys.bind(this, owner, tableOrView) ]; if (options.associations) { - tasks.push(this.discoverForeignKeys.bind(this, owner, table)); + tasks.push(this.discoverForeignKeys.bind(this, owner, tableOrView)); } async.parallel(tasks, function (err, results) { @@ -468,7 +502,7 @@ DataSource.prototype.discoverSchemas = function (owner, table, options, cb) { } var schema = { - name: fromDBName(table, false), + name: fromDBName(tableOrView, false), options: { idInjection: false // DO NOT add id property }, @@ -478,7 +512,7 @@ DataSource.prototype.discoverSchemas = function (owner, table, options, cb) { schema.options[dataSourceName] = { schema: columns[0].owner, - table: table + table: tableOrView }; columns.forEach(function (item) { @@ -502,9 +536,9 @@ DataSource.prototype.discoverSchemas = function (owner, table, options, cb) { }; }); - // Add current table to the visited tables + // Add current tableOrView to the visited tables options.visited = options.visited || {}; - var schemaKey = columns[0].owner + '.' + table; + var schemaKey = columns[0].owner + '.' + tableOrView; if (!options.visited.hasOwnProperty(schemaKey)) { if(self.settings.debug) { console.log('Adding schema for ' + schemaKey); @@ -570,6 +604,178 @@ DataSource.prototype.discoverSchemas = function (owner, table, options, cb) { }); } + +/** + * Discover schema from a given table/view + * @param owner + * @param table + * @param cb + */ +DataSource.prototype.discoverSchemasSync = function (owner, tableOrView, options) { + var self = this; + var dataSourceName = this.name || this.adapter.name; + + var columns = this.discoverModelPropertiesSync(owner, tableOrView); + if (!columns) { + return []; + } + + // Handle primary keys + var primaryKeys = this.discoverPrimaryKeysSync(owner, tableOrView); + var pks = {}; + primaryKeys.forEach(function (pk) { + pks[pk.columnName] = pk.keySeq; + }); + + if (self.settings.debug) { + console.log('Primary keys: ', pks); + } + + var schema = { + name: fromDBName(tableOrView, false), + options: { + idInjection: false // DO NOT add id property + }, + properties: { + } + }; + + schema.options[dataSourceName] = { + schema: columns[0].owner, + table: tableOrView + }; + + columns.forEach(function (item) { + var i = item; + + var propName = fromDBName(item.columnName, true); + schema.properties[propName] = { + type: item.type, + required: (item.nullable === 'N'), + length: item.dataLength + }; + + if (pks[item.columnName]) { + schema.properties[propName].id = pks[item.columnName]; + } + schema.properties[propName][dataSourceName] = { + columnName: i.columnName, + dataType: i.dataType, + dataLength: i.dataLength, + nullable: i.nullable + }; + }); + + // Add current tableOrView to the visited tables + options.visited = options.visited || {}; + var schemaKey = columns[0].owner + '.' + tableOrView; + if (!options.visited.hasOwnProperty(schemaKey)) { + if (self.settings.debug) { + console.log('Adding schema for ' + schemaKey); + } + options.visited[schemaKey] = schema; + } + + var otherTables = {}; + if (options.associations) { + // Handle foreign keys + var fks = {}; + var foreignKeys = this.discoverForeignKeysSync(owner, tableOrView); + foreignKeys.forEach(function (fk) { + var fkInfo = { + keySeq: fk.keySeq, + owner: fk.pkOwner, + tableName: fk.pkTableName, + columnName: fk.pkColumnName + }; + if (fks[fk.fkName]) { + fks[fk.fkName].push(fkInfo); + } else { + fks[fk.fkName] = [fkInfo]; + } + }); + + if (self.settings.debug) { + console.log('Foreign keys: ', fks); + } + + foreignKeys.forEach(function (fk) { + var propName = fromDBName(fk.pkTableName, true); + schema.properties[propName] = { + type: fromDBName(fk.pkTableName, false), + association: { + type: 'belongsTo', + foreignKey: fromDBName(fk.pkColumnName, true) + } + }; + + var key = fk.pkOwner + '.' + fk.pkTableName; + if (!options.visited.hasOwnProperty(key) && !otherTables.hasOwnProperty(key)) { + otherTables[key] = {owner: fk.pkOwner, tableName: fk.pkTableName}; + } + }); + } + + if (Object.keys(otherTables).length === 0) { + return options.visited; + } else { + var moreTasks = []; + for (var t in otherTables) { + if (self.settings.debug) { + console.log('Discovering related schema for ' + schemaKey); + } + self.discoverSchemasSync(otherTables[t].owner, otherTables[t].tableName, options); + } + return options.visited; + + } +} + +/** + * Discover and build models from the given owner/tableOrView + * @param owner + * @param tableOrView + * @param options + * @param cb + */ +DataSource.prototype.discoverAndBuildModels = function (owner, tableOrView, options, cb) { + this.discoverSchemas(owner, tableOrView, options, function (err, schemas) { + if (err) { + cb && cb(err, schemas); + return; + } + + var schemaList = []; + for (var s in schemas) { + var schema = schemas[s]; + schemaList.push(schema); + } + ; + + var models = this.buildModels(schemaList); + cb && cb(err, models); + }); +} + +/** + * Discover and build models from the given owner/tableOrView synchronously + * @param owner + * @param tableOrView + * @param options + */ +DataSource.prototype.discoverAndBuildModelsSync = function (owner, tableOrView, options) { + var schemas = this.discoverSchemasSync(owner, tableOrView, options); + + var schemaList = []; + for (var s in schemas) { + var schema = schemas[s]; + schemaList.push(schema); + } + + var models = this.buildModels(schemaList); + return models; +} + /** * Check whether migrations needed * This method make sense only for sql adapters. diff --git a/lib/model-builder.js b/lib/model-builder.js index a04efd35..8f288b32 100644 --- a/lib/model-builder.js +++ b/lib/model-builder.js @@ -391,6 +391,7 @@ function getSchemaType(type) { if (type.type) { return getSchemaType(type.type); } else { + console.error(type); throw new Error('Missing type property'); } }