Last active
May 8, 2018 16:08
-
-
Save amk221/87e5f358e5938eb42e822138592e5d00 to your computer and use it in GitHub Desktop.
Sequelize JSON API formatter
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
/** | |
* Outputs the result of a Sequelize query for JSONAPI | |
* | |
* e.g. | |
* let foo = yield models.Foo.findById(this.params.fooId); | |
* this.body = output(foo); | |
* | |
* Results in: | |
* | |
* { | |
* data: { | |
* type: 'Foo', | |
* id: 123, | |
* attributes: { | |
* myAttr: 'abcdef' | |
* }, | |
* relationships: { | |
* bar: { | |
* data: { | |
* id: 456, | |
* type: 'Bar' | |
* } | |
* } | |
* } | |
* }, | |
* included: [{ | |
* type: 'Bar', | |
* id: 546, | |
* attributes: { | |
* myAttr: 'ghijkl' | |
* } | |
* }] | |
* } | |
* | |
*/ | |
const _ = require('lodash'); | |
const { dasherise } = require('./string'); | |
function output(arg) { | |
if (Array.isArray(arg)) { | |
return outputMany(arg); | |
} else { | |
return outputOne(arg); | |
} | |
} | |
function getBasic(model) { | |
return { | |
type: dasherise(model.Model.name), | |
id: model.id.toString() | |
}; | |
} | |
function getAttributes(model) { | |
return Object.keys(model.rawAttributes).reduce((attributes, name) => { | |
let attribute = model.rawAttributes[name]; | |
if (!attribute.references) { | |
attributes[name] = model[name]; | |
} | |
return attributes; | |
}, {}); | |
} | |
function getAssociations(model) { | |
return Object.keys(model.Model.associations).reduce((associations, name) => { | |
let association = model[name]; | |
if (Array.isArray(association)) { | |
association.forEach(r => associations.push(r)); | |
} else { | |
associations.push(association); | |
} | |
return associations; | |
}, []); | |
} | |
function unique(model) { | |
return `${model.Model.name}:${model.id}`; | |
} | |
function getBasicRelationships(associations) { | |
return associations.reduce((relationships, association) => { | |
let name = dasherise(association.Model.name); | |
relationships[name] = getBasic(association); | |
return relationships; | |
}, {}); | |
} | |
function getIncluded(associations) { | |
return associations.map(association => { | |
let data = getBasic(association); | |
data.attributes = getAttributes(association); | |
return data; | |
}); | |
} | |
function getResult(model, associations) { | |
let result = getBasic(model); | |
result.attributes = getAttributes(model); | |
result.relationships = getBasicRelationships(associations); | |
return result; | |
} | |
function outputOne(model) { | |
let associations = getAssociations(model); | |
return { | |
data: getResult(model, associations), | |
included: getIncluded(associations) | |
}; | |
} | |
function outputMany(models) { | |
let results = []; | |
let allAssociations = []; | |
models.forEach(model => { | |
let associations = getAssociations(model); | |
let result = getResult(model, associations); | |
allAssociations.push(...associations); | |
results.push(result); | |
}); | |
return { | |
data: results, | |
included: getIncluded(_.uniqBy(allAssociations, unique)) | |
}; | |
} | |
module.exports = output; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is pretty cool.
Question: Am I understanding correctly that this is actually performing 2 queries rather than getting everything in one go (using
include
infindBy
)? Wouldn't that become a DB performance issue if you have many associations in a model?