基于Netflix DGS旧版本实现GraphQL Kotlin DSL查询的方案问询
实现Kotlin DSL风格的Netflix DGS Projection查询
完全可行,你可以通过为现有方法添加带初始化块参数的重载(不管是修改生成代码还是用Kotlin扩展函数)来实现目标DSL写法,具体方案分两种情况:
方案1:修改生成的Projection类(如果可以调整代码生成逻辑)
如果能修改DGS生成Projection类的模板,直接给每个方法添加重载版本:
生成的Foo类改造示例
class Foo : BaseProjectionNode { // 原方法保留 fun bar(): Bar { val bar = Bar() // add bar to output return bar } // 新增重载:接收子节点初始化块 fun bar(initializer: Bar.() -> Unit): Bar { return bar().apply(initializer) } // 原方法保留 fun yolo(): Foo { // add yolo to output return this } // 新增重载:支持DSL风格调用(可选空默认值,允许直接写yolo) fun yolo(initializer: Foo.() -> Unit = {}): Foo { return yolo().apply(initializer) } }
生成的Bar类改造示例
class Bar : BaseProjectionNode { // 原方法保留 fun baz(): Bar { // add baz to output return this } // 新增重载 fun baz(initializer: Bar.() -> Unit = {}): Bar { return baz().apply(initializer) } }
再添构造扩展函数
给根节点加个支持初始化块的构造扩展:
fun FooProjectionRoot(initializer: FooProjectionRoot.() -> Unit): FooProjectionRoot { return FooProjectionRoot().apply(initializer) }
这样就能直接用目标写法:
FooProjectionRoot { bar { baz } yolo }
方案2:用Kotlin扩展函数(无需修改生成的类)
如果无法调整DGS的代码生成逻辑,直接用Kotlin扩展函数给现有类补全重载方法:
// 给Foo类扩展bar的重载 fun Foo.bar(initializer: Bar.() -> Unit): Bar { return this.bar().apply(initializer) } // 给Foo类扩展yolo的重载 fun Foo.yolo(initializer: Foo.() -> Unit = {}): Foo { return this.yolo().apply(initializer) } // 给Bar类扩展baz的重载 fun Bar.baz(initializer: Bar.() -> Unit = {}): Bar { return this.baz().apply(initializer) } // 根节点构造扩展 fun FooProjectionRoot(initializer: FooProjectionRoot.() -> Unit): FooProjectionRoot { return FooProjectionRoot().apply(initializer) }
同样能实现目标DSL写法,完全不需要依赖原来的g辅助函数。
核心原理
Kotlin的函数重载和扩展函数特性允许我们在不修改原有类代码的前提下,新增符合DSL风格的方法:
- 对于返回子节点的方法(比如
bar()),重载版本调用原方法获取子节点后,用apply执行初始化块配置子节点字段 - 对于返回自身的标量方法(比如
yolo()),重载版本添加默认空初始化块,允许直接以yolo的形式在DSL中调用
内容的提问来源于stack exchange,提问作者fafl
相关产品推荐
相关产品推荐

