ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

NocoBase RunJS 上下文实战:用 ctx.dataSource 访问数据源、数据表与字段元数据

NocoBase RunJS 上下文实战:用 ctx.dataSource 访问数据源、数据表与字段元数据 NocoBase RunJS 上下文实战用 ctx.dataSource 访问数据源、数据表与字段元数据【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase在 NocoBase 的 RunJS 执行环境中ctx.dataSource是连接“无代码界面”与“数据模型元数据”的关键入口它是当前执行上下文绑定的数据源实例DataSource让你在已知当前数据源时直接获取数据表Collection、字段定义以及关联字段Association并管理当前数据源下的数据表配置。读完本文你将掌握ctx.dataSource的全部常用属性与方法、collectionName.fieldPath路径语法的工作原理、它与ctx.dataSourceManager跨数据源入口的分工边界并能结合 flow-engine 中的 DataSource 实现 理解其底层机制从而在 RunJS 脚本中完成数据表枚举、动态校验、按路径取字段等实战场景。一、什么是 ctx.dataSourcectx.dataSource的类型是DataSource表示当前 RunJS 执行上下文绑定的数据源实例。通常对应当前页/区块选中的数据源如主库main。属性/成员类型说明keystring数据源 key如mainnamestring同 keydisplayNamestring显示名称支持 i18nflowEngineFlowEngine当前 FlowEngine 实例从源码实现看这些属性都是DataSource类上的 getterkey与name直接返回options.keydisplayName会先通过flowEngine.translate(this.options.displayName, { ns: lm-collections })做多语言翻译翻译不到时才回退为 key。相关实现见 DataSource 类定义get displayName() { return this.flowEngine.translate(this.options.displayName, { ns: lm-collections }) || this.key; } get key() { return this.options.key; } get name() { return this.options.key; }这说明displayName是可以被界面多语言覆盖的展示名而key才是程序访问数据源时应当使用的稳定标识。适用场景场景说明单数据源操作在已知当前数据源时获取数据表、字段元数据数据表管理获取/添加/更新/删除当前数据源下的数据表按路径获取字段使用collectionName.fieldPath格式获取字段定义支持关联路径注意ctx.dataSource表示当前上下文的单一数据源若要枚举或访问其他数据源请使用 ctx.dataSourceManager。二、类型定义与 API 全貌DataSource在 RunJS 上下文中暴露的核心 API 如下dataSource: DataSource; class DataSource { constructor(options?: Recordstring, any); // 只读属性 get flowEngine(): FlowEngine; // 当前 FlowEngine 实例 get displayName(): string; // 显示名称支持 i18n get key(): string; // 数据源 key如 main get name(): string; // 同 key // 数据表读取 getCollections(): Collection[]; // 获取所有数据表 getCollection(name: string): Collection | undefined; // 按名称获取数据表 getAssociation(associationName: string): CollectionField | undefined; // 获取关联字段如 users.roles // 数据表管理 addCollection(collection: Collection | CollectionOptions): void; updateCollection(newOptions: CollectionOptions): void; upsertCollection(options: CollectionOptions): Collection | undefined; upsertCollections(collections: CollectionOptions[], options?: { clearFields?: boolean }): void; removeCollection(name: string): void; clearCollections(): void; // 字段元数据 getCollectionField(fieldPath: string): CollectionField | undefined; }与类型声明一一对应的是 flow-engine 中 DataSource 的源码这些方法大多是对内部CollectionManager的委托例如getCollections()返回this.collectionManager.getCollections()getCollection(name)返回this.collectionManager.getCollection(name)。这带来两个实践结论所有数据表状态都保存在CollectionManager中。CollectionManager使用observable.shallowMapstring, Collection存放数据表见 CollectionManager 构造函数对数据表进行增删改时会自动重置继承链缓存resetCaches因此在 RunJS 中调用upsertCollections等写方法后后续读取的元数据立即可见且保持响应式。旧拼写getAssocation已标记废弃源码中保留了getAssocation(associationName)作为兼容别名并转发到getAssociation见 getAssociation 实现。新脚本请统一使用getAssociation。常用方法速查方法说明getCollections()获取当前数据源下所有数据表已排序、过滤隐藏getCollection(name)按名称获取数据表name可为collectionName.fieldName获取关联目标数据表getAssociation(associationName)按collectionName.fieldName获取关联字段定义getCollectionField(fieldPath)按collectionName.fieldPath获取字段定义支持关联路径如users.profile.avatar三、getCollectionField路径解析的工作原理getCollectionField(fieldPath)的入参格式为collectionName.fieldPath第一段为数据表名后续为字段路径支持关联如user.name。其解析逻辑在源码中非常清晰getCollectionField 实现getCollectionField(fieldPath: string) { const [collectionName, ...otherKeys] fieldPath.split(.); const fieldName otherKeys.join(.); const collection this.getCollection(collectionName); if (!collection) { return; } const field collection.getFieldByPath(fieldName); if (!field) { return; } return field; }可以看出三步解析过程按.拆分第一段解析出collectionName其余拼回为字段路径通过this.getCollection(collectionName)拿到数据表——如果数据表不存在则直接返回undefined调用数据表的getFieldByPath(fieldName)沿字段路径逐段查找中途任一段不存在都会返回undefined。因此调用方必须对返回结果做空值判断。与它相对的是跨数据源版本 DataSourceManager.getCollectionField先拆出第一段作为数据源 key 取出对应数据源再把剩余路径交给该数据源的getCollectionField处理即main.users.profile.avatar等价于“在 main 数据源内执行getCollectionField(users.profile.avatar)”。四、实战示例以下示例继承自官方文档均假设 RunJS 上下文已绑定当前数据源。4.1 获取数据表及字段// 获取所有数据表 const collections ctx.dataSource.getCollections(); // 按名称获取数据表 const users ctx.dataSource.getCollection(users); const primaryKey users?.filterTargetKey ?? id; // 按「数据表.字段路径」获取字段定义支持关联 const field ctx.dataSource.getCollectionField(users.profile.avatar); const userNameField ctx.dataSource.getCollectionField(orders.createdBy.name);要点filterTargetKey是数据表的主键字段名filterTargetKey在 CollectionOptions 类型 中定义为string | Arraystring未配置时应回退到默认的id。4.2 获取关联字段// 按 collectionName.fieldName 获取关联字段定义 const rolesField ctx.dataSource.getAssociation(users.roles); if (rolesField?.isAssociationField()) { const targetCol rolesField.targetCollection; // 按目标数据表结构处理 }getAssociation(users.roles)返回的是roles这个关联字段的定义本身targetCollection则指向关联指向的目标数据表便于你按目标表结构继续做元数据操作。4.3 遍历数据表做动态处理const collections ctx.dataSource.getCollections(); for (const col of collections) { const fields col.getFields(); const requiredFields fields.filter((f) f.options?.required); // ... }从 ICollection 接口定义 可以看到数据表对象提供getFields()、getField(name)、getFieldByField(field)、setField、removeField、updateOptions等能力且每个字段都带有options: FieldOptions。FieldOptions中除name、type、interface外还包含primaryKey、unique、allowNull、autoIncrement、defaultValue等数据库语义字段见 FieldOptions 类型这些正是遍历数据表做“必填项统计”“主键推断”等动态处理时的判断依据。4.4 根据字段元数据做校验或动态 UIconst field ctx.dataSource.getCollectionField(users.status); if (field) { const options field.enum ?? []; const operators field.getFilterOperators(); // 根据 interface、enum、validation 等做 UI 或校验 }典型应用读取field.interface决定渲染哪种输入控件读取field.enum生成下拉选项调用field.getFilterOperators()获取该字段支持的筛选运算符集合从而在 RunJS 驱动的表单/筛选器中自动生成校验规则。五、ctx.dataSource 与 ctx.dataSourceManager 的分工两者同属 RunJS 上下文但职责边界不同选择错误的入口是常见的脚本错误来源需求推荐用法当前上下文绑定的单一数据源ctx.dataSource所有数据源入口ctx.dataSourceManager当前数据源内获取数据表ctx.dataSource.getCollection(name)跨数据源获取数据表ctx.dataSourceManager.getCollection(dataSourceKey, collectionName)当前数据源内获取字段ctx.dataSource.getCollectionField(users.profile.avatar)跨数据源获取字段ctx.dataSourceManager.getCollectionField(main.users.profile.avatar)从源码结构看DataSourceManager内部维护dataSources: Mapstring, DataSource这一注册表见 DataSourceManager 类并提供addDataSource/upsertDataSource/removeDataSource/clearDataSources等管理方法。两点值得注意addDataSource在 key 已存在时会直接抛出DataSource with name ${ds.key} already exists异常需要“覆盖或新增”语义时应改用upsertDataSourcegetDataSource(key)在数据源不存在时返回undefined使用前建议做空值判断数据源还支持通过registerLoader/ensureLoaded异步加载元数据并维护statusloading/loaded/loading-failed等状态DataSource.status与ErrorMessagegetter 也对应暴露了这些状态见 status/errorMessage getter。这意味着在数据源尚未加载完成时读取元数据可能拿到空结果编写健壮脚本时应留意数据源状态。六、注意事项与健壮性建议路径格式getCollectionField(fieldPath)的路径格式为collectionName.fieldPath第一段为数据表名后续为字段路径支持关联如user.name。关联目标数据表getCollection(name)支持collectionName.fieldName形式返回关联字段的目标数据表。可能为 undefinedctx.dataSource在 RunJS 上下文中通常由当前区块/页面的数据源决定若上下文无绑定数据源可能为undefined使用前建议做空值判断。同理getCollection、getCollectionField、getAssociation在找不到对象时都会返回undefined链式访问时应使用?.与回退值。七、延伸阅读ctx.dataSourceManager数据源管理器管理所有数据源ctx.collection当前上下文关联的数据表ctx.collectionField当前字段的数据表字段定义DataSource 源码实现RunJS 所用DataSource/DataSourceManager的完整实现数据源核心包服务端DataSource抽象类展示ctx.dataSource在请求中间件中的注入方式middleware 注入逻辑【免费下载链接】nocobaseNocoBase is an open-source AI no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表