盖茨比一对多关系

时间:2020-05-12 13:21:45

标签: javascript graphql gatsby

使用Gatsby.js,我想将许多静态文件转换为层次结构。这种层次结构的一个方面是一个“可执行文件”具有由该可执行文件生成的许多文件。我的可执行文件的GraphQL模式是:

exports.createSchemaCustomization = ({ actions: {createTypes}, schema }) => {
  createTypes([
    schema.buildObjectType({
      name: "CondaExecutable",
      fields: {
        wrappers: "[File]",
        name: "String!",
        path: "String!",
        publicURL: "String!",
      },  
      interfaces: ["Node"],
    }), 
  ])  
}

然后,我想将多个文件添加到新对象的wrapper字段中,我尝试在createPages中参照foreign key section in the Gatsby docs进行操作:

exports.createPages = async ({ graphql, actions, getNode, createContentDigest, createNodeId}) => {
  const { createNode, createNodeField, createPage, createParentChildLink } = actions
  const result = await graphql(`
        {
          allFile(filter: {sourceInstanceName: {in: ["Wrappers", "Definitions"]}}) {
            edges {
              node {
                id
                relativePath
                extension
                publicURL
              }
            }
          }
        }
  `)

  await Promise.all(result.data.allFile.edges.map(async ({ node }) => {
    // Now create the node for the single file within that package
    const exeId = createNodeId(...);
    let exe = getNode(exeId);
    if (!exe) {
      exe = {
        id: exeId,
        name: stem,
        path: node.relativePath.split('.')[0],
        publicURL: exeUrl,
        parent: versionId,
        wrappers: [],
        internal: {
          type: "CondaExecutable",
          contentDigest: node.relativePath
        }
      };
      await createNode(exe);
    }

    // Link the executable to the wrapper
    const wrappers = exe.wrappers || [];
    wrappers.push(node.id)
    createNodeField({node: exe, name: 'wrappers___NODE', value: wrappers});
  }));
}

很遗憾,此代码无法正常工作。我收到错误Cannot return null for non-nullable field File.id。无论如何,我并不惊讶这是错误的,因为我真的不知道我在这里做什么。

如何在自己的自定义类型和许多File之间建立联系?

1 个答案:

答案 0 :(得分:1)

正如文档的this section中更好地解释的那样,实现外键关系的方式因定义类型的方式而异。仅在使用自动类型推断时,才使用___NODE语法。如果您在GraphQL中定义了自定义类型而不是使用createTypes(),则可以为此目的使用@link指令。

如果您使用第三个选项createTypes()来定义您的自定义类型,则需要为外键实现resolve()。在我的一对多情况下,这意味着:

schema.buildObjectType({
  name: "CondaExecutable",
  fields: {
    wrappers: {
      type: "[File]",
      resolve(source, args, context, info){
        return context.nodeModel.getNodesByIds({
          ids: source.wrappers, // This matches the name of the field we're currently inside
          type: 'File' // This matches the type of the wrappers field
        })
      }
    },
    name: "String!",
    path: "String!",
    publicURL: "String!",
  },
  interfaces: ["Node"],
})

如果您改为一对一关系,则您的resolve函数将如下所示:

resolve(source, args, context, info){
  return context.nodeModel.getNodeById({
    id: source.wrapper,
    type: 'File'
  })
}

然后,要用createPages链接节点,就不必使用___NODE语法,但是每次添加时都必须对更新后的数组使用createNodeField一个新孩子:

const wrappers = exe.wrappers || [];
wrappers.push(node.id)
createNodeField({node: exe, name: 'wrappers', value: wrappers});