我正在尝试将一个对象作为键传递给Dataloader的示例。我知道我必须做一个自定义的缓存键函数,但我不知 prop 体怎么做。我在网上学习这个教程:https://www.youtube.com/watch?v=I6ypD7qv3Z8&t=41601s&ab_channel=BenAwad
它有点过时了,所以我不能完全理解它。
我这样调用dataload函数:
@FieldResolver(()=> Int, {nullable:true})
async voteStatus(
@Root() post: Post,
@Ctx() {upvoteLoader, req}: MyContext){
if (!req.session.userId) {
return null
}
const key = {
postId: post.id,
userId: req.session.userId
}
const upvote = await upvoteLoader.load(key)
console.log("upvote data: ", upvote)
return null
// const upvote = await upvoteLoader.loadMany(key)
// console.log("after")
// return upvote ? upvote.value : null
}
查看DataLoader的代码,我得到了这样的结果:
declare class DataLoader<K, V, C = K> {
constructor(
batchLoadFn: DataLoader.BatchLoadFn<K, V>,
options?: DataLoader.Options<K, V, C>,
); ... }
declare namespace DataLoader {
// If a custom cache is provided, it must be of this type (a subset of ES6 Map).
export type CacheMap<K, V> = {
get(key: K): V | void;
set(key: K, value: V): any;
delete(key: K): any;
clear(): any;
};
...
/**
* Default `key => key`. Produces cache key for a given load key. Useful
* when keys are objects and two objects should be considered equivalent.
*/
cacheKeyFn?: (key: K) => C;
我为该高速缓存键创建了一个自定义函数。我试过几种不同的方法。(我以后会给你起更好的名字)
方式一:
class C {
postId: number;
userId: number;
constructor(postId:number, userId: number) {
this.postId = postId
this.userId = userId
}
}
function cacheKeyFn({postId, userId}: {postId:number, userId: number }) {
const c = new C(postId, userId)
return c;
}
export const createUpvoteLoader = () =>
new DataLoader<{postId: number; userId: number}, Upvote | null, C> (async (keys)=>{
console.log("my keys are ", keys)
const upvotes = await Upvote.findBy({
postId: In((keys).postId as any[]),
userId: In(keys as any[])
})
const UpvoteIdsToUpvote: Record<string, Upvote> = {}
upvotes.forEach(upvote => {
UpvoteIdsToUpvote[`${upvote.userId}|${upvote.postId}`] = upvote
})
return keys.map(key => UpvoteIdsToUpvote[`${key.userId}|${key.postId}`])
}, {cacheKeyFn})
方式二:
function cacheKeyFn({postId, userId}: {postId:number, userId: number }) {
return {"postId": postId, "userId":userId};
}
export const createUpvoteLoader = () =>
new DataLoader<{postId: number; userId: number}, Upvote | null> (async (keys)=>{
const upvotes = await Upvote.findBy({
postId: In(keys as any[]),
userId: In(keys as any[])
})
const UpvoteIdsToUpvote: Record<string, Upvote> = {}
upvotes.forEach(upvote => {
UpvoteIdsToUpvote[`${upvote.userId}|${upvote.postId}`] = upvote
})
return keys.map(key => UpvoteIdsToUpvote[`${key.userId}|${key.postId}`])
}, {cacheKeyFn})
方式3(理智):
export const createUpvoteLoader = () =>
new DataLoader<{postId: number; userId: number}, Upvote | null> (async (keys)=>{
const upvotes = await Upvote.findBy({
postId: In(keys as any[]),
userId: In(keys as any[])
})
const UpvoteIdsToUpvote: Record<string, Upvote> = {}
upvotes.forEach(upvote => {
UpvoteIdsToUpvote[`${upvote.userId}|${upvote.postId}`] = upvote
})
return keys.map(key => UpvoteIdsToUpvote[`${key.userId}|${key.postId}`])
})
不断出现的错误是:driverError: error: invalid input syntax for type integer: "{"postId":317,"userId":2}"
1条答案
按热度按时间vcirk6k61#
cacheKeyFn
的输出应该是像string
或number
这样的简单值。我认为这应该起作用:要测试键的唯一性,DataLoader将调用
cacheKeyFn
并使用结果进行比较。在这里,我们创建一个字符串${postId}:${userId}
。批量加载fn将接收原始对象,而不是字符串。参见:https://stackoverflow.com/a/59349421