使用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
之间建立联系?
答案 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});