问题背景
本文介绍 对于在某一业务场景中有依赖关系的信息、如何通过一个 graphql 查询返回关联数据。
mysql 中的子查询
mysql 中的子查询:当查询执行时,首先执行子查询并返回一个结果集。然后,将此结果集作为外部查询的输入。例如有活动表和商品表,查询出商品类活动涉及的商品信息如下:
-- 参与活动的商品信息
select *
from commodity_info_table
where id ink
(
-- 活动类型为 "commodity" 时、该id为商品id
select item_id
-- 包含活动类型、涉及主体id、活动开始时间、结束时间等
from activity_info_table
-- activity_type_code 为活动类型
where activity_type_code = "commodity"
)
复制代码
graphql 中的子查询
上述数据往往会有 商品 和 活动 两个研发小组维护,并通过接口提供服务。既无法通过子查询直接查询 DB,也不可能存在<font color = red> 获取所有活动商品详情数据</font>的接口。
如果活动接口数据和商品接口数据治理到 graphql 平台上,原生的 graphql 查询也难以通过一个查询直接获取这种关联数据。一般解决方案为使用两次查询解决,两次 io、并需要有相应的硬编码、硬逻辑支持:
graphql查询活动数据 ——> 解析活动中的商品id ——> graphql查询商品数据。
复制代码
解决方案
示例 schema
对于上述问题存在如下 graphql schema 定义:
type Query{
activityInfo(activityType:String): Actitivy
commodityList(commodityIds:[Int]): Commodity
}
type Actitivy{
id: Int
itemId: Int
activityType: String
# ...
}
type Commodity{
id: Int
name: String
price: Int
}
复制代码
定义计算指令
graphql 提供了指令机制用于 graphql 查询执行能力的动态拓展、指令机制类似于 java 中的注解。我们通过定义‘源数据指令’和‘参数转换指令’实现数据之间的依赖传递。
directive @argumentTransform(argumentName:String!, operateType:ParamTransformType!, expression:String!, dependencySources:[String!]) on FIELD
enum ParamTransformType{
MAP # 参数转换
FILTER # 列表类型参数过滤
LIST_MAP # 列表类型参数元素转换
}
复制代码
指令具体说明可参考graphql-calculator-README。通过指令实现的 graphql“子查询”如下:
query getActivityCommodityInfo{
# 根据活动类型获取活动信息
activityInfo(activityType:"commodity"){
# 将 活动商品id注册为源数据
itemId @fetchSource(name:"itemIdList")
}
commodityList(commodityIds: 1)
@argumentTransform(
argumentName:"commodityIds", # 进行转换的参数名称
operateType:MAP,expression:"itemIdList", # 转换类型和表达式
dependencySources:"itemIdList" # 依赖的源数据
){
id
# ......
}
}
复制代码
参考资料
评论