编辑数据库逻辑
1. 表单验证系统
文件位置:frontend/packages/data/memory/database-v2-base/src/components/base-info-modal/index.tsx
编辑数据库表单的验证规则:
1// 数据库名称验证规则 2const nameValidationRules = [ 3 { 4 required: true, 5 whitespace: true, 6 message: I18n.t('database_name_cannot_be_empty'), 7 }, 8 { 9 pattern: /^[^\"]*$/, 10 message: I18n.t('database_name_cannot_contain_special_characters'), 11 }, 12 { 13 maxLength: 100, 14 message: I18n.t('database_name_max_length_100'), 15 }, 16]; 17 18// 注意:以下代码展示了编辑数据库时打开弹窗并加载数据的逻辑 19const edit = async (databaseId: string) => { 20 try { 21 setLoading(true); 22 // 获取数据库详情数据 23 const data = await MemoryApi.GetDatabaseDetail({ database_id: databaseId }); 24 setDatabase(data.database); 25 // 预填充表单 26 formRef.current?.setFieldsValue({ 27 name: data.database?.name, 28 description: data.database?.description, 29 icon_uri: [{ 30 url: '', 31 uri: data.database?.icon_uri || '', 32 uid: data.database?.icon_uri || '', 33 isDefault: true, 34 }], 35 }); 36 setIsOpen(true); 37 } catch (error) { 38 message.error(I18n.t('get_failed')); 39 } finally { 40 setLoading(false); 41 } 42}; 43 44// 数据库描述验证规则 45const descriptionValidationRules = [ 46 { 47 maxLength: 500, 48 message: I18n.t('database_description_max_length_500'), 49 }, 50]; 51 52// 编辑数据库表单数据接口 53export interface DatabaseBaseInfoFormData { 54 name: string; // 数据库名称 55 description: string; // 数据库描述 56 icon_uri?: Array<{ // 图标信息数组 57 url: string; // 图标URL 58 uri: string; // 图标URI 59 uid?: string; // 唯一标识 60 isDefault?: boolean; // 是否为默认图标 61 }>; 62} 63
设计亮点:
- 字符限制验证:数据库名称不允许包含特殊字符如引号等
- 长度限制:名称最大100字符,描述最大2000字符
- 必填项验证:名称为必填项,确保数据库基本信息完整性
- 国际化错误信息:所有验证错误信息都支持多语言
2. 核心逻辑
编辑数据库的核心逻辑主要在DatabaseBaseInfoModal组件中:
1// 打开编辑弹窗并加载数据 2const edit = async (databaseId: string) => { 3 try { 4 setLoading(true); 5 // 获取数据库详情数据 6 const data = await MemoryApi.GetDatabaseDetail({ database_id: databaseId }); 7 setDatabase(data.database); 8 // 预填充表单 9 formRef.current?.setFieldsValue({ 10 name: data.database?.name, 11 description: data.database?.description, 12 icon_uri: [{ 13 url: '', 14 uri: data.database?.icon_uri || '', 15 uid: data.database?.icon_uri || '', 16 isDefault: true, 17 }], 18 }); 19 setIsOpen(true); 20 } catch (error) { 21 message.error(I18n.t('get_failed')); 22 } finally { 23 setLoading(false); 24 } 25}; 26 27// 提交表单更新数据库 28const handleOk = async () => { 29 try { 30 if (!formRef.current || !database) return; 31 // 表单验证 32 const values = await formRef.current.validateFields(); 33 34 setLoading(true); 35 // 调用更新API 36 await MemoryApi.UpdateDatabase({ 37 database_id: database.database_id, 38 name: values.name, 39 description: values.description, 40 icon_uri: values.icon_uri?.[0]?.uri, 41 }); 42 43 message.success(I18n.t('update_success')); 44 // 刷新数据库信息 45 onUpdate?.(); 46 handleCancel(); 47 } catch (error) { 48 message.error(I18n.t('update_failed')); 49 } finally { 50 setLoading(false); 51 } 52}; 53 54// 图标上传处理已通过PictureUpload组件封装,详情见DatabaseBaseInfoModal组件中的实现 55// 主要配置包括: 56// - type: IconType.Database 57// - bizType: FileBizType.DATABASE_ICON 58// - renderAutoGenerate: 自定义的图标自动生成功能 59
设计亮点:
- 数据预填充:编辑前自动加载并填充数据库当前信息
- 表单验证:更新前进行完整的表单验证
- 图标上传:支持自定义图标上传功能,通过PictureUpload组件统一处理
- 状态管理:清晰的加载状态和错误处理机制
- 数据同步:更新成功后触发回调刷新数据
- 用户反馈:完善的操作反馈和错误提示机制
API层设计与实现
IDL基础类型定义(database.thrift)
文件位置:idl/data/database/database.thrift
核心代码:
1include "../../base.thrift" 2 3namespace go data.database 4 5enum DatabaseStatus { 6 DATABASE_STATUS_PROCESSING = 0 // 处理中 7 DATABASE_STATUS_READY = 1 // 可用 8 DATABASE_STATUS_DELETED = 2 // 软删除 9 DATABASE_STATUS_FORBID = 3 // 禁用 10 DATABASE_STATUS_FAILED = 9 // 失败 11} 12 13enum DatabaseMode { 14 DATABASE_MODE_READONLY = 0 // 只读模式 15 DATABASE_MODE_READWRITE = 1 // 读写模式 16} 17 18struct Database { 19 1: string database_id (agw.js_conv="str", api.js_conv="true") 20 2: string name 21 3: string description 22 4: string icon_uri 23 5: DatabaseStatus status 24 6: DatabaseMode mode 25 7: i64 create_time 26 8: i64 update_time 27 9: string space_id (agw.js_conv="str", api.js_conv="true") 28 10: string project_id (agw.js_conv="str", api.js_conv="true") 29 11: i64 creator_id (agw.js_conv="str", api.js_conv="true") 30} 31 32struct UpdateDatabaseRequest { 33 1: string database_id (agw.js_conv="str", api.js_conv="true") // 数据库ID 34 2: string name // 数据库名称,长度不超过100个字符 35 3: string description // 数据库描述 36 4: string icon_uri // 数据库头像URI 37 5: optional DatabaseMode mode // 数据库模式 38 39 255: optional base.Base Base 40} 41 42struct UpdateDatabaseResponse { 43 1: i64 code 44 2: string msg 45 46 255: optional base.BaseResp BaseResp 47} 48 49struct GetDatabaseDetailRequest { 50 1: string database_id (agw.js_conv="str", api.js_conv="true") // 数据库ID 51 255: optional base.Base Base 52} 53 54struct GetDatabaseDetailResponse { 55 1: i64 code 56 2: string msg 57 3: Database database 58 59 255: optional base.BaseResp BaseResp 60} 61
文件作用:
定义了数据库相关的数据结构,包括更新请求、响应和数据库实体定义。
编辑数据库-IDL接口定义(database_svc.thrift)
文件路径:idl/data/database/database_svc.thrift
核心代码:
1include "slice.thrift" 2include "database.thrift" 3 4namespace go data.database 5 6service DatabaseService { 7 // 数据库相关 8 database.GetDatabaseDetailResponse GetDatabaseDetail(1:database.GetDatabaseDetailRequest req) (api.post='/api/memory/database/detail', api.category="memory",agw.preserve_base="true") 9 database.UpdateDatabaseResponse UpdateDatabase(1:database.UpdateDatabaseRequest req) (api.post='/api/memory/database/update', api.category="memory",agw.preserve_base="true") 10 database.DeleteDatabaseResponse DeleteDatabase(1:database.DeleteDatabaseRequest req) (api.post='/api/memory/database/delete', api.category="memory",agw.preserve_base="true") 11 database.ListDatabaseResponse ListDatabase(1:database.ListDatabaseRequest req) (api.post='/api/memory/database/list', api.category="memory",agw.preserve_base="true") 12 database.GetDatabaseIconResponse GetDatabaseIcon(1:database.GetDatabaseIconRequest req) (api.post='/api/memory/database/icon', api.category="memory",agw.preserve_base="true") 13} 14
源码作用:定义数据库更新、删除和获取相关的接口
编辑数据库-API接口实现(memory-api.ts)
文件位置:frontend/packages/arch/bot-api/src/memory-api.ts
核心代码:
1import DatabaseService from './idl/memory/database'; 2import { axiosInstance, type BotAPIRequestConfig } from './axios'; 3 4// eslint-disable-next-line @typescript-eslint/naming-convention 5export const MemoryApi = { 6 // 数据库相关API 7 UpdateDatabase: (req: any, config?: BotAPIRequestConfig) => { 8 const databaseService = new DatabaseService<BotAPIRequestConfig>({ 9 request: (params, config = {}) => { 10 const { headers } = config; 11 const reqHeaders = { 12 ...headers, 13 'Agw-Js-Conv': 'str', 14 }; 15 return axiosInstance.request({ ...params, ...config, headers: reqHeaders }); 16 }, 17 }); 18 return databaseService.UpdateDatabase(req, config); 19 }, 20 21 GetDatabaseDetail: (req: any, config?: BotAPIRequestConfig) => { 22 const databaseService = new DatabaseService<BotAPIRequestConfig>({ 23 request: (params, config = {}) => { 24 const { headers } = config; 25 const reqHeaders = { 26 ...headers, 27 'Agw-Js-Conv': 'str', 28 }; 29 return axiosInstance.request({ ...params, ...config, headers: reqHeaders }); 30 }, 31 }); 32 return databaseService.GetDatabaseDetail(req, config); 33 }, 34}; 35
数据库服务类实现
文件位置:frontend/packages/arch/idl/src/auto-generated/memory/database.ts
核心代码:
1export default class DatabaseService<T> { 2 private request: any = () => { 3 throw new Error('DatabaseService.request is undefined'); 4 }; 5 private baseURL: string | ((path: string) => string) = ''; 6 7 constructor(options?: { 8 baseURL?: string | ((path: string) => string); 9 request?<R>( 10 params: { 11 url: string; 12 method: 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH'; 13 data?: any; 14 params?: any; 15 headers?: any; 16 }, 17 options?: T, 18 ): Promise<R>; 19 }) { 20 this.request = options?.request || this.request; 21 this.baseURL = options?.baseURL || ''; 22 } 23 24 /** POST /api/memory/database/update */ 25 UpdateDatabase( 26 req?: database.UpdateDatabaseRequest, 27 options?: T, 28 ): Promise<database.UpdateDatabaseResponse> { 29 const _req = req || {}; 30 const url = this.genBaseURL('/api/memory/database/update'); 31 const method = 'POST'; 32 const data = { 33 database_id: _req['database_id'], 34 name: _req['name'], 35 description: _req['description'], 36 icon_uri: _req['icon_uri'], 37 mode: _req['mode'], 38 }; 39 return this.request<R, database.UpdateDatabaseResponse>({ url, method, data }, options); 40 } 41 42 /** POST /api/memory/database/detail */ 43 GetDatabaseDetail( 44 req?: database.GetDatabaseDetailRequest, 45 options?: T, 46 ): Promise<database.GetDatabaseDetailResponse> { 47 const _req = req || {}; 48 const url = this.genBaseURL('/api/memory/database/detail'); 49 const method = 'POST'; 50 const data = { 51 database_id: _req['database_id'], 52 }; 53 return this.request<R, database.GetDatabaseDetailResponse>({ url, method, data }, options); 54 } 55} 56 57代码作用:`DatabaseService` 类包含数据库相关的API方法: 58- `UpdateDatabase`:用于更新数据库,调用 `/api/memory/database/update` 接口 59- `GetDatabaseDetail`:用于获取数据库详情,调用 `/api/memory/database/detail` 接口 60 61此文件是基于database.thrift自动生成的,开发者无需手动修改。 62 63### 编辑数据库--结构体实现补充 64 65根据database.thrift文件定义,数据库编辑相关的结构体已经在前面的IDL基础类型定义部分详细说明。需要注意的是: 66 671. UpdateDatabaseRequest包含database_id、name、description和icon_uri等字段 682. GetDatabaseDetailResponse返回的是带有database字段的响应对象 693. 这些结构体都是通过idl2ts-cli工具从thrift文件自动生成的TypeScript类型定义 70## idl2ts-cli 工具 71 72### 工具名称 73[`@coze-arch/idl2ts-cli`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.arch.md) 74 75### 详细地址 76**项目路径**:`frontend/infra/idl/idl2ts-cli/` 77 78### 工具详细信息 79 80**版本**:0.1.7 81 82**描述**:IDL(Interface Definition Language)到TypeScript的转换工具 83 84**主要功能**: 851. **gen命令**:从Thrift或Protocol Buffer文件生成API代码 862. **filter命令**:生成过滤后的API类型定义 87 88**可执行文件**:`idl2ts`(位于 `./src/cli.js`) 89最终调用的是`frontend/infra/idl/idl2ts-cli/src/cli.ts` 这个文件 90 91**核心依赖**: 92- [`@coze-arch/idl2ts-generator`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.arch.md):代码生成器 93- [`@coze-arch/idl2ts-helper`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.arch.md):辅助工具 94- [`@coze-arch/idl2ts-plugin`](https://xplanc.org/primers/document/zh/10.Bash/90.%E5%B8%AE%E5%8A%A9%E6%89%8B%E5%86%8C/EX.arch.md):插件系统 95- `commander`:命令行界面 96- `prettier`:代码格式化 97 98**使用方式**: 99```bash 100# 生成API代码 101idl2ts gen <projectRoot> [-f --format-config <formatConfig>] 102 103# 生成过滤类型 104idl2ts filter <projectRoot> [-f --format-config <formatConfig>] 105
许可证:Apache-2.0
这个工具是Coze Studio项目中统一处理所有IDL文件(包括database.thrift和相关数据库IDL文件)的核心工具,确保了整个项目中数据库API代码生成的一致性。
数据库相关IDL文件处理
该工具主要处理以下数据库相关的IDL文件:
- database.thrift - 数据库核心数据结构定义
- database_svc.thrift - 数据库服务接口定义
- slice.thrift - 数据切片相关定义
生成的数据库相关代码
在编辑数据库功能开发过程中,该工具能够:
- 自动生成数据库API类型:包括UpdateDatabaseRequest、UpdateDatabaseResponse、GetDatabaseDetailRequest、GetDatabaseDetailResponse等接口类型
- 生成数据库服务类:DatabaseService类及其所有方法,特别是UpdateDatabase和GetDatabaseDetail方法
- 确保类型安全:所有数据库API调用都有完整的TypeScript类型支持
- 统一代码风格:通过Prettier确保生成代码的格式一致性
- 支持数据库模式:处理只读模式、读写模式等不同数据库操作模式的类型定义
编辑数据库开发工作流
1# 1. 修改数据库相关IDL文件 2vi idl/data/database/database.thrift 3 4# 2. 生成TypeScript代码 5idl2ts gen frontend/ 6 7# 3. 自动更新前端API接口 8# 生成路径:frontend/packages/arch/idl/src/auto-generated/memory/database.ts 9
这确保了编辑数据库功能的前后端接口定义始终保持同步,大大提高了开发效率和代码质量。在编辑数据库场景中,类型安全尤为重要,它确保了编辑前后的数据结构一致性,避免了因数据格式不匹配导致的错误。
总结
数据库编辑功能是Coze平台中资源库模块的核心功能之一,它为用户提供了直观、高效的数据库基础信息管理体验。本文档详细分析了该功能的前端实现架构、核心组件和技术细节。
主要功能特性
- 数据库列表展示与筛选:在资源库页面中通过
BaseLibraryPage组件展示数据库列表,支持按名称搜索和分页加载。 - 数据库详情编辑:用户可点击列表中的数据库行进入详情页,并通过
DatabaseBaseInfoModal编辑数据库的名称、描述和图标。 - 表单验证系统:实现了完善的表单验证逻辑,确保数据库名称长度(1-100字符)、描述长度(不超过500字符)等符合系统规范。
- 图标上传处理:支持数据库图标的选择和上传,通过
uploadIcon函数处理文件上传并更新URI。 - 权限控制机制:根据用户角色和创建者信息判断编辑权限,通过
isReadOnlyMode状态控制编辑功能的可用性。 - 状态同步与反馈:编辑完成后自动刷新数据并提供操作成功提示,使用
message.success和message.error提供用户反馈。
技术实现亮点
- 基于Hook的架构设计:
- 使用
useEditDatabaseModalBase等自定义Hook封装业务逻辑 - 采用
useState、useEffect、useMemo和useCallback管理组件状态 - 通过
useTranslation实现国际化支持
- 使用
- 组件化与解耦:
- 将UI拆分为可复用的独立组件
- 业务逻辑与UI展示分离,提高代码可维护性
- 使用配置化路由管理页面导航
- 类型安全实现:
- 使用TypeScript定义严格的接口类型,如
CozeDatabaseEditContentFormData - 通过idl2ts-cli工具从IDL文件自动生成类型定义
- 确保API调用和数据处理的类型安全
- 使用TypeScript定义严格的接口类型,如
- API层设计:
- 通过
MemoryApi统一管理数据库相关API调用 - 实现了
GetDatabaseDetail和UpdateDatabase等核心接口 - 使用Promise处理异步请求和错误状态
- 通过
- 响应式交互设计:
- 支持从不同入口(资源库、项目等)进入数据库编辑流程
- 提供清晰的加载状态和操作反馈
- 实现了模态框的平滑打开和关闭动画
组件协作关系
数据库编辑功能的组件协作呈现清晰的层级结构:
- 入口层:
BaseLibraryPage作为资源库主页,提供数据库列表展示和入口 - 配置层:
useDatabaseConfig提供数据库资源的配置信息和权限控制 - 详情层:
DatabaseDetail作为详情页,整合各功能模块 - 编辑层:
DatabaseBaseInfoModal负责基础信息编辑表单的展示和提交 - API层:
MemoryApi处理与后端的所有数据交互
这种分层设计确保了功能模块之间的低耦合高内聚,便于后续的功能扩展和维护。
未来优化方向
- 性能优化:实现更高效的数据加载策略,如虚拟滚动和数据缓存
- 用户体验提升:增强表单验证的实时反馈,优化编辑流程
- 功能扩展:增加批量编辑、版本历史查看等高级功能
- 代码重构:进一步抽象和标准化组件接口,提高代码复用率
数据库编辑功能通过合理的架构设计和技术选型,为Coze平台用户提供了稳定、高效的数据库管理体验,是资源库模块中不可或缺的重要组成部分。
《Coze源码分析-资源库-编辑数据库-前端源码-核心逻辑与接口》 是转载文章,点击查看原文。
