Skip to content

Instantly share code, notes, and snippets.

@luc0
Last active November 25, 2016 17:24
Show Gist options
  • Save luc0/33e9df2aeeb34736f0e3e5a3f29c069b to your computer and use it in GitHub Desktop.
Save luc0/33e9df2aeeb34736f0e3e5a3f29c069b to your computer and use it in GitHub Desktop.
Loopback: Extended ORM and Utils
var async = require('async');
var server = require('../../server/server.js');
var _ = require('underscore');
// Better abstraction for loopback. Extended functionality.
module.exports = function( app ) {
var lb = {};
//--------------
// HELPERS
//--------------
// Works with method 'observe' with 'before save' and 'after save'
lb.getInstanceToSave = function( ctx ){
if( ctx.instance ){
return ctx.instance; //create
}else if( ctx.currentInstance ){
return ctx.result; //update
}
};
lb.getLinkToSave = function( ctx ){
return ctx.args.data;
};
//--------------
// ORM
//--------------
// Destroy instances by ID
lb.destroyInstances = function( Model, instances ){
var intancesIds = [];
instances.forEach(function( current ){
intancesIds.push( current.id );
});
async.series({
instancesIds: function( cb ){
Model.destroyAll({ id : intancesIds },function(err){
if(err) return console.log('err',err);
cb(intancesIds);
});
}
}, function(err, results){
return results;
});
};
// Normalize relation in loopback, when we need data from the pivot table.
/*
REF:
ctx.result.notifications = lb.normalizeRelation({
data: profile.listNotifications(),
method: 'notification',
relationModel: Notification,
pivotModel: NotificationsProfiles,
relationHiddenFields: ['field1','...'],
pivotHiddenFields: ['field1','...']
});
*/
lb.normalizeRelation = function( fields ){
// prepare fields
var relationFields = [];
var pivotFields = [];
var prop;
for( prop in fields.relationModel.definition.properties ){
if( fields.relationHiddenFields.indexOf(prop) < 0 ){
relationFields.push(prop);
}
}
for( prop in fields.pivotModel.definition.properties ){
if( fields.pivotHiddenFields.indexOf(prop) < 0 ){
pivotFields.push(prop);
}
}
// reorder
var result = [];
fields.data.forEach(function( instance, i ){
result[i] = {};
pivotFields.forEach(function( prop, propIndex ){
result[i][prop] = instance[prop];
});
relationFields.forEach(function( prop, propIndex ){
result[i][prop] = instance[ fields.method ]()[prop];
});
});
return result;
};
// Update multiple w/ different values.
/*
REF:
var UpdateObject = new lb.MultiUpdate( {
model: 'modelName',
update: { conditionalField : ['updateField','...'] }
});
UpdateObject.add({
field: 'field',
when: 'conditionalField',
then: 'value'
}); // as many times as you like.
UpdateObject.run( callback );
*/
lb.MultiUpdate = function( config ){
this.updateQuery = [];
this.referenceModel = config.model;
this.updateField = config.update;
this.hasSomethingToSave = false;
};
lb.MultiUpdate.prototype.add = function( query ){
if( !this.updateQuery[ query.field ] ) this.updateQuery[ query.field ] = '';
this.updateQuery[ query.field ] += ' WHEN ' + query.when + ' THEN ' + query.then;
this.hasSomethingToSave = true;
};
lb.MultiUpdate.prototype.run = function( cb ){
var db = server.models[ this.referenceModel ].dataSource;
var sql = 'UPDATE `' + this.referenceModel + '` SET ';
var self = this;
var first = true;
for( var condition in self.updateField ){
self.updateField[condition].forEach(function( update, i ){
var field = self.updateField[condition][i];
if( self.updateQuery[ field ] ){
if(first){
first = false;
}else{
sql += ',';
}
sql += '`' + field + '` = CASE ' + condition + self.updateQuery[ field ] + ' ELSE `' + field + '` END';
}
});
}
if( this.hasSomethingToSave ){
db.connector.execute(sql, [], function(errUpdate, obj){
if(errUpdate) return console.log('errUpdate',errUpdate);
cb(null,{success:true});
});
}else{
cb(null,{success: 'no hubo cambios'});
}
};
//--------------
// SECURITY
//--------------
/* Avoid editing link ID - ( insert this in each model who has many to many relatons -> pivot table ) */
lb.forceLinkId = function( Model ){
//console.log('ForceId on'.red, Model.modelName , _.keys(Model.settings.relations));
var GUARDED = new lb.guarded({
'guarded' : ['id']
});
var relationsName = _.keys(Model.settings.relations);
relationsName.forEach(function( rel ){
Model.beforeRemote('*.__link__' + rel, function(ctx, remoteMethodOutput, next) {
var linkData = lb.getLinkToSave( ctx );
linkData = GUARDED.protect( linkData );
next();
});
});
};
// Protect fields for data injection
/*
REF:
var GUARDED = new lb.guarded({
"guarded" : ['scoreStarters','scoreSubstitutions','scoreResult','scoreGoals','scoreBestPlayer']
});
(THEN in before save):
instanceToSave = GUARDED.protect( instanceToSave );
*/
lb.guarded = function( config ){
this.GUARDED = config.guarded;
};
lb.guarded.prototype.protect = function( model ){
this.GUARDED.forEach(function( prop ){
model[ prop ] = null;
delete model[ prop ];
});
return model;
};
// It's not working as expected - Todo: check if exists, if not create it.
lb.findOrCreateMany = function( config, objectsToSave ){
this.model = config.model;
this.props = [];
this.values = [];
if( objectsToSave.length ){
for( var obj in objectsToSave[0] ){
this.props.push( obj );
}
}
objectsToSave.forEach( function( obj, val ){
for( var i in obj ){
if( _.isString(obj[i]) ) obj[i] = '"' + obj[i] + '"';
if( !_.isNumber(obj[i]) && _.isEmpty(obj[i]) ) obj[i] = '""';
}
this.values.push( _.values(obj).join(',') );
});
};
lb.findOrCreateMany.prototype.run = function( cb ){
var db = server.models[ this.model ].dataSource;
var sql = 'INSERT into `' + this.model + '` (' + this.props.join(',') + ') VALUES (' + this.values.join('),(') + ')';
// INSERT INTO table_listnames (name, address, tele)
// SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp
// WHERE NOT EXISTS (
// SELECT name FROM table_listnames WHERE name = 'Rupert'
// ) LIMIT 1;
if( this.props.length && this.values.length ){
db.connector.execute(sql, [], function(errUpdate, obj){
if(errUpdate) return console.log('errUpdate',errUpdate);
cb(null,{success:true});
});
}else{
cb(null,{success: 'no hubo cambios'});
}
};
return lb;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment