Last active
November 25, 2016 17:24
-
-
Save luc0/33e9df2aeeb34736f0e3e5a3f29c069b to your computer and use it in GitHub Desktop.
Loopback: Extended ORM and Utils
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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