问题背景
在使用 graphql 进行查询的时候,很多场景需要对 list 类型字段进行过滤筛选,例如过滤下架的商品、年龄不满 18 岁的用户、余量为 0 的优惠券等。
如下查询,如果要过滤未在售(onSale==false)的商品,需要在硬编码实现。
query itemListByIds($ItemIds:[Int]){
commodity{
itemList(itemIds: $ItemIds){
itemId
onSale
name
salePrice
}
}
}
复制代码
解决方案
graphql 提供了指令机制,该机制类似于 java 注解,可用于 graphql 查询执行能力的动态拓展。
定义对列表数据记性过滤的指令:predicate:过滤判断表达式,结果为 true 的元素会被保留。
directive @filter(predicate: String!) on FIELD
复制代码
修改后的查询为:
query filterUnSaleCommodity($ItemIds:[Int]){
commodity{
filteredItemList: itemList(itemIds: $ItemIds)
# 只保留在售的商品
@filter(predicate: "onSale")
{
itemId
onSale
name
salePrice
}
}
}
复制代码
具体实现
该能力可通过graphql-java-calculator进行实现,该组件基于指令系统、为 graphql 查询提供数据编排、动态计算和控制流的能力。
Config wrapperConfig = DefaultConfig.newConfig().build();
DefaultGraphQLSourceBuilder graphqlSourceBuilder = new DefaultGraphQLSourceBuilder();
GraphQLSource graphqlSource = graphqlSourceBuilder
.wrapperConfig(wrapperConfig)
.originalSchema(
// 原始schema对象
GraphQLSourceHolder.getDefaultSchema()
).build();
String query = "" +
"query filterUnSaleCommodity($itemIds:[Int]){\n" +
" commodity{\n" +
" itemList(itemIds: $itemIds)\n" +
" @filter(predicate: "onSale")\n" +
" {\n" +
" itemId\n" +
" onSale\n" +
" name\n" +
" salePrice\n" +
" }\n" +
" \n" +
" }\n" +
"}";
ExecutionInput input = ExecutionInput
.newExecutionInput(query)
.variables(Collections.singletonMap("itemIds", Arrays.asList(1, 2, 3)))
.build();
ExecutionResult result = graphqlSource.getGraphQL().execute(input);
复制代码
完整示例参考Example。
联系反馈
欢迎大家试用graphql-java-calculator,笔者毕业后一直从事 graphql 的平台化工作,graphql-java组件的活跃 contributor,期待使用反馈建议。
评论