使用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
参照 外键部分:
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
s?
中解释得更好。本节 的文档,实现外键关系的方式根据你如何定义类型而不同。只有当你使用自动类型推理时,你才会使用 ___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(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});