Skip to content

Commit

Permalink
feat(model): FCC Models support multiple primaryKeys, dirty checking …
Browse files Browse the repository at this point in the history
…and better handling of underscores
  • Loading branch information
pilsy committed Jan 22, 2015
1 parent 72d09f8 commit e2bd7ab
Showing 1 changed file with 157 additions and 30 deletions.
187 changes: 157 additions & 30 deletions lib/classes/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var injector = require( 'injector' )
, util = require( 'util' )
, utils = require( 'utils' )
, debuggr = require( 'debug' )( 'Models' )
, _ = require( 'underscore' )
, inflect = require( 'i' )()
, Class = injector.getInstance( 'Class' )
, moduleLdr = injector.getInstance( 'moduleLoader' )
Expand Down Expand Up @@ -124,6 +125,15 @@ var Model = Class.extend(
}
}
},
TINYINT: function( length ) {
return {
type: this.TINYINT,
length: length,
toString: function() {
return this.type;
}
}
},
BIGINT: function( length ) {
return {
type: this.BIGINT,
Expand Down Expand Up @@ -177,26 +187,26 @@ var Model = Class.extend(

// The function you call to create a new model
extend: function() {
var extendingArgs = [].slice.call( arguments )
, modelName = ( typeof extendingArgs[ 0 ] === 'string' ) ? extendingArgs.shift() : false
, Static = ( extendingArgs.length === 2 ) ? extendingArgs.shift() : {}
, Proto = extendingArgs.shift()
, modelType = Static.type !== undefined ? Static.type : this.type
, moduleName = 'clever-' + modelType.toLowerCase()
, driver = null
, model = null
, debug = null;

extendingArgs = [ Static, Proto ];
var extendingArgs = [].slice.call( arguments )
, modelName = ( typeof extendingArgs[ 0 ] === 'string' ) ? extendingArgs.shift() : false
, Static = ( extendingArgs.length === 2 ) ? extendingArgs.shift() : {}
, Proto = extendingArgs.shift()
, modelType = Static.type !== undefined ? Static.type : this.type
, moduleName = 'clever-' + modelType.toLowerCase()
, driver = null
, model = null
, debug = null;

extendingArgs = [ Static, Proto ];

if ( !modelName ) {

var Reg = new RegExp( '.*\\(([^\\)]+)\\:.*\\:.*\\)', 'ig' )
, stack = new Error().stack.split( '\n' )
, file = stack.splice( 2, 1 );
var Reg = new RegExp( '.*\\(([^\\)]+)\\:.*\\:.*\\)', 'ig' )
, stack = new Error().stack.split( '\n' )
, file = stack.splice( 2, 1 );

if ( Reg.test( file ) ) {
modelName = RegExp.$1.split( path.sep ).pop().replace( '.js', '' );
modelName = RegExp.$1.split( path.sep ).pop().replace( '.js', '' );
} else {
throw new Error( 'Unable to determine model name.' );
}
Expand All @@ -213,8 +223,11 @@ var Model = Class.extend(

debuggr( [ modelName + 'Model: Defining model using', modelType, 'type...' ].join( ' ' ) );

Static._name = modelName;
Static.type = modelType;
Static._name = modelName;
Static.type = modelType;
Static.underscored = Static.underscored || this.underscored;
Static._customColumnNames = [];
Static.primaryKey = [];

debuggr( modelName + 'Model: Checking to see if the driver is installed and enabled...' );
if ( moduleLdr.moduleIsEnabled( moduleName ) !== true ) {
Expand All @@ -225,17 +238,20 @@ var Model = Class.extend(

debug( 'Checking for defined getters and setters...' );

Static._getters = Static._getters || {};
if ( Proto.getters !== undefined ) {
Static._getters = Proto.getters;
delete Proto.getters;
}

Static._setters = Static._setters || {};
if ( Proto.setters !== undefined ) {
Static._setters = Proto.setters;
delete Proto.setters;
}

debug( 'Defining schema...' );
Static._schema = {};
Object.keys( Proto ).forEach( this.callback( 'getSchemaFromProto', Proto, Static ) );

debug( 'Defining models this.debug() helper...' );
Expand Down Expand Up @@ -285,9 +301,16 @@ var Model = Class.extend(

// Private function used to build _schema so it can be passed to the _driver for schema creation
getSchemaFromProto: function( Proto, Static, key ) {
var prop = Proto[ key ];
var prop = Proto[ key ]
, columnName = !!this.underscored ? inflect.underscore( key ) : key;

if ( !!prop.columnName && key !== prop.columnName ) {
Static._customColumnNames.push( { key: key, columnName: prop.columnName } );
} else if ( !!Static.underscored && key !== columnName ) {
Static._customColumnNames.push( { key: key, columnName: columnName } );
}

if ( typeof prop === 'function' && [ String, Number, Boolean, Date, Buffer, Model.Types.ENUM, Model.Types.BIGINT, Model.Types.FLOAT, Model.Types.DECIMAL, Model.Types.TEXT ].indexOf( Proto[ key ] ) === -1 && key !== 'defaults') {
if ( typeof prop === 'function' && [ String, Number, Boolean, Date, Buffer, Model.Types.ENUM, Model.Types.TINYINT, Model.Types.BIGINT, Model.Types.FLOAT, Model.Types.DECIMAL, Model.Types.TEXT ].indexOf( Proto[ key ] ) === -1 && key !== 'defaults') {

} else if ( key !== 'defaults' ) {

Expand All @@ -308,11 +331,15 @@ var Model = Class.extend(
if ( key === 'id' && Static.type.toLowerCase() === 'odm' ) {
return this._model._id;
} else {
return this._model[ key ];
return this._model[ !!prop.columnName ? prop.columnName : columnName ];
}
};
Static._setters[ key ] = function( val ) {
this._model[ key ] = val;
Static._setters[ key ] = function( val ) {
this._dirty = true;
this._model[ !!prop.columnName ? prop.columnName : columnName ] = val;
this._changed.push( key );

return this;
};

delete Proto[ key ];
Expand Down Expand Up @@ -344,6 +371,23 @@ var Model = Class.extend(
}
}

if ( findOptions.where.id && that._primaryKey !== undefined && that._primaryKey !== 'id' && that._primaryKey.length === 1) {
findOptions.where[ that._primaryKey[ 0 ] ] = findOptions.where.id;
delete findOptions.where.id;
}

if ( findOptions.where && that._customColumnNames.length > 0 ) {
Object.keys( findOptions.where ).forEach( function( key ) {
var val = findOptions.where[ key ]
, newKey = _.findWhere( that._customColumnNames, { key: key } );

if ( newKey ) {
findOptions.where[ newKey.columnName ] = val;
delete findOptions.where[ key ];
}
});
}

// Make sure we have either an id or findOptions to find by models with
if ( !!isModel && !id && !findOptions ) {
return reject( new Exceptions.InvalidData( [ 'You must specify either an id or an object containing fields to find a', that._name ].join( ' ' ) ) );
Expand Down Expand Up @@ -396,13 +440,24 @@ var Model = Class.extend(
}

if ( findOptions.include ) {
var populate = [];
var populate = []
, addToPopulate = function( modelInclude, index, array, parentInclude ) {
var include = modelInclude.model.modelName || modelInclude.modelName;

findOptions.include.forEach( function( modelInclude ) {
populate.push( modelInclude.model.modelName );
});
if ( parentInclude ) {
include = parentInclude + '.' + include;
}

that._model.findOne( findOptions.where ).populate( populate.join( ' ' ) ).exec( callback );
populate.push( include );
if ( modelInclude.include ) {
modelInclude.include.forEach( function() {
addToPopulate.apply( this, [ arguments[ 0 ], arguments[ 1 ], arguments[ 2 ], include ] );
});
}
};

findOptions.include.forEach( addToPopulate );
that._model.findOne( findOptions.where ).deepPopulate( populate.join( ' ' ) ).exec( callback );

} else {
that._model.findOne( findOptions.where, callback );
Expand Down Expand Up @@ -528,6 +583,23 @@ var Model = Class.extend(
findOptions = typeof findOptions === 'object' ? findOptions : { where: findOptions };
options = options || {};

if ( findOptions && findOptions.where && that._primaryKey !== undefined && findOptions.where.id && that._primaryKey.length === 1 && that._primaryKey[ 0 ] !== 'id' ) {
findOptions.where[ that._primaryKey[ 0 ] ] = findOptions.where.id;
delete findOptions.where.id;
}

if ( findOptions.where && that._customColumnNames.length > 0 ) {
Object.keys( findOptions.where ).forEach( function( key ) {
var val = findOptions.where[ key ]
, newKey = _.findWhere( that._customColumnNames, { key: key } );

if ( newKey ) {
findOptions.where[ newKey.columnName ] = val;
delete findOptions.where[ key ];
}
});
}

return new Promise(function( resolve, reject ) {
async.waterfall(
[
Expand Down Expand Up @@ -576,7 +648,7 @@ var Model = Class.extend(
populate.push( modelInclude.model.modelName );
});

that._model.find( findOptions.where ).populate( populate.join( ' ' ) ).exec( callback );
that._model.find( findOptions.where ).deepPopulate( populate.join( ' ' ) ).exec( callback );

} else {
that._model.find( findOptions.where, callback );
Expand Down Expand Up @@ -622,6 +694,29 @@ var Model = Class.extend(
}
});
}
} else if ( modelType === 'ODM' ) {

if ( model !== null && findOptions.include && findOptions.include.length ) {
findOptions.include.forEach( function( _include ) {
var modelName = _include.model.modelName
, as = modelName
, csModel = models[ modelName ];

if ( !!csModel && !!model._model[ as ] ) {
if ( model._model[ as ] instanceof Array ) {
for ( var i = 0; i < model._model[ as ].length; i++ ) {
if ( !( model._model[ as ][ i ] instanceof csModel ) ) {
model._model._doc[ as ][ i ] = new csModel( model._model[ as ][ i ] );
}
}
} else {
if ( !( model._model[ as ] instanceof csModel ) ) {
model._model._doc[ as ] = new csModel( model[ as ] );
}
}
}
});
}
}
models.push( model );
}
Expand Down Expand Up @@ -676,6 +771,20 @@ var Model = Class.extend(
}
callback( null );
},

function handleCustomColumnNames( callback ) {
if ( that._customColumnNames.length ) {
that._customColumnNames.forEach( function( column ) {
if ( data[ column.key ] ) {
data[ column.columnName ] = data[ column.key ];
delete data[ column.key ];
}
});
callback( null );
} else {
callback( null );
}
},

function createModel( callback ) {
that.debug( 'create()' );
Expand Down Expand Up @@ -737,8 +846,13 @@ var Model = Class.extend(
{
_model: null,

_dirty: false,

_changed: [],

setup: function( model ) {
this._setModel( model );

Object.keys( this.Class._getters ).forEach( this.proxy( '_setupProperty' ) );

if ( this.Class.timeStampable ) {
Expand Down Expand Up @@ -773,7 +887,9 @@ var Model = Class.extend(
},

_setModel: function( _model ) {
this._model = _model;
this._dirty = false;
this._changed = [];
this._model = _model;
},

map: function() {
Expand Down Expand Up @@ -803,7 +919,7 @@ var Model = Class.extend(
if ( that.Class.type.toLowerCase() === 'orm' ) {

that._model
.save( that._model.values, options )
.save( _.pick( that._model.values, this._changed ), options )
.then( callback.bind( null, null ) )
.catch( callback )

Expand Down Expand Up @@ -914,6 +1030,13 @@ var Model = Class.extend(
}
});

this.Class._customColumnNames.forEach( function( columnName ) {
if ( json[ columnName.columnName ] !== undefined ) {
json[ columnName.key ] = json[ columnName.columnName ];
delete json[ columnName.columnName ];
}
});

return json;
},

Expand All @@ -926,6 +1049,10 @@ Model.Types.ENUM.toString = function() {
return 'ENUM';
};

Model.Types.TINYINT.toString = function() {
return 'TINYINT';
};

Model.Types.BIGINT.toString = function() {
return 'BIGINT';
};
Expand Down

0 comments on commit e2bd7ab

Please sign in to comment.