1

我正在实现光标分页以创建无限滚动的帖子,基于文档中 URQL 的简单分页示例。它工作得很好,我得到了我想要的所有信息的帖子......直到缓存通过在我的函数中设置info.partial为无效。然后我得到.truecursorPagination()project: null

我想知道我是否需要做一些特别的事情来缓存来自字段解析器(数据加载器)的结果?我还有其他关系,除了post.project它们的行为符合预期,所以它必须是这个字段解析器特有的东西......它是唯一可以为空的,也许它与这个事实有关,但为什么它最初会返回值和然后在info.partial设置为时丢失它true

这是我的代码,如果我应该分享更多内容以阐明问题,请告诉我。提前致谢。

createProjectLoader.ts

import DataLoader from "dataloader";
import { Project } from "../entities/Project";

export const createProjectLoader = () => new DataLoader<number, Project>(async projectIds => {
  const projects = await Project.findByIds(projectIds as number[]);

  const projectIdToProject: Record<number, Project> = {};

  projects.forEach(p => {
    projectIdToProject[p.id] = p;
  });

  return projectIds.map((projectId) => projectIdToProject[projectId])
})

解析器/post.ts

@FieldResolver(() => Project, { nullable: true })
  project(
    @Root() post: Post,
    @Ctx() { projectLoader }: MyContext
  ) {
    return post.projectId ? projectLoader.load(post.projectId) : undefined
  }

...

@Query(() => PaginatedPosts)
async posts(
  @Arg('limit', () => Int) limit: number,
  @Arg('cursor', () => String, { nullable: true }) cursor: string | null,
): Promise<PaginatedPosts> {
  const realLimit = Math.min(20, limit);
  const realLimitPlusOne = realLimit + 1;

  const replacements: any[] = [realLimitPlusOne];

  if (cursor) {
    replacements.push(new Date(parseInt(cursor)));
  }

  const posts = await getConnection().query(`
    select p.*
    from post p
    ${cursor ? `where p."createdAt" < $2` : ""}
    order by p."createdAt" DESC
    limit $1
  `,
    replacements
  )

  return {
    posts: posts.slice(0, realLimit),
    hasMore: posts.length === realLimitPlusOne
  };
}

创建UrqlClient.ts

const cursorPagination = (): Resolver => {
  return (_parent, fieldArgs, cache, info) => {
    const { parentKey: entityKey, fieldName } = info;

    const allFields = cache.inspectFields(entityKey);
    const fieldInfos = allFields.filter((info) => info.fieldName === fieldName);
    const size = fieldInfos.length;
    if (size === 0) {
      return undefined
    }

    const fieldKey = `${fieldName}(${stringifyVariables(fieldArgs)})`
    const isItInTheCache = cache.resolve(
      cache.resolveFieldByKey(entityKey, fieldKey) as string,
      'posts'
    );
    info.partial = !isItInTheCache;

    let hasMore = true;
    const results: string[] = [];
    fieldInfos.forEach(fi => {
      const key = cache.resolveFieldByKey(entityKey, fi.fieldKey) as string;
      const data = cache.resolve(key, 'posts') as string[];
      const _hasMore = cache.resolve(key, 'hasMore');
      if (!_hasMore) {
        hasMore = _hasMore as boolean;
      }
      results.push(...data);
    })

    return {
      __typename: 'PaginatedPosts',
      hasMore,
      posts: results
    }
  }
}
4

0 回答 0