我可能面临的设计限制是 Apollo GraphQL服务器 我想问一下是否有解决办法。
我的模式包含类型 Thing
,具有场 flag
. 我希望能够过滤 things
以 flag
但如果单独解决这个字段,似乎是不可能的。如果我想对这个字段进行排序,也会出现同样的问题。things
. 这是一个例子。
type Thing {
id: String!
flag Boolean!
}
type Query {
things(onlyWhereFlagIsTrue: Boolean): [Thing!]!
}
const resolvers = {
Thing: {
flag: async ({id}) => {
const value = await getFlagForThing(id);
return value;
}
},
Query: {
async things(obj, {onlyWhereFlagIsTrue = false}) {
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue) {
// ↓ this does not work, because flag is still undefined
result = _.filter(result, ['flag', true]);
}
return result;
}
}
}
有没有什么方法可以过滤 things
在所有异步字段都解决之后?我知道我可以调用 getFlagForThing(id)
里面 things
resolver,但这不就是在重复我自己吗?解析背后的逻辑是 flag
可以比只调用一个函数更复杂一些。
UPD: 这是我目前能找到的最好的解决方案。相当丑陋,而且很难扩展到其他字段。
const resolvers = {
Thing: {
flag: async ({id, flag}) => {
// need to check if flag has already been resolved
// to avoid calling getThingsWithoutFlags() twice
if (!_.isUndefined(flag)) {
return flag;
}
const value = await getFlagForThing(id);
return value;
}
},
Query: {
async things(obj, {onlyWhereFlagIsTrue = false}) {
let result = await getThingsWithoutFlags();
if (onlyWhereFlagIsTrue) {
// asynchroniously resolving flags when needed
const promises = _.map(result, ({id}) =>
getFlagForThing(id)
);
const flags = await Promise.all(promises);
for (let i = 0; i < flags.length; i += 1) {
result[i].flag = flags[i];
}
// ↓ this line works now
result = _.filter(result, ['flag', true]);
}
return result;
}
},
};
我认为这里的问题其实并不是Apollo服务器的限制,更多的是与你有一个带解析器的原始字段的事实有关。一般来说,只有当字段要返回一个单独的类型时,才最好对字段使用解析器。
Thing {
id: ID!
flag: Boolean!
otherThings: OtherThing
}
Query {
things(onlyWhereFlag: Boolean): [Thing!]!
}
在这个例子中,可以为以下字段单独设置一个解析器: otherThings
但如果一个字段是一个基元,那么我就会把这个字段和 Thing 一起解析。使用你的原始模式。
const filterByKeyValuePair = ([key, value]) => obj => obj[key] === value;
const resolvers = {
Query: {
async things(parent, { onlyWhereFlag }) {
const things = await Promise.all(
(await getThings()).map(
thing =>
new Promise(async resolve =>
resolve({
...thing,
flag: await getFlagForThing(thing)
})
)
)
);
if (onlyWhereFlag) {
return things.filter(filterByKeyValuePair(['flag', true]));
} else {
return things;
}
}
}
};
如果... flag
不是原始人吗?好吧,如果你想通过它来过滤,那么你将有几个不同的选项。这些选项实际上取决于你是如何获取 "标志 "数据的。如果你能提供更多关于你的模式和数据模型的细节,我很乐意详细说明。