如何在Typescript中将自定义对象参数传递给Dataloader?

gupuwyp2  于 2023-06-24  发布在  TypeScript
关注(0)|答案(1)|浏览(149)

我正在尝试将一个对象作为键传递给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}"

vcirk6k6

vcirk6k61#

cacheKeyFn的输出应该是像stringnumber这样的简单值。我认为这应该起作用:

new DataLoader<{postId: number; userId: number}, Upvote | null, string> (
    async keys => { ... }, // batchLoadFn
    {
        cacheKeyFn: ({postId: number, userId: number}) => `${postId}:${userId}`
    }
);

要测试键的唯一性,DataLoader将调用cacheKeyFn并使用结果进行比较。在这里,我们创建一个字符串${postId}:${userId}。批量加载fn将接收原始对象,而不是字符串。参见:https://stackoverflow.com/a/59349421

相关问题