Open sneznaovca opened 4 years ago
A couple of weeks ago I was experimenting with something and I needed to do something similar to this, I came up with this solution
class MyDataLoader extends DataLoader {
constructor(batchLoadFn, options) {
// Initialize the DataLoader class
super(batchLoadFn, options)
// A custom function to run before .load resolves.
// It doesn't do anything by default, it just returns what
// was passed to it
this._beforeResolveFn = row => row
}
// Overwrite the default load handler, so that we have a chance
// to run our custom method
// .loadMany is just a wrapper around .load, which is why we only need to
// overwrite this one.
async load(key) {
// Call the original load method, passing in the key,
// then run our middleware function, and after it resolves,
// return the result to the caller.
// You can imagine that we are trying to resolve a Many to Many relationship,
// where the result of calling super.load returns an array of foreign keys.
// We can then pipe them through another dataloader to get the actual objects
return super.load(key)
.then(this._beforeResolveFn)
}
// Sets a custom function to run before the .load promise resolves
async beforeResolve(fn) {
this._beforeResolveFn = fn
}
}
// Arbitrary usage
const ProductLoader = new MyDataLoader(...) // accepts productId
const CategoryLoader = new MyDataLoader(...) // accepts categoryId
// accepts productId, returns a list of categoryId's, like
// `SELECT * FROM productsCategories pc WHERE pc."productId" IN (...)`
const ProductCategoryLoader = new MyDataLoader()
// We know that the ProductCategoryLoader returns us an array of ids,
// So we pipe its result through the CategoryLoader, and after that resolves
// .load will return an array of categories to the ProductCategoryLoader.load callee
ProductCategoryLoader.beforeResolve(categoryIds => CategoryLoader.loadMany(categoryIds))
ProductCategoryLoader.load(1) // Product id
.then(categories => {...} ) // An array of categories
I figured it would somewhat simplify the more complex use-cases.
It requires extending the base class, but its a transparent wrapper by default. Also, I just wrote this in a text editor, didn't test this specific implementation, because I don't have access to my code at the moment, but the general idea is the same ( in case it doesn't work after copy/paste ).
Hi, is it possible chain two dataloaders? I have one resolver where I need using two dataloaders, is it possible? I can't use SQL join because it's slow.