ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Dagger 模块自定义标量类型 ScalarTypeDef:TypeScript 客户端 API 完全指南

Dagger 模块自定义标量类型 ScalarTypeDef:TypeScript 客户端 API 完全指南 Dagger 模块自定义标量类型 ScalarTypeDefTypeScript 客户端 API 完全指南【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger导读ScalarTypeDef是 Dagger 引擎中描述“模块内自定义标量类型custom scalar”的核心类型定义对象。在 Dagger 模块化体系中模块可以对外暴露自定义数据类型如自定义 ID、枚举之外的简单值类型而ScalarTypeDef就是这些标量在 GraphQL/DAG 执行引擎中的统一载体。本文以 docs/versioned_docs/version-0.19/reference/typescript/api/client.gen/classes/ScalarTypeDef.md 为骨架结合仓库源码sdk/typescript/src/api/client.gen.ts、core/typedef.go、core/schema/module.go完整讲解该类的构造约束、四个查询方法的语义、底层实现原理与真实调用链路帮助读者在 TypeScript 模块开发中正确理解和使用标量类型定义。类概述什么是 ScalarTypeDef根据 API 文档ScalarTypeDef的官方定义是A definition of a custom scalar defined in a Module.即在一个 Module 中定义的自定义标量的类型定义。它是 Dagger 类型系统TypeDef家族中用于描述标量scalar的一等公民。从源码结构看Dagger 的 TypeDef 家族包含多种“子类型定义”其中标量对应的正是ScalarTypeDef。在 core/typedef.go 中其 Go 侧核心结构如下type ScalarTypeDef struct { Name string field:true doc:The name of the scalar. doNotCache:simple field selection Description string field:true doc:A doc string for the scalar, if any. doNotCache:simple field selection OriginalName string // SourceModuleName is currently only set when returning the TypeDef from the Scalars field on Module SourceModuleName string field:true doc:If this ScalarTypeDef is associated with a Module, the name of the module. Unset otherwise. doNotCache:simple field selection }可以看到Go 侧字段与 TypeScript 客户端公开的四个属性一一对应字段含义Name标量的名称GraphQL 名称由NewScalarTypeDef构造时经strcase.ToCamel规范化Description标量的文档字符串可空SourceModuleName若该标量与某个 Module 关联则为该模块名否则为空OriginalName构造时传入的原始名称仅存在于 Go 引擎侧不暴露给 GraphQL API它在 TypeDef 类型体系中的位置ScalarTypeDef并非孤立存在它是TypeDef这个总类型kind 判别联合的一个分支。在 core/typedef.go 中引擎通过以下方式把标量挂接到通用TypeDef上func (typeDef *TypeDef) WithScalar(scalar dagql.ObjectResult[*ScalarTypeDef]) *TypeDef { typeDef typeDef.WithKind(TypeDefKindScalar) typeDef.AsScalar dagql.NonNull(scalar) return typeDef.syncName() } func (typeDef *TypeDef) WithScalarTypeDef(scalar dagql.ObjectResult[*ScalarTypeDef]) *TypeDef { typeDef typeDef.Clone() typeDef.Kind TypeDefKindScalar typeDef.AsScalar dagql.NonNull(scalar) return typeDef.syncName() }其中TypeDefKindScalar的注册描述为 “A scalar value of any basic kind.”见 core/typedef.go。这意味着当你看到TypeDef.Kind SCALAR_KIND时其AsScalar字段就是一个ScalarTypeDef。构造函数仅供内部使用禁止手动创建new ScalarTypeDef( ctx?: Context, _id?: ScalarTypeDefID, _description?: string, _name?: string, _sourceModuleName?: string ): ScalarTypeDef文档明确指出Constructor is used for internal usage only, do not create object from it.该构造函数参数如下参数类型说明ctx?ContextGraphQL 执行上下文由BaseClient维护_id?ScalarTypeDefID持久化标识符对应 GraphQL 的ScalarTypeDefID类型别名_description?string标量文档字符串_name?string标量名称_sourceModuleName?string关联模块名称在 TypeScript 实现中sdk/typescript/src/api/client.gen.ts构造函数只做两件事调用super(ctx)继承BaseClient并把四个可选值原样保存到私有只读字段_id、_description、_name、_sourceModuleName。这些私有字段会在对应方法中被“短路”使用——见下文各方法实现。实际上客户端代码不会直接new一个ScalarTypeDef而是通过两种途径获得实例GraphQL 响应反序列化在 sdk/typescript/src/api/client.gen.ts 中TypeDef.asScalar()方法把查询结果节点封装为ScalarTypeDef实例asScalar async (): PromiseScalarTypeDef | null { const ctx this._ctx.select(asScalar, ...) const response: AwaitedScalarTypeDef | null await ctx.execute() return new ScalarTypeDef(ctx.copy().selectNode(response, ScalarTypeDef)) }模块 SDK 的withScalar构造链路TypeScript 模块运行时通过dag.typeDef().withScalar(name)构造见下文调用链分析。实例方法详解ScalarTypeDef共暴露四个异步方法全部返回Promise与文档一一对应。以下逐个结合实现说明。id()获取唯一标识符id async (): PromiseScalarTypeDefID { if (this._id) { return this._id } const ctx this._ctx.select(id) const response: AwaitedScalarTypeDefID await ctx.execute() return response }若构造时已携带_id例如从反序列化结果中取得直接返回缓存值不发起网络请求否则向 GraphQL 服务器查询id字段并返回ScalarTypeDefID。ScalarTypeDefID是一个类型别名type alias它代表 Dagger 引擎生成的标量类型定义 ID。该 ID 在引擎侧对应持久化机制ScalarTypeDef实现了EncodePersistedObject/DecodePersistedObject见 core/typedef.go可将自身编码为persistedScalarTypeDefJSON 载荷通过 ID 在会话间恢复对象这正是 Dagger“一切皆 ID、懒执行”的核心设计。description()标量文档字符串description async (): Promisestring { if (this._description) { return this._description } const ctx this._ctx.select(description) const response: Awaitedstring await ctx.execute() return response }文档语义为 “A doc string for the scalar, if any.”——即标量的文档字符串可以为空。同样遵循“先查缓存、再发查询”的模式。name()标量名称name async (): Promisestring { if (this._name) { return this._name } const ctx this._ctx.select(name) const response: Awaitedstring await ctx.execute() return response }返回标量的名称The name of the scalar。注意引擎侧的NewScalarTypeDefcore/typedef.go会将传入名称通过strcase.ToCamel规范化为最终 GraphQL 名称原始名称保留在OriginalName中而WithNamecore/typedef.go则用于在重命名场景下直接写入已规范化的名称与ObjectTypeDef.WithName的处理方式一致避免二次规范化。sourceModuleName()来源模块名sourceModuleName async (): Promisestring { if (this._sourceModuleName) { return this._sourceModuleName } const ctx this._ctx.select(sourceModuleName) const response: Awaitedstring await ctx.execute() return response }文档语义为If this ScalarTypeDef is associated with a Module, the name of the module. Unset otherwise.即若该标量类型定义与某个 Module 关联返回该模块名否则为空字符串。从引擎注释core/typedef.go可知SourceModuleName目前只在通过Module上的Scalars字段返回TypeDef时才会被设置。而创建标量的入口scalarTypeDefcore/schema/module.go也支持可选的SourceModuleName内部参数func (s *moduleSchema) scalarTypeDef(ctx context.Context, _ *core.Query, args struct { Name string Description string default: SourceModuleName dagql.Optional[dagql.String] internal:true }) (*core.ScalarTypeDef, error) { scalar : core.NewScalarTypeDef(args.Name, args.Description) if args.SourceModuleName.Valid { scalar.SourceModuleName string(args.SourceModuleName.Value) } return scalar, nil }统一的“短路”执行模式四个方法共享同一实现模式若构造时已注入对应值则直接返回否则向引擎发起字段查询。这在 Dagger 的 TypeScript 客户端client.gen.ts中是一种通用优化——SDK 在反序列化时会把引擎已返回的字段缓存到实例上避免重复的 GraphQL 往返。所有方法均通过this._ctx.select(...)选择字段并execute()遵循BaseClient的懒加载lazy执行模型方法调用只记录查询意图真正执行发生在最终await时。引擎侧完整解析链路1. GraphQL Schema 注册ScalarTypeDef在引擎侧通过 dagql 注册为 GraphQL 对象类型。在 core/schema/module.go 附近可以看到dagql.Fields[*core.ScalarTypeDef]{...}的字段注册且模块 Schema 暴露了构造标量定义的顶层入口scalarTypeDef以及__withScalarTypeDef等内部工具函数core/schema/module.go。2. TypeDef 的 asScalar 分支当对TypeDef查询asScalar字段时引擎会取出TypeDef.AsScalar并返回其ScalarTypeDef实例对应 TypeScript 客户端 sdk/typescript/src/api/client.gen.ts 的asScalar()方法。在 core/typedef.go 附近可以看到引擎侧对该分支的类型断言处理attached.(dagql.ObjectResult[*ScalarTypeDef])。3. 模块 SDK 的 withScalar 注册链路在 TypeScript 模块运行时中当模块开发者把自定义类型注册进模块时addTypeDef函数sdk/typescript/src/module/entrypoint/register.ts会按 kind 分发case TypeDefKind.ScalarKind: return dag.typeDef().withScalar((type as ScalarTypeDef).name)即对SCALAR_KIND类型的 typedef仅取其.name调用dag.typeDef().withScalar(name)由引擎侧typeDefWithScalarcore/schema/module.go完成校验与构造。该处理器要求名称非空if args.Name { return nil, fmt.Errorf(scalar type def must have a name) }这印证了文档中name()是必填语义字段而description()是可选字段。4. 类型内省Introspection与标量在 TypeScript 模块的 introspection 工具中ScalarTypeDef被建模为“基础 typedef 的扩展”sdk/typescript/src/module/introspector/typedef.tsExtends the base typedef if its a scalar to add its name and real type.即当内省到 kind 为scalar时基础TypeDef会被扩展为ScalarTypeDef补上 name 与真实类型信息。这说明ScalarTypeDef在“引擎类型系统 ↔ 模块 SDK 类型系统”之间承担着标准化的桥梁作用。真实调用场景示例在 Dagger 模块中标量类型最常见的出现场景是模块定义自定义函数、参数或返回值时引擎需要为它们建立类型描述。例如一个返回自定义标量的模块函数其类型描述最终会以TypeDef{Kind: SCALAR_KIND, AsScalar: ScalarTypeDef{Name: MyScalar, Description: ...}}的形式被引擎持久化并暴露给客户端。在 TypeScript 客户端侧一个典型的查询片段如下示意对应四个方法import { connect } from dagger.io/dagger connect(async (client) { // 通过模块的类型信息获得 TypeDef 后取标量分支 const typeDef await client.module().scalars().name(MyScalar).typeDef() const scalar await typeDef.asScalar() const id await scalar?.id() // 唯一标识符 const name await scalar?.name() // 标量名 const desc await scalar?.description() // 文档字符串 const mod await scalar?.sourceModuleName() // 来源模块名未关联则为空 })注意实际获取ScalarTypeDef的方式取决于你的查询入口如通过module.scalars()、typeDef().asScalar()或自定义模块的构造链路上述代码用于展示方法语义具体字段路径请以你使用的 SDK 版本生成的 client 为准。测试与验证依据仓库中多处集成测试数据验证了标量类型定义的实际行为core/typedef_test.go 与 core/typedef_test_helpers_test.go覆盖TypeDef系列含标量分支的构造、序列化与往返core/schema/testdata/base_schema.graphqlsSchema 基准测试中包含ScalarTypeDef的 GraphQL 类型定义大量生成代码如 core/integration/testdata/modules/go/ifaces/internal/dagger/dagger.gen.go展示了各语言 SDK 生成的ScalarTypeDef相关客户端代码可作为跨语言对照。关键要点总结ScalarTypeDef是 Dagger 模块类型系统中描述自定义标量的标准对象与ObjectTypeDef、EnumTypeDef、ListTypeDef等并列通过TypeDef.AsScalar挂载在统一的TypeDef之上Kind 为SCALAR_KIND。构造函数仅供 SDK 内部使用业务代码不应手动new实例应通过 GraphQL 查询结果如typeDef.asScalar()或模块运行时构造链路获得。四个方法语义明确id()返回持久化标识符、name()返回标量名、description()返回可选文档字符串、sourceModuleName()返回关联模块名未关联时为空。全部方法采用“缓存短路 懒查询”模式SDK 反序列化时已缓存的字段直接返回未缓存的字段才会触发一次 GraphQL 查询。名称规范化发生在引擎侧NewScalarTypeDef会经strcase.ToCamel生成最终 GraphQL 名称且名称不可为空引擎会显式报错。SourceModuleName仅在通过Module的Scalars字段返回TypeDef时设置这是判断标量“归属模块”的关键信号。通过本文读者应能准确理解 Dagger TypeScript 客户端中ScalarTypeDef的完整语义、实现原理与调用场景从而在自定义 Dagger 模块的类型设计中正确使用这一 API。【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表