Created
November 18, 2017 03:13
-
-
Save RichAyotte/cb4cae6147f2f8ca1c31371b640793b5 to your computer and use it in GitHub Desktop.
Sequelize Dataloader Advices
This file contains hidden or 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
/** | |
* @overview Sequelize find - dataloader advice | |
* @author Richard Ayotte | |
* @copyright Copyright © 2017 Richard Ayotte | |
* @date 2017-11-03 | |
* @license GNU GPL-3.0 | |
* @flow | |
*/ | |
'use strict' | |
const DataLoader = require('dataloader') | |
const hash = require('object-hash') | |
const { | |
find | |
, get | |
, isPlainObject | |
, union | |
} = require('lodash') | |
const {Op} = require('sequelize') | |
const log = require('../../lib/log') | |
const loaders = new Map() | |
const symbolKeysToStrings = obj => { | |
const newObj = {} | |
Object.getOwnPropertySymbols(obj).forEach(k => { | |
newObj[String(k)] = isPlainObject(obj[k]) ? symbolKeysToStrings(obj[k]) : obj[k] | |
}) | |
Object.keys(obj).forEach(k => { | |
newObj[k] = isPlainObject(obj[k]) ? symbolKeysToStrings(obj[k]) : obj[k] | |
}) | |
return newObj | |
} | |
module.exports = function adviseDataloader({args, proceed, proceedCount, target}) { | |
const [options, transaction] = args | |
const where = get(options, 'where') | |
let id | |
// Don't dataload when there's not where. | |
if (!where) { | |
return proceed() | |
} | |
const whereKeys = [ | |
...Object.keys(where) | |
, ...Object.getOwnPropertySymbols(where) | |
] | |
// Don't dataload if 'or' is found in the where keys. | |
if (whereKeys.includes(Op.or) || whereKeys.includes('$or')) { | |
return proceed() | |
} | |
// Only look into the where object 1 level deep. I don't think I'll need to | |
// go much deeper so leaving the recursive complexity out for now. RA | |
if (whereKeys.includes('id')) { | |
id = where.id | |
delete where.id | |
} | |
else if (whereKeys.includes(Op.and)) { | |
if (!where[Op.and].id) { | |
return proceed() | |
} | |
id = where[Op.and].id | |
delete where[Op.and].id | |
} | |
if (!id) { | |
return proceed() | |
} | |
// Create a new where object with all the Symbols transformed into strings. | |
const loaderWhere = symbolKeysToStrings(where) | |
const loaderId = hash( | |
JSON.stringify({ | |
attributes: options.attributes | |
, include: options.include | |
, table: target.tableName | |
, where | |
}) | |
, { | |
encoding: 'binary' | |
} | |
) | |
let loader = loaders.get(loaderId) | |
if (!loader) { | |
loader = new DataLoader(function(keys) { | |
return proceed({ | |
meta: options.meta | |
, attributes: union(['id'], options.attributes) | |
, where: { | |
[Op.and]: { | |
id: [...new Set(keys)] | |
, ...where | |
} | |
} | |
}) | |
.then(sqlResult => { | |
return keys.reduce((result, key) => { | |
result.push(find(sqlResult, {id: key})) | |
return result | |
}, []) | |
}) | |
}, { cache: false }) | |
loaders.set(loaderId, loader) | |
} | |
return loader.load(id) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment