GraphQl Calculator 计算指令 @distinct:使用表达式对列表进行去重
问题背景
在实际的业务场景中,有时候有对列表元素进行去重的需求,比如对于用户列表、每个年龄段只保留一个用户;对于商品列表、每种品类只保留一个商品。
不同的业务场景往往有不同的去重需求,本文介绍通过表达式和指令、在 graphql 查询中以配置化的方式实现对列表去重,满足需求的快速开发和即时生效。
解决方案
定义指令
graphql 提供了指令机制用于执行能力的动态拓展、指令机制类似于 java 中的注解。
我们通过定义 @distinct 指令对列表数据进行去重,该指令只可用在列表类型字段上,其命名和语义参考了java.util.stream.Stream
。
comparator:使用该表达式计算元素的唯一 key,唯一 key 相同的元素会被去重,保留有序列表第一个元素。comparator 为可选参数,当未设置该参数时使用
System.identityHashCode(object)
判断元素是否为相同对象。对列表元素进行去重,当元素为基本类型时、表达式变量为 key 为ele
、value 为元素值。
示例查询
根据年龄对用户列表进行去重,每个年龄只保留一个用户。
代码实现
该能力可通过graphql-calculator实现,该组件是一款轻量级、高性能的 graphql 查询计算引擎。使用该组件对原有的GraphQLSchema
对象进行包装转换即可,具体步骤如下
继承 AsyncDataFetcherInterface
如果项目中使用了异步DataFetcher
,则使其则继承AsyncDataFetcherInterface
,并在方法实现中返回被包装的DataFetcher
和使用的线程池。
创建 GraphQLSource
使用配置类Config
创建GraphQLSource
对象,GraphQLSource
包含GraphQLSchema
和GraphQL
,配置类可指定脚本执行引擎、计算指令引擎使用的线程池和对象转换工具。
脚本语法使用了aviatorscript
,aviator 是 graphql-java-calculator 的默认表达行引擎,可通过ScriptEvaluator
和Config
自定义脚本执行引擎。
执行前校验
使用Validator
对计算指令的使用进行语法校验、该校验包含 graphql 原生语法校验,建议实现CalculatorDocumentCachedProvider
缓存校验结果。
完整示例参考Example
评论