Remove inheritence from DataSource to ModelBuilder

This commit is contained in:
Raymond Feng 2013-11-08 17:13:00 -08:00
parent 4c75bd4575
commit 7aa2eefec4
5 changed files with 73 additions and 52 deletions

View File

@ -53,7 +53,7 @@ var slice = Array.prototype.slice;
* });
* ```
*/
function DataSource(name, settings) {
function DataSource(name, settings, modelBuilder) {
if (!(this instanceof DataSource)) {
return new DataSource(name, settings);
}
@ -74,7 +74,9 @@ function DataSource(name, settings) {
settings = utils.parseSettings(settings);
}
ModelBuilder.call(this, name, settings);
this.modelBuilder = modelBuilder || new ModelBuilder();
this.models = this.modelBuilder.models;
this.definitions = this.modelBuilder.definitions;
// operation metadata
// Initialize it before calling setup as the connector might register operations
@ -113,8 +115,7 @@ function DataSource(name, settings) {
var fn = this.DataAccessObject.prototype[name];
if(typeof fn === 'function') {
var returns = fn.returns;
this.defineOperation(name, {
prototype: true,
accepts: fn.accepts,
@ -128,17 +129,12 @@ function DataSource(name, settings) {
}.bind(this));
}
util.inherits(DataSource, ModelBuilder);
util.inherits(DataSource, EventEmitter);
// allow child classes to supply a data access object
DataSource.DataAccessObject = DataAccessObject;
// Copy over statics
for (var m in ModelBuilder) {
if (!DataSource.hasOwnProperty(m) && 'super_' !== m) {
DataSource[m] = ModelBuilder[m];
}
}
/**
* Set up the connector instance for backward compatibility with JugglingDB schema/adapter
@ -322,7 +318,7 @@ DataSource.prototype.defineRelations = function(modelClass, relations) {
// Create a function for the closure in the loop
var createListener = function (name, relation, targetModel, throughModel) {
if (targetModel && targetModel.settings.unresolved) {
targetModel.once('defined', function (model) {
targetModel.once('dataSourceAttached', function (model) {
// Check if the through model doesn't exist or resolved
if (!throughModel || !throughModel.settings.unresolved) {
// The target model is resolved
@ -340,7 +336,7 @@ DataSource.prototype.defineRelations = function(modelClass, relations) {
}
if (throughModel && throughModel.settings.unresolved) {
// Set up a listener to the through model
throughModel.once('defined', function (model) {
throughModel.once('dataSourceAttached', function (model) {
if (!targetModel.settings.unresolved) {
// The target model is resolved
var params = {
@ -360,14 +356,14 @@ DataSource.prototype.defineRelations = function(modelClass, relations) {
for (var rn in relations) {
var r = relations[rn];
assert(DataSource.relationTypes.indexOf(r.type) !== -1, "Invalid relation type: " + r.type);
var targetModel = isModelClass(r.model) ? r.model : this.models[r.model];
var targetModel = isModelClass(r.model) ? r.model : this.getModel(r.model);
if (!targetModel) {
// The target model doesn't exist, let create a place holder for it
targetModel = this.define(r.model, {}, {unresolved: true});
}
var throughModel = null;
if (r.through) {
throughModel = isModelClass(r.through) ? r.through : this.models[r.through];
throughModel = isModelClass(r.through) ? r.through : this.getModel(r.through);
if (!throughModel) {
// The through model doesn't exist, let create a place holder for it
throughModel = this.define(r.through, {}, {unresolved: true});
@ -475,11 +471,15 @@ DataSource.prototype.createModel = DataSource.prototype.define = function define
}
}
var modelClass = ModelBuilder.prototype.define.call(this, className, properties, settings);
var modelClass = this.modelBuilder.define(className, properties, settings);
modelClass.dataSource = this;
if(settings.unresolved) {
return modelClass;
}
modelClass.emit('dataSourceAttached', modelClass);
this.setupDataAccess(modelClass, settings);
return modelClass;
};
@ -526,6 +526,14 @@ DataSource.prototype.mixin = function (ModelCtor) {
});
};
DataSource.prototype.getModel = function(name) {
return this.modelBuilder.getModel(name);
};
DataSource.prototype.getModelDefinition = function(name) {
return this.modelBuilder.getModelDefinition(name);
};
/**
* Attach an existing model to a data source.
*
@ -538,16 +546,19 @@ DataSource.prototype.attach = function (modelClass) {
return;
}
var className = modelClass.modelName;
var properties = modelClass.dataSource.definitions[className].properties;
var settings = modelClass.dataSource.definitions[className].settings;
var modelDef = modelClass.dataSource.getModelDefinition(className);
var properties = modelDef.properties;
var settings = modelDef.settings;
// redefine the dataSource
modelClass.dataSource = this;
// add to def
var def = new ModelDefinition(this, className, properties, settings);
var def = new ModelDefinition(this.modelBuilder, className, properties, settings);
def.build();
this.definitions[className] = def;
this.models[className] = modelClass;
this.modelBuilder.definitions[className] = def;
this.modelBuilder.models[className] = modelClass;
modelClass.emit('dataSourceAttached', modelClass);
this.setupDataAccess(modelClass, settings);
@ -562,9 +573,9 @@ DataSource.prototype.attach = function (modelClass) {
* @param {Object} params - property settings
*/
DataSource.prototype.defineProperty = function (model, prop, params) {
ModelBuilder.prototype.defineProperty.call(this, model, prop, params);
this.modelBuilder.defineProperty(model, prop, params);
var resolvedProp = this.definitions[model].properties[prop];
var resolvedProp = this.getModelDefinition(model).properties[prop];
if (this.connector.defineProperty) {
this.connector.defineProperty(model, prop, resolvedProp);
}
@ -1225,7 +1236,7 @@ DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb)
schemaList.push(schema);
}
var models = self.buildModels(schemaList);
var models = self.modelBuilder.buildModels(schemaList);
cb && cb(err, models);
});
};
@ -1252,7 +1263,7 @@ DataSource.prototype.discoverAndBuildModelsSync = function (modelName, options)
schemaList.push(schema);
}
var models = this.buildModels(schemaList);
var models = this.modelBuilder.buildModels(schemaList);
return models;
};
@ -1305,7 +1316,7 @@ DataSource.prototype.freeze = function freeze() {
* @param {String} modelName The model name
*/
DataSource.prototype.tableName = function (modelName) {
return this.definitions[modelName].tableName(this.connector.name);
return this.getModelDefinition(modelName).tableName(this.connector.name);
};
/**
@ -1315,7 +1326,7 @@ DataSource.prototype.tableName = function (modelName) {
* @returns {String} columnName
*/
DataSource.prototype.columnName = function (modelName, propertyName) {
return this.definitions[modelName].columnName(this.connector.name, propertyName);
return this.getModelDefinition(modelName).columnName(this.connector.name, propertyName);
};
/**
@ -1325,7 +1336,7 @@ DataSource.prototype.columnName = function (modelName, propertyName) {
* @returns {Object} column metadata
*/
DataSource.prototype.columnMetadata = function (modelName, propertyName) {
return this.definitions[modelName].columnMetadata(this.connector.name, propertyName);
return this.getModelDefinition(modelName).columnMetadata(this.connector.name, propertyName);
};
/**
@ -1334,7 +1345,7 @@ DataSource.prototype.columnMetadata = function (modelName, propertyName) {
* @returns {String[]} column names
*/
DataSource.prototype.columnNames = function (modelName) {
return this.definitions[modelName].columnNames(this.connector.name);
return this.getModelDefinition(modelName).columnNames(this.connector.name);
};
/**
@ -1343,7 +1354,7 @@ DataSource.prototype.columnNames = function (modelName) {
* @returns {String} columnName for ID
*/
DataSource.prototype.idColumnName = function(modelName) {
return this.definitions[modelName].idColumnName(this.connector.name);
return this.getModelDefinition(modelName).idColumnName(this.connector.name);
};
/**
@ -1352,10 +1363,10 @@ DataSource.prototype.idColumnName = function(modelName) {
* @returns {String} property name for ID
*/
DataSource.prototype.idName = function(modelName) {
if(!this.definitions[modelName].idName) {
console.log(this.definitions[modelName]);
if(!this.getModelDefinition(modelName).idName) {
console.error('No id name', this.getModelDefinition(modelName));
}
return this.definitions[modelName].idName();
return this.getModelDefinition(modelName).idName();
};
/**
@ -1364,7 +1375,7 @@ DataSource.prototype.idName = function(modelName) {
* @returns {String[]} property names for IDs
*/
DataSource.prototype.idNames = function (modelName) {
return this.definitions[modelName].idNames();
return this.getModelDefinition(modelName).idNames();
};
@ -1376,7 +1387,7 @@ DataSource.prototype.idNames = function (modelName) {
*/
DataSource.prototype.defineForeignKey = function defineForeignKey(className, key, foreignClassName) {
// quit if key already defined
if (this.definitions[className].rawProperties[key]) return;
if (this.getModelDefinition(className).rawProperties[key]) return;
if (this.connector.defineForeignKey) {
var cb = function (err, keyType) {
@ -1428,7 +1439,7 @@ DataSource.prototype.disconnect = function disconnect(cb) {
DataSource.prototype.copyModel = function copyModel(Master) {
var dataSource = this;
var className = Master.modelName;
var md = Master.dataSource.definitions[className];
var md = Master.dataSource.getModelDefinition(className);
var Slave = function SlaveModel() {
Master.apply(this, [].slice.call(arguments));
};
@ -1442,11 +1453,11 @@ DataSource.prototype.copyModel = function copyModel(Master) {
hiddenProperty(Slave, 'modelName', className);
hiddenProperty(Slave, 'relations', Master.relations);
if (!(className in dataSource.models)) {
if (!(className in dataSource.modelBuilder.models)) {
// store class in model pool
dataSource.models[className] = Slave;
dataSource.definitions[className] = new ModelDefinition(dataSource, md.name, md.properties, md.settings);
dataSource.modelBuilder.models[className] = Slave;
dataSource.modelBuilder.definitions[className] = new ModelDefinition(dataSource.modelBuilder, md.name, md.properties, md.settings);
if ((!dataSource.isTransaction) && dataSource.connector && dataSource.connector.define) {
dataSource.connector.define({
@ -1483,11 +1494,12 @@ DataSource.prototype.transaction = function() {
transaction.connector = dataSource.connector.transaction();
// create blank models pool
transaction.models = {};
transaction.definitions = {};
transaction.modelBuilder = new ModelBuilder();
transaction.models = transaction.modelBuilder.models;
transaction.definitions = transaction.modelBuilder.definitions;
for (var i in dataSource.models) {
dataSource.copyModel.call(transaction, dataSource.models[i]);
for (var i in dataSource.modelBuilder.models) {
dataSource.copyModel.call(transaction, dataSource.modelBuilder.models[i]);
}
transaction.exec = function(cb) {

View File

@ -55,6 +55,14 @@ function isModelClass(cls) {
return cls.prototype instanceof DefaultModelBaseClass;
}
ModelBuilder.prototype.getModel = function(name) {
return this.models[name];
};
ModelBuilder.prototype.getModelDefinition = function(name) {
return this.definitions[name];
};
/**
* Define a model class
*

View File

@ -34,9 +34,9 @@ Relation.hasMany = function hasMany(anotherClass, params) {
anotherClass = params.model;
} else {
var anotherClassName = i8n.singularize(anotherClass).toLowerCase();
for(var name in this.dataSource.models) {
for(var name in this.dataSource.modelBuilder.models) {
if (name.toLowerCase() === anotherClassName) {
anotherClass = this.dataSource.models[name];
anotherClass = this.dataSource.modelBuilder.models[name];
}
}
}
@ -187,9 +187,9 @@ Relation.belongsTo = function (anotherClass, params) {
anotherClass = params.model;
} else {
var anotherClassName = anotherClass.toLowerCase();
for(var name in this.dataSource.models) {
for(var name in this.dataSource.modelBuilder.models) {
if (name.toLowerCase() === anotherClassName) {
anotherClass = this.dataSource.models[name];
anotherClass = this.dataSource.modelBuilder.models[name];
}
}
}
@ -271,7 +271,7 @@ Relation.belongsTo = function (anotherClass, params) {
*/
Relation.hasAndBelongsToMany = function hasAndBelongsToMany(anotherClass, params) {
params = params || {};
var models = this.dataSource.models;
var models = this.dataSource.modelBuilder.models;
if ('string' === typeof anotherClass) {
params.as = anotherClass;

View File

@ -2,13 +2,14 @@
var should = require('./init.js');
var Schema = require('../').Schema;
var ModelBuilder = require('../').ModelBuilder;
describe('JSON property', function() {
var dataSource, Model;
it('should be defined', function() {
dataSource = getSchema();
Model = dataSource.define('Model', {propertyName: Schema.JSON});
Model = dataSource.define('Model', {propertyName: ModelBuilder.JSON});
var m = new Model;
(new Boolean('propertyName' in m)).should.eql(true);
should.not.exist(m.propertyName);

View File

@ -200,7 +200,7 @@ describe('DataSource define model', function () {
// define models
var Post = ds.define('Post', {
title: { type: String, length: 255 },
content: { type: DataSource.Text },
content: { type: ModelBuilder.Text },
date: { type: Date, default: function () {
return new Date();
} },
@ -211,7 +211,7 @@ describe('DataSource define model', function () {
// simpler way to describe model
var User = ds.define('User', {
name: String,
bio: DataSource.Text,
bio: ModelBuilder.Text,
approved: Boolean,
joinedAt: Date,
age: Number
@ -592,7 +592,7 @@ describe('Load models from json', function () {
// Read the dataSource JSON file
var schemas = JSON.parse(fs.readFileSync(schemaFile));
return dataSource.buildModels(schemas);
return dataSource.modelBuilder.buildModels(schemas);
}