From fff11a722383854a6ec5fef3e9a7fb51526d01a7 Mon Sep 17 00:00:00 2001 From: circle33 Date: Sat, 18 Apr 2026 17:43:53 +0800 Subject: [PATCH 1/5] feat: migrate frontend-backend communication from Tauri IPC to gRPC-Web --- AGENTS.md | 137 +- backend/AGENTS.md | 51 + backend/api/vstable.proto | 9 +- backend/go.mod | 17 +- backend/go.sum | 490 ++++- backend/internal/ast/types.go | 14 +- backend/internal/mapper/mapper.go | 17 +- backend/internal/pb/vstable.pb.go | 176 +- backend/main.go | 32 +- frontend/AGENTS.md | 47 + frontend/e2e/AGENTS.md | 83 +- frontend/package-lock.json | 624 +++++- frontend/package.json | 5 + frontend/src/App.tsx | 2 +- frontend/src/api/client.ts | 54 +- frontend/src/api/grpcClient.ts | 48 + .../schema-designer/StructureView.test.tsx | 8 +- .../schema-designer/StructureView.tsx | 80 +- frontend/src/layouts/MainLayout.tsx | 2 +- frontend/src/stores/useSessionStore.tsx | 1 + frontend/src/types/google/protobuf/struct.ts | 408 ++++ frontend/src/types/vstable.ts | 1906 +++++++++++++++++ frontend/tauri/AGENTS.md | 64 +- frontend/tauri/Cargo.lock | 466 +--- frontend/tauri/Cargo.toml | 7 - frontend/tauri/build.rs | 8 - frontend/tauri/src/commands.rs | 125 +- frontend/tauri/src/error.rs | 44 + frontend/tauri/src/grpc.rs | 8 - frontend/tauri/src/lib.rs | 19 +- frontend/tauri/src/utils.rs | 383 ---- refactoring_plan.md | 72 + 32 files changed, 4039 insertions(+), 1368 deletions(-) create mode 100644 backend/AGENTS.md create mode 100644 frontend/AGENTS.md create mode 100644 frontend/src/api/grpcClient.ts create mode 100644 frontend/src/types/google/protobuf/struct.ts create mode 100644 frontend/src/types/vstable.ts create mode 100644 frontend/tauri/src/error.rs delete mode 100644 frontend/tauri/src/grpc.rs delete mode 100644 frontend/tauri/src/utils.rs create mode 100644 refactoring_plan.md diff --git a/AGENTS.md b/AGENTS.md index b219607..e21f380 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,118 +1,43 @@ -# vstable +# Agent Context: vstable Root -## Quick commands +> **ATTENTION AI AGENTS & DEVELOPERS:** +> 本文件是 `vstable` 项目的**全局**开发指南。请作为所有子目录操作的最高纲领。各独立模块的详细业务逻辑与特定规则,请参阅对应目录下的 `AGENTS.md`。 -- `cd frontend && npm run dev` (拉起双端开发环境:Tauri + Go Engine) -- `cd frontend && npm run dev-frontend` (仅启动前端 Vite,不启动 Tauri/Go,适合纯 UI 调试) -- `cd frontend && npm run build` (编译前端与后端二进制) -- `cd frontend && npm run test` (Vitest 单元测试) -- `cd frontend && npm run test:e2e` (Playwright 全链路测试,会先 build) -- `cd frontend && npm run check` (Biome 格式化与静态检查) -- `cd frontend && npm run docker:up` (启动测试所需的 PG/MySQL 容器) -- `cd frontend && npm run docker:down` (停止并清理测试容器) -- `cd backend && go test -v ./...` (后端集成测试,需 Docker) -- `cd backend && ./scripts/gen_proto.sh` (生成 gRPC 代码) - -## Project overview - -vstable 是一款专为开发者设计的现代数据库管理工具,支持可视化表结构设计与高性能 SQL 查询。其核心设计目标是“状态对齐”,即通过对比新旧 AST(抽象语法树)生成精确的数据库变更语句。 - -## Tech stack - -- **Frontend**: React 19 (TypeScript), TailwindCSS 4.0, Monaco Editor -- **Desktop Runtime**: Tauri 2.0 (Rust), Vite -- **Backend Engine**: Go 1.24 (vstable-engine) -- **Communication**: gRPC, Protocol Buffers (Strict types) -- **Database Drivers**: `pgx/v5` (PostgreSQL), `go-sql-driver/mysql` (MySQL) -- **Testing**: Playwright (E2E), Vitest (Unit), Go test (Integration) -- **Infrastructure**: Docker Compose (Database testing environments) - -## Architecture overview - -该项目采用解耦的三层架构: -1. **Frontend (React)**: 基于 React 19、TailwindCSS 4.0 和 Monaco Editor 构建的现代用户界面。负责处理用户交互、SQL 编辑以及可视化的表结构设计。 -2. **Desktop Runtime (Tauri)**: 作为操作系统与 Web 内容之间的桥梁。基于 Rust 的核心层负责管理 Go 引擎(Sidecar)的生命周期、处理由前端发起的高性能 IPC 请求,并通过原生的能力(Capabilities)系统提供持久化存储和窗口管理。 -3. **Backend Engine (Go)**: 一个使用 Go 1.24 编写的高性能守护进程。它在本地作为 Tauri Sidecar 运行并向 Rust 核心暴露 gRPC API(定义于 `vstable.proto`)。它承担繁重的计算任务,包括数据库连接管理、AST 解析,以及基于状态对齐进行 Schema Diff 并生成精确的 DDL 语句。 +## 1. Project Overview & Core Logic -## Major modules and interfaces +`vstable` 是一款专为开发者设计的现代数据库管理工具,支持可视化表结构设计与高性能 SQL 查询。 -- **Go Engine (`backend/`)**: - - `internal/ast`: 核心 Schema Diff 引擎。提供 AST 类型定义以及特定数据库方言(PostgreSQL/MySQL)的编译器,用于基于状态对齐生成精确的 DDL Diff。 - - `internal/db`: 数据库连接管理器和驱动程序抽象。 - - `main.go`: 启动 gRPC Server,处理来自 Tauri Rust 核心的远程过程调用。 - - `scripts/gen_proto.sh`: 构建脚本,用于从 `.proto` 文件生成 Go 代码。 -- **Tauri Core (`frontend/tauri/`)**: - - `src/lib.rs`: Tauri 应用的核心库。初始化 gRPC 客户端池以通过严格类型的 Protobuf 协议与后端引擎通信;处理前端的 IPC 路由(如 `db_connect`, `db_query`),以及原生窗口控制和日志捕获。 - - `src/main.rs`: 桌面应用启动入口。 - - `tauri.conf.json`: 应用配置,包括构建指令、窗口属性以及 Sidecar (Go 引擎)的绑定声明。 -- **React Renderer (`frontend/src/`)**: - - `features/`: 包含核心功能模块: - - `connection`: 数据库连接表单和管理。 - - `navigator`: 数据库和数据表树形视图。 - - `query-editor`: 基于 Monaco 的 SQL 执行环境。 - - `schema-designer`: 可视化的表结构修改器。 - - `table-viewer`: 用于查看和编辑表数据的数据网格。 - - `api/`: 通过 IPC 与主进程进行通信的 API 客户端。 +**全栈核心逻辑:基于 AST 的“状态对齐” (Schema Diff Engine)** +传统数据库工具通过手动拼接 `ALTER TABLE` 语句来修改表结构。`vstable` 的核心逻辑是“状态对齐”: +1. **解析 (Parse)**:将当前的数据库表结构拉取并解析为内部统一的抽象语法树 (AST)。 +2. **修改 (Mutate)**:用户在前端可视化的 React Schema Designer 中修改表结构,产生一个目标 AST(New State)。 +3. **对比与生成 (Diff & Generate)**:Go 后端比较 Old AST 与 New AST,针对不同的数据库方言(PostgreSQL/MySQL),精确生成对应的 DDL 变更语句。 -## Repo map +## 2. Global Architecture: Direct Communication -- `backend/`: Go 后端引擎源码。 - - `internal/ast/`: AST 类型、Diff 逻辑以及数据库方言编译器。 - - `internal/db/`: 数据库驱动实现。 -- `frontend/`: Tauri 应用与 React 前端。 - - `e2e/`: 用于全链路验证的 Playwright E2E 测试。 - - `tauri/`: Tauri 胶水代码,将 frontend 和 backend 粘合在一起。 - - `src/`: React Web 应用。 - - `components/`: 可复用的通用 UI 组件。 - - `features/`: 特定领域的业务逻辑与视图。 - - `hooks/`, `stores/`: 全局状态管理 (Zustand) 和自定义 React Hooks。 -- `requirement/`: 产品需求、设计文档和待办事项列表。 +项目采用解耦的三层架构,并**强制执行**“前端直连后端”的网络通信模型: -## Conventions and quality +1. **Frontend (React)**: 负责所有业务交互、可视化设计,并通过 gRPC-Web HTTP 直连后端。(详见 `frontend/AGENTS.md`) +2. **Desktop Runtime (Tauri)**: 降级为 “Thin Shell”,仅负责原生窗口控制与启动后台引擎。(详见 `frontend/tauri/AGENTS.md`) +3. **Backend Engine (Go)**: 本地守护进程(Sidecar),负责繁重的 AST 计算与数据库 I/O。(详见 `backend/AGENTS.md`) -- **代码风格**: - - 前端:TypeScript 严格模式,Biome。 - - 后端:Go 1.24 标准风格。 -- **测试驱动**: - - 新功能必须包含单元测试(Vitest)。 - - DDL 方言修改必须通过后端集成测试(`go test`)。 - - 关键路径(连接、查询、同步)必须覆盖 E2E 测试。 -- **全链路验证**: - - 自动完成 Docker 环境拉起、引擎预编译、模拟用户操作。 - - 双向对齐验证:在后端维护同步化的集成测试,确保生成的 DDL 在真实数据库中执行一致。 -- **UI 渲染稳定性**: - - 对于包含 Monaco Editor 等对 DOM 物理位置敏感的组件,在实现排序功能时必须采用“稳定 DOM 排序”策略。 - - 即 DOM 物理顺序按 ID 保持固定,与 UI 显示顺序解耦,仅通过切换可见性而非物理移动 DOM 节点来处理排序。 -- **类型安全性**: 贯穿前端 UI 到后端 AST 编译器的强类型约束。 +## 3. Global Hard Rules -## Git commit messages +在为本项目编写代码时,必须遵守以下全局铁律: -采用 Conventional Commits 格式: +- **[RULE 1] 杜绝“浅模块” (No Shallow Modules in Tauri)**: + - 遵循 John Ousterhout 的《A Philosophy of Software Design》。 + - 严禁在 Tauri 的 Rust 核心层编写用于“透传”网络请求的中间件代码。前端必须直接向后端发起网络请求。 +- **[RULE 2] Protobuf 驱动开发 (Proto-Driven)**: + - 任何前后端交互的 API 变更,必须首发修改 `backend/api/vstable.proto`,随后运行构建脚本重新生成双端接口代码。严禁单方面 Hardcode 接口数据结构。 +- **[RULE 3] 强制全链路测试保护**: + - AST 编译或方言逻辑的变更必须通过 Go 集成测试。 + - UI 核心链路(连接、设计器、数据网格)修改必须通过 Playwright 全链路测试。(详见 `frontend/e2e/AGENTS.md`) -```text -(): -``` +## 4. Quick Commands -Allowed types: -`feat`, `fix`, `test`, `refactor`, `chore`, `style`, `docs`, `perf`, `build`, `ci`, `revert`. - -## Versioning - -项目遵循语义化版本控制 (`MAJOR.MINOR.PATCH`): - -- **Patch** 版本仅用于向后兼容的 Bug 修复。 -- **Minor** 版本用于新增向后兼容的功能和改进。 -- **Major** 版本用于破坏性或不兼容的 API 变更。 - -## Release workflow - -1. 确保 `master` 分支代码已更新 (pull latest)。 -2. 创建发布分支,如 `release-v1.2.0`。 -3. 更新 `frontend/package.json`、`frontend/tauri/tauri.conf.json` 中的版本号。 -4. 运行全链路测试 (`npm run test:e2e` 与 `go test ./...`) 确保版本稳定性。 -5. 提交变更并创建 PR。 -6. PR 合并后,切换回 `master` 分支并拉取最新代码。 -7. 建立标签并推送: - - `git tag v1.2.0` - - `git push --tags` -8. GitHub Actions 或相关 CI/CD 流程在检测到 tag 推送后,自动构建双端产物(Tauri Mac/Windows/Linux 与 Go Engine 二进制)并执行发布。 +- `cd frontend && npm run dev` (拉起双端开发环境:Tauri + Go Engine) +- `cd frontend && npm run build` (打包全平台产物) +- `cd frontend && npm run test:e2e` (执行端到端测试) +- `cd backend && go test -v ./...` (执行后端集成测试,需预先 `npm run docker:up`) +- `cd backend && ./scripts/gen_proto.sh` (生成 gRPC 代码) diff --git a/backend/AGENTS.md b/backend/AGENTS.md new file mode 100644 index 0000000..fd890ad --- /dev/null +++ b/backend/AGENTS.md @@ -0,0 +1,51 @@ +# Agent Context: Go Engine (Backend) + +> **ATTENTION AI AGENTS & DEVELOPERS:** +> 此目录 `backend/` 包含了 vstable 的核心计算引擎(Go 1.24)。这里承载了数据库直连、AST Diff 计算和网络服务的重任。在编写代码前,请牢记这里的核心逻辑与架构规则。 + +## 1. Core Logic & Responsibilities + +**AST 状态对齐与 gRPC-Web 服务** +后端作为一个独立的二进制进程(Sidecar),承担着应用中最核心的“脏活累活”。 + +- **gRPC-Web Server (`main.go`)**: + - 核心逻辑:后端不使用 Envoy 代理,而是借助 `improbable-eng/grpc-web` 库将标准的 gRPC Server 包装为 `http.Server`,直接向浏览器的 Fetch API 提供服务。 +- **Session Management (`internal/db`)**: + - 引擎内部通过 `db.Manager` 在内存中维护了一个以 `id` (Session ID) 为键的线程安全字典,确保前端同一连接复用对应的 DB Driver 实例。 + +## 2. Business Logic Map (业务逻辑快速定位导航) + +遇到需求变更或修复 Bug 时,请根据以下模块分工快速定位代码: + +- **网络入口与拦截器 (`main.go`)** + - **职责**: 端口监听 (默认 `:39082`),gRPC-Web 协议转换。 + - **跨域**: `rs/cors` 跨域策略配置。 + - **拦截器**: `UnaryInterceptor` 用于全局请求的 `panic` 捕捉与耗时、错误日志打印。 +- **数据库驱动层 (`internal/db/driver.go`)** + - **职责**: 底层依赖 `pgx/v5` 和 `go-sql-driver/mysql`。 + - **逻辑**: 执行纯文本 SQL 并解析动态数据结构;获取数据库系统元数据 (Meta queries)。 +- **抽象语法树模型 (`internal/ast/types.go`)** + - **职责**: 跨方言的统一数据结构。 + - **逻辑**: 定义 Table, Column, Index 等实体,作为前后端状态对齐的媒介。 +- **状态对齐与差异计算 (`internal/ast/diff.go`)** + - **职责**: 比较 Old AST 和 New AST。 + - **逻辑**: 识别出需要增加、删除或修改的列与约束。 +- **方言 DDL 生成器 (`internal/ast/compiler_pg.go` & `compiler_mysql.go`)** + - **职责**: 将 diff 结果翻译为特定数据库的 SQL 语句。 + - **逻辑**: 处理诸如修改非空约束、更改数据类型等具体方言的 SQL 拼接。修改此类文件极易引发线上 Bug。 +- **Protobuf 转换映射 (`internal/mapper/`)** + - **职责**: 将 gRPC 传入的 Protobuf struct (`pb.*`) 转换为内部 AST 原生结构。 + +## 3. Hard Rules for AI Agents (Go Layer) + +修改后端代码时,必须遵守以下防翻车铁律: + +- **[RULE 1] 跨域安全红线 (CORS Gotchas)**: + - **致命警告 (Wildcard vs. Credentials Conflict)**:当 `main.go` 中的 `AllowedOrigins` 包含 wildcard `*` 时,`AllowCredentials` **必须且只能设置为 `false`**。 + - **排障特征**:一旦错误配置,浏览器会拦截 Preflight 请求,并在前端抛出晦涩的 `/vstable.EngineService/DbConnect UNKNOWN: Transport error: Load failed` 错误。 +- **[RULE 2] 标准化错误处理 (gRPC Status Codes)**: + - 必须使用 `google.golang.org/grpc/status` 包装对外返回的 error,以便前端的 Interceptor 能够精准拦截和归类(如 `codes.NotFound`, `codes.InvalidArgument`)。 +- **[RULE 3] 防御性编程与 Panic 恢复**: + - `UnaryInterceptor` 已提供全局 `recover()`,但在编写业务逻辑时,必须显式返回 `error`,严禁滥用 `panic`。 +- **[RULE 4] AST/DDL 变更的测试覆盖要求**: + - 涉及 `internal/ast`(SQL 生成逻辑)或 `internal/db`(方言特化适配)的任何改动,**必须**补充对应的集成测试(如 `diff_integration_pg_test.go`),且必须在真实 Docker 数据库中验证执行。 diff --git a/backend/api/vstable.proto b/backend/api/vstable.proto index ab66738..53bbe97 100644 --- a/backend/api/vstable.proto +++ b/backend/api/vstable.proto @@ -4,7 +4,6 @@ package vstable; option go_package = "vstable-engine/internal/pb"; import "google/protobuf/struct.proto"; -import "google/protobuf/wrappers.proto"; service EngineService { rpc Ping(PingRequest) returns (PingResponse); @@ -61,11 +60,11 @@ message ColumnDefinition { string name = 2; string type = 3; repeated string enum_values = 4; - google.protobuf.Value length = 5; - google.protobuf.Value precision = 6; - google.protobuf.Value scale = 7; + optional int64 length = 5; + optional int64 precision = 6; + optional int64 scale = 7; bool nullable = 8; - google.protobuf.StringValue default_value = 9; + optional string default_value = 9; bool is_default_expression = 10; bool is_primary_key = 11; bool is_auto_increment = 12; diff --git a/backend/go.mod b/backend/go.mod index 74ba540..53f299b 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,23 +1,28 @@ module vstable-engine -go 1.24.0 +go 1.25.0 require ( github.com/go-sql-driver/mysql v1.9.3 - github.com/golang/protobuf v1.5.4 + github.com/improbable-eng/grpc-web v0.15.0 github.com/jackc/pgx/v5 v5.8.0 + github.com/rs/cors v1.7.0 google.golang.org/grpc v1.79.2 google.golang.org/protobuf v1.36.11 ) require ( filippo.io/edwards25519 v1.1.0 // indirect + github.com/cenkalti/backoff/v4 v4.1.1 // indirect + github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect - golang.org/x/net v0.48.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect + github.com/klauspost/compress v1.11.7 // indirect + golang.org/x/net v0.53.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + nhooyr.io/websocket v1.8.6 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 4a7a758..79cd9dd 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,22 +1,179 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= +github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= +github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= +github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= @@ -25,13 +182,161 @@ github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= @@ -44,23 +349,192 @@ go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2W go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k= +nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/backend/internal/ast/types.go b/backend/internal/ast/types.go index a3f107f..12f080c 100644 --- a/backend/internal/ast/types.go +++ b/backend/internal/ast/types.go @@ -17,7 +17,7 @@ type ColumnDefinition struct { Comment string `json:"comment"` PkConstraintName string `json:"pkConstraintName"` OriginalIndex int `json:"originalIndex"` - Original *ColumnDefinition `json:"_original"` // 关键:对应前端的 _original + Original *ColumnDefinition `json:"original"` // 关键:对应前端的 _original } type IndexDefinition struct { @@ -25,7 +25,7 @@ type IndexDefinition struct { Name string `json:"name"` Columns []string `json:"columns"` IsUnique bool `json:"isUnique"` - Original *IndexDefinition `json:"_original"` + Original *IndexDefinition `json:"original"` } type ForeignKeyDefinition struct { @@ -36,21 +36,21 @@ type ForeignKeyDefinition struct { ReferencedColumns []string `json:"referencedColumns"` OnDelete string `json:"onDelete"` OnUpdate string `json:"onUpdate"` - Original *ForeignKeyDefinition `json:"_original"` + Original *ForeignKeyDefinition `json:"original"` } type CheckConstraintDefinition struct { ID string `json:"id"` Name string `json:"name"` Expression string `json:"expression"` - Original *CheckConstraintDefinition `json:"_original"` + Original *CheckConstraintDefinition `json:"original"` } type ViewDefinition struct { ID string `json:"id"` Name string `json:"name"` Definition string `json:"definition"` - Original *ViewDefinition `json:"_original"` + Original *ViewDefinition `json:"original"` } type TriggerDefinition struct { @@ -61,7 +61,7 @@ type TriggerDefinition struct { TableName string `json:"tableName"` Definition string `json:"definition"` Enabled bool `json:"enabled"` - Original *TriggerDefinition `json:"_original"` + Original *TriggerDefinition `json:"original"` } type RoutineDefinition struct { @@ -69,7 +69,7 @@ type RoutineDefinition struct { Name string `json:"name"` Type string `json:"type"` // PROCEDURE or FUNCTION Definition string `json:"definition"` - Original *RoutineDefinition `json:"_original"` + Original *RoutineDefinition `json:"original"` } type DatabaseConfig struct { diff --git a/backend/internal/mapper/mapper.go b/backend/internal/mapper/mapper.go index 9a7f596..ab6c5be 100644 --- a/backend/internal/mapper/mapper.go +++ b/backend/internal/mapper/mapper.go @@ -72,11 +72,6 @@ func mapColumn(c *pb.ColumnDefinition) ast.ColumnDefinition { return ast.ColumnDefinition{} } - var defaultValue *string - if c.DefaultValue != nil { - defaultValue = &c.DefaultValue.Value - } - var original *ast.ColumnDefinition if c.Original != nil { orig := mapColumn(c.Original) @@ -88,11 +83,11 @@ func mapColumn(c *pb.ColumnDefinition) ast.ColumnDefinition { Name: c.Name, Type: c.Type, EnumValues: c.EnumValues, - Length: fromValue(c.Length), - Precision: fromValue(c.Precision), - Scale: fromValue(c.Scale), + Length: fromInt64Ptr(c.Length), + Precision: fromInt64Ptr(c.Precision), + Scale: fromInt64Ptr(c.Scale), Nullable: c.Nullable, - DefaultValue: defaultValue, + DefaultValue: c.DefaultValue, IsDefaultExpression: c.IsDefaultExpression, IsPrimaryKey: c.IsPrimaryKey, IsAutoIncrement: c.IsAutoIncrement, @@ -104,11 +99,11 @@ func mapColumn(c *pb.ColumnDefinition) ast.ColumnDefinition { } } -func fromValue(v *structpb.Value) interface{} { +func fromInt64Ptr(v *int64) interface{} { if v == nil { return nil } - return v.AsInterface() + return *v } func mapIndexes(idxs []*pb.IndexDefinition) []ast.IndexDefinition { diff --git a/backend/internal/pb/vstable.pb.go b/backend/internal/pb/vstable.pb.go index d2768b0..f504c42 100644 --- a/backend/internal/pb/vstable.pb.go +++ b/backend/internal/pb/vstable.pb.go @@ -10,7 +10,7 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" structpb "google.golang.org/protobuf/types/known/structpb" - wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" + _ "google.golang.org/protobuf/types/known/wrapperspb" reflect "reflect" sync "sync" unsafe "unsafe" @@ -468,24 +468,24 @@ func (x *QueryResponse) GetFields() []*FieldInfo { } type ColumnDefinition struct { - state protoimpl.MessageState `protogen:"open.v1"` - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` - EnumValues []string `protobuf:"bytes,4,rep,name=enum_values,json=enumValues,proto3" json:"enum_values,omitempty"` - Length *structpb.Value `protobuf:"bytes,5,opt,name=length,proto3" json:"length,omitempty"` - Precision *structpb.Value `protobuf:"bytes,6,opt,name=precision,proto3" json:"precision,omitempty"` - Scale *structpb.Value `protobuf:"bytes,7,opt,name=scale,proto3" json:"scale,omitempty"` - Nullable bool `protobuf:"varint,8,opt,name=nullable,proto3" json:"nullable,omitempty"` - DefaultValue *wrapperspb.StringValue `protobuf:"bytes,9,opt,name=default_value,json=defaultValue,proto3" json:"default_value,omitempty"` - IsDefaultExpression bool `protobuf:"varint,10,opt,name=is_default_expression,json=isDefaultExpression,proto3" json:"is_default_expression,omitempty"` - IsPrimaryKey bool `protobuf:"varint,11,opt,name=is_primary_key,json=isPrimaryKey,proto3" json:"is_primary_key,omitempty"` - IsAutoIncrement bool `protobuf:"varint,12,opt,name=is_auto_increment,json=isAutoIncrement,proto3" json:"is_auto_increment,omitempty"` - IsIdentity bool `protobuf:"varint,13,opt,name=is_identity,json=isIdentity,proto3" json:"is_identity,omitempty"` - Comment string `protobuf:"bytes,14,opt,name=comment,proto3" json:"comment,omitempty"` - PkConstraintName string `protobuf:"bytes,15,opt,name=pk_constraint_name,json=pkConstraintName,proto3" json:"pk_constraint_name,omitempty"` - OriginalIndex int32 `protobuf:"varint,16,opt,name=original_index,json=originalIndex,proto3" json:"original_index,omitempty"` - Original *ColumnDefinition `protobuf:"bytes,17,opt,name=original,proto3" json:"original,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` + EnumValues []string `protobuf:"bytes,4,rep,name=enum_values,json=enumValues,proto3" json:"enum_values,omitempty"` + Length *int64 `protobuf:"varint,5,opt,name=length,proto3,oneof" json:"length,omitempty"` + Precision *int64 `protobuf:"varint,6,opt,name=precision,proto3,oneof" json:"precision,omitempty"` + Scale *int64 `protobuf:"varint,7,opt,name=scale,proto3,oneof" json:"scale,omitempty"` + Nullable bool `protobuf:"varint,8,opt,name=nullable,proto3" json:"nullable,omitempty"` + DefaultValue *string `protobuf:"bytes,9,opt,name=default_value,json=defaultValue,proto3,oneof" json:"default_value,omitempty"` + IsDefaultExpression bool `protobuf:"varint,10,opt,name=is_default_expression,json=isDefaultExpression,proto3" json:"is_default_expression,omitempty"` + IsPrimaryKey bool `protobuf:"varint,11,opt,name=is_primary_key,json=isPrimaryKey,proto3" json:"is_primary_key,omitempty"` + IsAutoIncrement bool `protobuf:"varint,12,opt,name=is_auto_increment,json=isAutoIncrement,proto3" json:"is_auto_increment,omitempty"` + IsIdentity bool `protobuf:"varint,13,opt,name=is_identity,json=isIdentity,proto3" json:"is_identity,omitempty"` + Comment string `protobuf:"bytes,14,opt,name=comment,proto3" json:"comment,omitempty"` + PkConstraintName string `protobuf:"bytes,15,opt,name=pk_constraint_name,json=pkConstraintName,proto3" json:"pk_constraint_name,omitempty"` + OriginalIndex int32 `protobuf:"varint,16,opt,name=original_index,json=originalIndex,proto3" json:"original_index,omitempty"` + Original *ColumnDefinition `protobuf:"bytes,17,opt,name=original,proto3" json:"original,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -548,25 +548,25 @@ func (x *ColumnDefinition) GetEnumValues() []string { return nil } -func (x *ColumnDefinition) GetLength() *structpb.Value { - if x != nil { - return x.Length +func (x *ColumnDefinition) GetLength() int64 { + if x != nil && x.Length != nil { + return *x.Length } - return nil + return 0 } -func (x *ColumnDefinition) GetPrecision() *structpb.Value { - if x != nil { - return x.Precision +func (x *ColumnDefinition) GetPrecision() int64 { + if x != nil && x.Precision != nil { + return *x.Precision } - return nil + return 0 } -func (x *ColumnDefinition) GetScale() *structpb.Value { - if x != nil { - return x.Scale +func (x *ColumnDefinition) GetScale() int64 { + if x != nil && x.Scale != nil { + return *x.Scale } - return nil + return 0 } func (x *ColumnDefinition) GetNullable() bool { @@ -576,11 +576,11 @@ func (x *ColumnDefinition) GetNullable() bool { return false } -func (x *ColumnDefinition) GetDefaultValue() *wrapperspb.StringValue { - if x != nil { - return x.DefaultValue +func (x *ColumnDefinition) GetDefaultValue() string { + if x != nil && x.DefaultValue != nil { + return *x.DefaultValue } - return nil + return "" } func (x *ColumnDefinition) GetIsDefaultExpression() bool { @@ -1463,18 +1463,18 @@ const file_api_vstable_proto_rawDesc = "" + "\rQueryResponse\x12\x18\n" + "\asuccess\x18\x01 \x01(\bR\asuccess\x12+\n" + "\x04rows\x18\x02 \x03(\v2\x17.google.protobuf.StructR\x04rows\x12*\n" + - "\x06fields\x18\x03 \x03(\v2\x12.vstable.FieldInfoR\x06fields\"\xab\x05\n" + + "\x06fields\x18\x03 \x03(\v2\x12.vstable.FieldInfoR\x06fields\"\x8e\x05\n" + "\x10ColumnDefinition\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" + "\x04type\x18\x03 \x01(\tR\x04type\x12\x1f\n" + "\venum_values\x18\x04 \x03(\tR\n" + - "enumValues\x12.\n" + - "\x06length\x18\x05 \x01(\v2\x16.google.protobuf.ValueR\x06length\x124\n" + - "\tprecision\x18\x06 \x01(\v2\x16.google.protobuf.ValueR\tprecision\x12,\n" + - "\x05scale\x18\a \x01(\v2\x16.google.protobuf.ValueR\x05scale\x12\x1a\n" + - "\bnullable\x18\b \x01(\bR\bnullable\x12A\n" + - "\rdefault_value\x18\t \x01(\v2\x1c.google.protobuf.StringValueR\fdefaultValue\x122\n" + + "enumValues\x12\x1b\n" + + "\x06length\x18\x05 \x01(\x03H\x00R\x06length\x88\x01\x01\x12!\n" + + "\tprecision\x18\x06 \x01(\x03H\x01R\tprecision\x88\x01\x01\x12\x19\n" + + "\x05scale\x18\a \x01(\x03H\x02R\x05scale\x88\x01\x01\x12\x1a\n" + + "\bnullable\x18\b \x01(\bR\bnullable\x12(\n" + + "\rdefault_value\x18\t \x01(\tH\x03R\fdefaultValue\x88\x01\x01\x122\n" + "\x15is_default_expression\x18\n" + " \x01(\bR\x13isDefaultExpression\x12$\n" + "\x0eis_primary_key\x18\v \x01(\bR\fisPrimaryKey\x12*\n" + @@ -1484,7 +1484,12 @@ const file_api_vstable_proto_rawDesc = "" + "\acomment\x18\x0e \x01(\tR\acomment\x12,\n" + "\x12pk_constraint_name\x18\x0f \x01(\tR\x10pkConstraintName\x12%\n" + "\x0eoriginal_index\x18\x10 \x01(\x05R\roriginalIndex\x125\n" + - "\boriginal\x18\x11 \x01(\v2\x19.vstable.ColumnDefinitionR\boriginal\"\xa2\x01\n" + + "\boriginal\x18\x11 \x01(\v2\x19.vstable.ColumnDefinitionR\boriginalB\t\n" + + "\a_lengthB\f\n" + + "\n" + + "_precisionB\b\n" + + "\x06_scaleB\x10\n" + + "\x0e_default_value\"\xa2\x01\n" + "\x0fIndexDefinition\x12\x0e\n" + "\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x18\n" + @@ -1608,56 +1613,50 @@ var file_api_vstable_proto_goTypes = []any{ (*GenerateSQLResponse)(nil), // 18: vstable.GenerateSQLResponse (*structpb.ListValue)(nil), // 19: google.protobuf.ListValue (*structpb.Struct)(nil), // 20: google.protobuf.Struct - (*structpb.Value)(nil), // 21: google.protobuf.Value - (*wrapperspb.StringValue)(nil), // 22: google.protobuf.StringValue } var file_api_vstable_proto_depIdxs = []int32{ 19, // 0: vstable.QueryRequest.params:type_name -> google.protobuf.ListValue 20, // 1: vstable.QueryResponse.rows:type_name -> google.protobuf.Struct 7, // 2: vstable.QueryResponse.fields:type_name -> vstable.FieldInfo - 21, // 3: vstable.ColumnDefinition.length:type_name -> google.protobuf.Value - 21, // 4: vstable.ColumnDefinition.precision:type_name -> google.protobuf.Value - 21, // 5: vstable.ColumnDefinition.scale:type_name -> google.protobuf.Value - 22, // 6: vstable.ColumnDefinition.default_value:type_name -> google.protobuf.StringValue - 9, // 7: vstable.ColumnDefinition.original:type_name -> vstable.ColumnDefinition - 10, // 8: vstable.IndexDefinition.original:type_name -> vstable.IndexDefinition - 11, // 9: vstable.ForeignKeyDefinition.original:type_name -> vstable.ForeignKeyDefinition - 12, // 10: vstable.CheckConstraintDefinition.original:type_name -> vstable.CheckConstraintDefinition - 13, // 11: vstable.ViewDefinition.original:type_name -> vstable.ViewDefinition - 14, // 12: vstable.TriggerDefinition.original:type_name -> vstable.TriggerDefinition - 15, // 13: vstable.RoutineDefinition.original:type_name -> vstable.RoutineDefinition - 9, // 14: vstable.DiffRequest.columns:type_name -> vstable.ColumnDefinition - 10, // 15: vstable.DiffRequest.indexes:type_name -> vstable.IndexDefinition - 9, // 16: vstable.DiffRequest.deleted_columns:type_name -> vstable.ColumnDefinition - 10, // 17: vstable.DiffRequest.deleted_indexes:type_name -> vstable.IndexDefinition - 11, // 18: vstable.DiffRequest.foreign_keys:type_name -> vstable.ForeignKeyDefinition - 11, // 19: vstable.DiffRequest.deleted_foreign_keys:type_name -> vstable.ForeignKeyDefinition - 12, // 20: vstable.DiffRequest.check_constraints:type_name -> vstable.CheckConstraintDefinition - 12, // 21: vstable.DiffRequest.deleted_checks:type_name -> vstable.CheckConstraintDefinition - 13, // 22: vstable.DiffRequest.views:type_name -> vstable.ViewDefinition - 13, // 23: vstable.DiffRequest.deleted_views:type_name -> vstable.ViewDefinition - 14, // 24: vstable.DiffRequest.triggers:type_name -> vstable.TriggerDefinition - 14, // 25: vstable.DiffRequest.deleted_triggers:type_name -> vstable.TriggerDefinition - 15, // 26: vstable.DiffRequest.routines:type_name -> vstable.RoutineDefinition - 15, // 27: vstable.DiffRequest.deleted_routines:type_name -> vstable.RoutineDefinition - 16, // 28: vstable.DiffRequest.config:type_name -> vstable.DatabaseConfig - 0, // 29: vstable.EngineService.Ping:input_type -> vstable.PingRequest - 2, // 30: vstable.EngineService.DbConnect:input_type -> vstable.ConnectRequest - 4, // 31: vstable.EngineService.Disconnect:input_type -> vstable.DisconnectRequest - 6, // 32: vstable.EngineService.Query:input_type -> vstable.QueryRequest - 17, // 33: vstable.EngineService.GenerateAlterTable:input_type -> vstable.DiffRequest - 17, // 34: vstable.EngineService.GenerateCreateTable:input_type -> vstable.DiffRequest - 1, // 35: vstable.EngineService.Ping:output_type -> vstable.PingResponse - 3, // 36: vstable.EngineService.DbConnect:output_type -> vstable.ConnectResponse - 5, // 37: vstable.EngineService.Disconnect:output_type -> vstable.DisconnectResponse - 8, // 38: vstable.EngineService.Query:output_type -> vstable.QueryResponse - 18, // 39: vstable.EngineService.GenerateAlterTable:output_type -> vstable.GenerateSQLResponse - 18, // 40: vstable.EngineService.GenerateCreateTable:output_type -> vstable.GenerateSQLResponse - 35, // [35:41] is the sub-list for method output_type - 29, // [29:35] is the sub-list for method input_type - 29, // [29:29] is the sub-list for extension type_name - 29, // [29:29] is the sub-list for extension extendee - 0, // [0:29] is the sub-list for field type_name + 9, // 3: vstable.ColumnDefinition.original:type_name -> vstable.ColumnDefinition + 10, // 4: vstable.IndexDefinition.original:type_name -> vstable.IndexDefinition + 11, // 5: vstable.ForeignKeyDefinition.original:type_name -> vstable.ForeignKeyDefinition + 12, // 6: vstable.CheckConstraintDefinition.original:type_name -> vstable.CheckConstraintDefinition + 13, // 7: vstable.ViewDefinition.original:type_name -> vstable.ViewDefinition + 14, // 8: vstable.TriggerDefinition.original:type_name -> vstable.TriggerDefinition + 15, // 9: vstable.RoutineDefinition.original:type_name -> vstable.RoutineDefinition + 9, // 10: vstable.DiffRequest.columns:type_name -> vstable.ColumnDefinition + 10, // 11: vstable.DiffRequest.indexes:type_name -> vstable.IndexDefinition + 9, // 12: vstable.DiffRequest.deleted_columns:type_name -> vstable.ColumnDefinition + 10, // 13: vstable.DiffRequest.deleted_indexes:type_name -> vstable.IndexDefinition + 11, // 14: vstable.DiffRequest.foreign_keys:type_name -> vstable.ForeignKeyDefinition + 11, // 15: vstable.DiffRequest.deleted_foreign_keys:type_name -> vstable.ForeignKeyDefinition + 12, // 16: vstable.DiffRequest.check_constraints:type_name -> vstable.CheckConstraintDefinition + 12, // 17: vstable.DiffRequest.deleted_checks:type_name -> vstable.CheckConstraintDefinition + 13, // 18: vstable.DiffRequest.views:type_name -> vstable.ViewDefinition + 13, // 19: vstable.DiffRequest.deleted_views:type_name -> vstable.ViewDefinition + 14, // 20: vstable.DiffRequest.triggers:type_name -> vstable.TriggerDefinition + 14, // 21: vstable.DiffRequest.deleted_triggers:type_name -> vstable.TriggerDefinition + 15, // 22: vstable.DiffRequest.routines:type_name -> vstable.RoutineDefinition + 15, // 23: vstable.DiffRequest.deleted_routines:type_name -> vstable.RoutineDefinition + 16, // 24: vstable.DiffRequest.config:type_name -> vstable.DatabaseConfig + 0, // 25: vstable.EngineService.Ping:input_type -> vstable.PingRequest + 2, // 26: vstable.EngineService.DbConnect:input_type -> vstable.ConnectRequest + 4, // 27: vstable.EngineService.Disconnect:input_type -> vstable.DisconnectRequest + 6, // 28: vstable.EngineService.Query:input_type -> vstable.QueryRequest + 17, // 29: vstable.EngineService.GenerateAlterTable:input_type -> vstable.DiffRequest + 17, // 30: vstable.EngineService.GenerateCreateTable:input_type -> vstable.DiffRequest + 1, // 31: vstable.EngineService.Ping:output_type -> vstable.PingResponse + 3, // 32: vstable.EngineService.DbConnect:output_type -> vstable.ConnectResponse + 5, // 33: vstable.EngineService.Disconnect:output_type -> vstable.DisconnectResponse + 8, // 34: vstable.EngineService.Query:output_type -> vstable.QueryResponse + 18, // 35: vstable.EngineService.GenerateAlterTable:output_type -> vstable.GenerateSQLResponse + 18, // 36: vstable.EngineService.GenerateCreateTable:output_type -> vstable.GenerateSQLResponse + 31, // [31:37] is the sub-list for method output_type + 25, // [25:31] is the sub-list for method input_type + 25, // [25:25] is the sub-list for extension type_name + 25, // [25:25] is the sub-list for extension extendee + 0, // [0:25] is the sub-list for field type_name } func init() { file_api_vstable_proto_init() } @@ -1665,6 +1664,7 @@ func file_api_vstable_proto_init() { if File_api_vstable_proto != nil { return } + file_api_vstable_proto_msgTypes[9].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ diff --git a/backend/main.go b/backend/main.go index 0284b12..8af8469 100644 --- a/backend/main.go +++ b/backend/main.go @@ -12,6 +12,10 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "net/http" + + "github.com/improbable-eng/grpc-web/go/grpcweb" + "github.com/rs/cors" "vstable-engine/internal/ast" "vstable-engine/internal/db" @@ -171,8 +175,32 @@ func main() { dbManager := db.NewManager() pb.RegisterEngineServiceServer(grpcServer, &engineServer{dbManager: dbManager}) - fmt.Printf("gRPC Engine listening on :%s...\n", port) - if err := grpcServer.Serve(lis); err != nil { + wrappedGrpc := grpcweb.WrapServer(grpcServer, + grpcweb.WithOriginFunc(func(origin string) bool { return true }), + ) + + handler := func(res http.ResponseWriter, req *http.Request) { + if wrappedGrpc.IsGrpcWebRequest(req) || wrappedGrpc.IsAcceptableGrpcCorsRequest(req) { + wrappedGrpc.ServeHTTP(res, req) + return + } + http.DefaultServeMux.ServeHTTP(res, req) + } + + corsHandler := cors.New(cors.Options{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"GET", "POST", "OPTIONS"}, + AllowedHeaders: []string{"Accept", "Accept-Encoding", "Accept-Language", "Content-Length", "Content-Type", "x-grpc-web", "x-user-agent", "x-trace-id"}, + AllowCredentials: false, + }).Handler(http.HandlerFunc(handler)) + + fmt.Printf("gRPC-Web Engine listening on :%s...\n", port) + + httpServer := &http.Server{ + Handler: corsHandler, + } + + if err := httpServer.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } diff --git a/frontend/AGENTS.md b/frontend/AGENTS.md new file mode 100644 index 0000000..c555f70 --- /dev/null +++ b/frontend/AGENTS.md @@ -0,0 +1,47 @@ +# Agent Context: Frontend (React & Web) + +> **ATTENTION AI AGENTS & DEVELOPERS:** +> 此目录 `frontend/` 包含了 vstable 的 React 客户端逻辑。在进行 UI 组件修改、状态管理调整或网络层交互时,请严格遵循本文件的开发规范。 + +## 1. Core Architecture & Logic + +**React 19 + Vite + gRPC-Web** +前端不仅是一个展示层,它还需要承载复杂的“状态构建”任务(如可视化的 Schema 设计器)。 + +- **直接网络通信 (gRPC-Web)**: + - 使用 `nice-grpc-web` 库创建 HTTP 客户端(`src/api/grpcClient.ts`)。 + - **核心链路**:绕过 Tauri IPC,直接通过 Fetch 请求向后端的 `:39082` 端口发送序列化数据。 +- **全局拦截器与错误处理**: + - 所有的网络请求错误在 `loggingAndErrorInterceptor` 中统一捕获,并提取 gRPC Status Code 转换为前端友好的 Toast/Alert。 +- **状态管理 (Zustand)**: + - `stores/` 目录中维护了全局状态(如活跃连接、当前工作区)。业务逻辑通过拆分的 Custom Hooks 消费这些状态。 +- **Schema Designer 状态机**: + - 前端负责维护表结构的 "New State"(增删改操作),在保存时将其构建为 Protobuf 结构体发送给后端进行 Diff 计算。 + +## 2. Business Logic Map (业务逻辑快速定位导航) + +当你需要修改某个特定业务功能时,请直接前往对应的目录: + +- **`src/features/connection/` (连接管理)** + - 逻辑:处理数据库的登录信息表单、连接测试。调用 `tauri-plugin-store` 进行本地持久化。 +- **`src/features/navigator/` (数据库左侧边栏树形视图)** + - 逻辑:显示 Databases、Schemas、Tables。处理右键菜单操作(打开数据、设计表结构等)。 +- **`src/features/query-editor/` (SQL 编辑器与执行台)** + - 逻辑:基于 Monaco Editor 的多标签页 SQL 编写环境。支持快捷键执行、结果集统计、SQL 高亮。 +- **`src/features/schema-designer/` (核心:可视化架构设计器)** + - 逻辑:维护表结构的 AST 视图。支持增删列、设置主键/外键/索引、调整类型和长度。保存时触发 DDL 预览。 +- **`src/features/table-viewer/` (数据网格查看器)** + - 逻辑:用于展示表行数据。支持内联编辑 (Inline Update)、新增行、右键删除。管理分页和过滤条件构建。 + +## 3. Hard Rules for AI Agents (Frontend Layer) + +- **[RULE 1] 严禁使用 Tauri IPC 代理业务请求**: + - 前后端业务通信**只能**通过 `src/api/client.ts` 封装的 gRPC-Web 客户端调用。仅在需要原生系统能力(存储、窗口控制)时允许使用 Tauri IPC。 +- **[RULE 2] 类型对齐强制约束**: + - 前端请求和响应体**必须**使用 `gen_proto.sh` 生成的 TypeScript 类型。绝不允许在前端擅自 Hardcode 接口响应类型(如 `interface MyFakeResponse {}`)。 +- **[RULE 3] 稳定 DOM 排序 (Stable DOM Sorting)**: + - **红线**:Monaco Editor 对 DOM 物理位置极度敏感。在实现拖拽、Tabs 或列表排序时,必须保证真实 DOM 结构顺序不变。仅允许通过数据驱动的 CSS `display: none` 或 flex `order` 等视觉手段表现状态切换,以防 Monaco 实例销毁或内存泄露。 +- **[RULE 4] UI 审美与交互标准**: + - 使用 TailwindCSS 4.0 进行样式开发。 + - 破坏性操作必须调用全局 ConfirmModal 进行二次确认。 + - 大数据量渲染必须使用虚拟列表技术。 diff --git a/frontend/e2e/AGENTS.md b/frontend/e2e/AGENTS.md index c907d3b..555ea8d 100644 --- a/frontend/e2e/AGENTS.md +++ b/frontend/e2e/AGENTS.md @@ -1,45 +1,42 @@ # Agent Context: Frontend E2E Tests -## Goals and Scope -- 验证 `vstable` 客户端的核心 UI 交互逻辑。 -- 测试重点:数据库连接管理、架构设计器(Schema Designer)、数据网格(Data Grid)CRUD、分页与过滤。 -- **架构**:基于 Playwright 的 Web 自动化测试,通过 Mock Tauri IPC 桥接层与 Go 引擎通信。 -- **不在范围内**:底层的 Go 引擎单元测试、纯前端组件的 Vitest 单元测试。 - -## Execution Rules -- **运行命令**:在 `frontend/` 目录下执行 `npm run test:e2e`。 -- **环境要求**: - - 本地运行会自动通过 `global-setup.ts` 启动 Docker 容器和 Go 引擎后台进程。 - - 测试通过 `fixture.ts` 注入 `window.__TAURI_INTERNALS__` 实现底层模拟。 -- **最佳实践**: - - 优先使用 `data-testid` 定位器。 - - 使用 `expect(...).toPass()` 处理异步延迟(如数据库响应或动画)。 - - 测试用例应从 `import { test, expect } from './fixture'` 导入以启用 Tauri 模拟。 - - 为了尽可能还原真实环境,`./fixture` 只能用于模拟 Tauri 相关的调用,而不能处理业务逻辑。 - -## Test Matrix - -**Connection Management** -- C-01 PostgreSQL Connection: 输入主机、端口、凭据,点击连接,表单消失并显示侧边栏。 -- C-02 MySQL Connection: 切换 Dialect 为 MySQL,验证不同默认端口(3307)的连接流。 - -**Schema Designer** -- S-01 Create Table: 输入表名,添加多个列,选择数据类型,验证 DDL 执行预览。 -- S-02 Column Operations: 验证添加/删除列、设置主键(PK)、设置长度/精度。 -- S-03 DDL Execution: 提交更改后,验证结构页签关闭且侧边栏出现新表。 - -**Data Grid** -- D-01 Create Row: 右键菜单 "Add Row",输入数据,保存并验证行出现在网格中。 -- D-02 Inline Update: 双击单元格打开编辑模态框/文本框,修改值并保存。 -- D-03 Delete Row: 右键选择 "Delete Row",验证 ConfirmModal 弹出并确认删除。 -- D-04 Refresh: 点击刷新按钮或按下快捷键 (Cmd/Ctrl+R),数据重新加载。 - -**Advanced Features** -- A-01 SQL Console: 使用快捷键 (Cmd/Ctrl+T) 打开新页签,执行批量 SQL,验证结果统计显示。 -- A-02 Pagination: 验证数据超过每页限额(默认 100)时出现分页控件,点击 "Next" 翻页。 -- A-03 Sorting: 点击列头切换升序/降序状态。 -- A-04 Filtering: 使用 Filter Bar 测试包含 `=`, `>`, `BETWEEN`, `IN`, `NOT IN`, `IS NULL`, `IS NOT NULL` 等多种比较操作符,验证数据精确匹配。 - -**Resilience and Errors** -- R-01 Constraint Violation: 尝试插入重复主键或非法格式(如 UUID 列填入普通字符串),验证 AlertModal 报错。 -- R-02 Connection Failure: 输入错误的凭据,验证 UI 显示明确的错误提示。 +> **ATTENTION AI AGENTS & DEVELOPERS:** +> 此目录 `frontend/e2e/` 包含了保证 `vstable` 核心链路稳定性的最重要防线。在编写和维护测试用例时,请严格遵守本文件定义的真实全链路测试规范。 + +## 1. Core Logic & Testing Philosophy + +**真实环境,拒绝重度 Mock (Real Environment over Heavy Mocks)** +- 本项目的 E2E 测试基于 Playwright 框架。 +- 在测试启动前,`global-setup.ts` 会自动拉起真实的 Docker 数据库(PostgreSQL/MySQL)以及**真实的 Go Engine 后台进程**。 +- 得益于目前的 gRPC-Web 直连架构,运行在 Playwright 浏览器实例中的 React 前端将**直接发送 HTTP 请求**到真实 Go Engine。 +- **核心逻辑**:通过真实的 AST 解析、真实的 Schema Diff 生成和真实的数据库 DDL 执行,来验证 UI 的正确性。 + +## 2. Hard Rules for AI Agents (E2E Layer) + +在编写 E2E 测试代码时,必须遵守以下铁律: + +- **[RULE 1] 禁止拦截和 Mock 数据库网络请求**: + - 不得在 `fixture.ts` 或具体的测试用例中使用 `page.route` 或 `__playwright_invoke` 去模拟 `db_connect`, `db_query`, `sql_generate_alter` 等业务操作。 + - 所有业务请求必须畅通无阻地打到后端的 `localhost:39082`。 +- **[RULE 2] 仅 Mock 必要的系统原生能力 (Tauri IPC)**: + - 测试用例必须从 `import { test, expect } from './fixture'` 导入。 + - `fixture.ts` 的唯一职责是拦截 `window.__TAURI_INTERNALS__.invoke`,以 Mock 掉那些在无头浏览器中不存在的原生调用(例如:窗口最大化 `window_toggle_maximize`、持久化存储 `tauri-plugin-store`)。 +- **[RULE 3] 异步断言与稳定性保障 (Async Resilience)**: + - 由于走真实的数据库交互,网络和 SQL 执行会有延迟。 + - 必须使用 `expect(...).toPass()` 配合重试机制,或者使用 `page.waitForResponse` 等待对应的 gRPC-Web 响应,绝不允许使用 `page.waitForTimeout` 硬编码死等。 +- **[RULE 4] 测试环境隔离 (Test Isolation)**: + - 每个测试用例在执行 DDL 操作(建表、删列)时,必须使用带有随机后缀或时间戳的 Table Name,避免测试并发执行或重复执行时产生的脏数据冲突。 + +## 3. Test Matrix (Key Flows to Verify) + +维护或新增功能时,必须确保覆盖以下链路: + +- **Connection Management (连接与认证)**: + - PostgreSQL 与 MySQL 的登录连通性。错误密码的拦截与 Alert 提示。 +- **Schema Designer (架构设计器)**: + - S-01: 可视化添加列(主键、类型、长度)、预览 DDL 语句是否生成准确。 + - S-02: 提交应用后,数据库 Navigator 树是否能正确拉取并显示新表。 +- **Data Grid (数据操作)**: + - 插入新行 (Add Row)、内联单元格更新 (Inline Update)、删除数据行。 +- **Advanced UI Interactions**: + - SQL Console 多标签页执行、数据表的客户端级 Pagination(分页)与字段过滤(Filter Bar)。 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e3b4e9d..8d6a58b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,8 @@ "@tauri-apps/plugin-store": "^2.2.0", "lucide-react": "^0.563.0", "mysql2": "^3.18.2", + "nice-grpc-common": "^2.0.3", + "nice-grpc-web": "^3.3.10", "pg": "^8.18.0", "react": "^19.2.4", "react-dom": "^19.2.4", @@ -32,6 +34,7 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@types/jest": "^30.0.0", "@types/node": "^25.2.3", "@types/pg": "^8.16.0", "@types/react": "^19.2.13", @@ -42,6 +45,7 @@ "playwright": "^1.58.2", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", + "ts-proto": "^2.11.6", "typescript": "^5.9.3", "vite": "^7.3.1", "vitest": "^4.0.18", @@ -798,6 +802,13 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/@bufbuild/protobuf": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", + "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, "node_modules/@exodus/bytes": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.14.1.tgz", @@ -849,6 +860,85 @@ "node": ">=6" } }, + "node_modules/@jest/diff-sequences": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz", + "integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz", + "integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz", + "integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -1361,6 +1451,13 @@ "win32" ] }, + "node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "dev": true, + "license": "MIT" + }, "node_modules/@tailwindcss/node": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", @@ -2125,6 +2222,72 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@types/node": { "version": "25.3.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.3.tgz", @@ -2169,6 +2332,30 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", @@ -2318,6 +2505,12 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/abort-controller-x": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.5.0.tgz", + "integrity": "sha512-yTt9CI0x+nRfX6BFMenEGP8ooPvErGH6AbFz20C2IeOLIlDsrw/VHpgne3GsCEuTA410IiFiaLVFKmgM4bKEPQ==", + "license": "MIT" + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2518,6 +2711,19 @@ ], "license": "CC-BY-4.0" }, + "node_modules/case-anything": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", + "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -2528,6 +2734,39 @@ "node": ">=18" } }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2879,6 +3118,29 @@ "dev": true, "license": "MIT" }, + "node_modules/dprint-node": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", + "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + } + }, + "node_modules/dprint-node/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -3003,6 +3265,34 @@ "node": ">=6" } }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/expect": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz", + "integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.3.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.3.0", + "jest-message-util": "30.3.0", + "jest-mock": "30.3.0", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -3190,6 +3480,16 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -3297,6 +3597,195 @@ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", "license": "MIT" }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jest-diff": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz", + "integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.3.0", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz", + "integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.3.0", + "pretty-format": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz", + "integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.3.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3", + "pretty-format": "30.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", + "integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz", + "integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "jest-util": "30.3.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util": { + "version": "30.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz", + "integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.3.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -3386,6 +3875,12 @@ "dev": true, "license": "MIT" }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3929,6 +4424,27 @@ "node": ">=8.0.0" } }, + "node_modules/nice-grpc-common": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.3.tgz", + "integrity": "sha512-MEhnD3JMah0mgyivpb9hpRDbOBuXBxI/TVO+OK1h6rC97WM42HsPMR+zzRNQ0C5BqYJTw1nyWiQRD0DucO+pjQ==", + "license": "MIT", + "dependencies": { + "ts-error": "^1.0.6" + } + }, + "node_modules/nice-grpc-web": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/nice-grpc-web/-/nice-grpc-web-3.3.10.tgz", + "integrity": "sha512-8XyCtbs7uL0mWQEjpkjZy57bnLbtheRbIWgj8p98XPbjFqXOBkTLu+ebj5H4fUu/yxqt+6ULPPDHT/icUsyieA==", + "license": "MIT", + "dependencies": { + "abort-controller-x": "^0.5.0", + "isomorphic-ws": "^5.0.0", + "js-base64": "^3.7.2", + "nice-grpc-common": "^2.0.3" + } + }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -4075,7 +4591,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -4329,6 +4844,13 @@ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "license": "MIT" }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, "node_modules/react-refresh": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", @@ -4433,6 +4955,16 @@ "dev": true, "license": "ISC" }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4466,6 +4998,19 @@ "url": "https://github.com/mysqljs/sql-escaper?sponsor=1" } }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -4521,6 +5066,19 @@ "node": ">=8" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -4642,6 +5200,48 @@ "dev": true, "license": "MIT" }, + "node_modules/ts-error": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", + "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==", + "license": "MIT" + }, + "node_modules/ts-poet": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", + "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dprint-node": "^1.0.8" + } + }, + "node_modules/ts-proto": { + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.11.6.tgz", + "integrity": "sha512-2rPkH5W/KeXOyVUC6o06RdRabVK8zSDmQpnRz4XbRiYMHRdI12KqDjAdGW7ebxzzMNE5cw/j+ptA0WMVqZILrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.10.2", + "case-anything": "^2.1.13", + "ts-poet": "^6.12.0", + "ts-proto-descriptors": "2.1.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.1.0.tgz", + "integrity": "sha512-S5EZYEQ6L9KLFfjSRpZWDIXDV/W7tAj8uW7pLsihIxyr62EAVSiKuVPwE8iWnr849Bqa53enex1jhDUcpgquzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0" + } + }, "node_modules/tslib": { "optional": true }, @@ -5523,6 +6123,28 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 5597bdd..92d1c7b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "preview": "vite preview", "test": "vitest", "test:e2e": "playwright test", + "generate:proto": "mkdir -p src/types && protoc --plugin=protoc-gen-ts_proto=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=src/types --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,env=browser,esModuleInterop=true,forceLong=number,useOptionals=all,outputEncodeMethods=true,outputJsonMethods=false,outputPartialMethods=false --proto_path=../backend/api ../backend/api/vstable.proto", "docker:up": "docker compose -f docker-compose.yml up -d", "docker:down": "docker compose -f docker-compose.yml down -v", "lint": "biome lint .", @@ -37,6 +38,7 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@types/jest": "^30.0.0", "@types/node": "^25.2.3", "@types/pg": "^8.16.0", "@types/react": "^19.2.13", @@ -47,6 +49,7 @@ "playwright": "^1.58.2", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", + "ts-proto": "^2.11.6", "typescript": "^5.9.3", "vite": "^7.3.1", "vitest": "^4.0.18", @@ -60,6 +63,8 @@ "@tauri-apps/plugin-store": "^2.2.0", "lucide-react": "^0.563.0", "mysql2": "^3.18.2", + "nice-grpc-common": "^2.0.3", + "nice-grpc-web": "^3.3.10", "pg": "^8.18.0", "react": "^19.2.4", "react-dom": "^19.2.4", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d8985b3..8bdaafa 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -34,7 +34,7 @@ const SessionsContent: React.FC = React.memo( initialConfig={session.initialConfig} initialWorkspace={session.initialWorkspace} onStateChange={onStateChange} - onUpdateTitle={onUpdateTitle} + onUpdateTitle={(title: string) => onUpdateTitle(session.id, title)} /> ))} diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 7547d07..400cb68 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -1,25 +1,18 @@ import { invoke } from '@tauri-apps/api/core'; import { LazyStore } from '@tauri-apps/plugin-store'; -import { info } from '@tauri-apps/plugin-log'; import type { ConnectionConfig, PersistedWorkspace, QueryResult } from '../types/session'; +import type { DiffRequest } from '../types/vstable'; +import { grpcClient } from './grpcClient'; /** - * API Client Layer (Tauri Version) - * Encapsulates all IPC calls to Tauri invoke and Store. + * API Client Layer + * Encapsulates gRPC-Web calls to Go engine and IPC calls to Tauri Store/Native. */ const store = new LazyStore('settings.json'); -const callApi = async (command: string, args: Record = {}): Promise => { - const traceId = crypto.randomUUID(); - const payload = { ...args, traceId }; - // Log the outgoing request to the unified log file - info(`[${traceId}] IPC Call: ${command} | args: ${JSON.stringify(args)}`); - return invoke(command, payload); -}; - export const apiClient = { - // Database Operations + // Database Operations via gRPC-Web connect: async (id: string, config: ConnectionConfig): Promise => { const { dialect, user, password, host, port, database } = config; let dsn = ''; @@ -28,23 +21,39 @@ export const apiClient = { } else { dsn = `postgres://${user}:${password}@${host}:${port}/${database}?sslmode=disable`; } - return callApi('db_connect', { id, dialect, dsn }); + await grpcClient.dbConnect({ id, dialect, dsn }); + return { success: true }; }, - query: async (id: string, sql: string, params?: any[]): Promise => - callApi('db_query', { id, sql, params }), + query: async (id: string, sql: string, params?: any[]): Promise => { + const res = await grpcClient.query({ id, sql, params }); + return { + success: res.success || false, + rows: res.rows || [], + fields: res.fields as { name: string; type: string }[] | undefined, + }; + }, - disconnect: async (id: string): Promise => callApi('db_disconnect', { id }), + disconnect: async (id: string): Promise => { + await grpcClient.disconnect({ id }); + }, - enginePing: async (): Promise => callApi('engine_ping'), + enginePing: async (): Promise => { + try { + const res = await grpcClient.ping({}); + return res.status === 'ok'; + } catch { + return false; + } + }, - generateAlterSql: async (req: any): Promise => { - const res: any = await callApi('sql_generate_alter', { req }); + generateAlterSql: async (req: DiffRequest): Promise => { + const res = await grpcClient.generateAlterTable(req); return res.sqls || []; }, - generateCreateSql: async (req: any): Promise => { - const res: any = await callApi('sql_generate_create', { req }); + generateCreateSql: async (req: DiffRequest): Promise => { + const res = await grpcClient.generateCreateTable(req); return res.sqls || []; }, @@ -76,7 +85,8 @@ export const apiClient = { }, getWorkspace: async (): Promise => { - return store.get('workspace'); + const ws = await store.get('workspace'); + return ws ?? null; }, saveWorkspace: async (data: PersistedWorkspace): Promise => { diff --git a/frontend/src/api/grpcClient.ts b/frontend/src/api/grpcClient.ts new file mode 100644 index 0000000..b0cee0e --- /dev/null +++ b/frontend/src/api/grpcClient.ts @@ -0,0 +1,48 @@ +import { + type CallOptions, + ClientError, + type ClientMiddlewareCall, + createChannel, + createClient, +} from 'nice-grpc-web'; +import { type EngineServiceClient, EngineServiceDefinition } from '../types/vstable'; + +// Middleware to log requests and handle errors uniformly +async function* loggingAndErrorInterceptor( + call: ClientMiddlewareCall, + options: CallOptions +) { + const traceId = crypto.randomUUID(); + console.log(`[${traceId}] gRPC Call: ${call.method.path}`, call.request); + + // Inject trace-id into metadata + options.metadata = options.metadata || new Headers(); + if (options.metadata instanceof Headers) { + options.metadata.set('x-trace-id', traceId); + } else if (typeof options.metadata.set === 'function') { + options.metadata.set('x-trace-id', traceId); + } + + try { + return yield* call.next(call.request, options); + } catch (error: unknown) { + if (error instanceof ClientError) { + console.error(`[${traceId}] gRPC Error: ${call.method.path}`, error.code, error.details); + const apiError = new Error(`[${error.code}] ${error.details}`); + (apiError as any).code = error.code; + (apiError as any).originalMessage = error.details; + throw apiError; + } + throw error; + } +} + +// Create the gRPC-Web channel pointing to the local Go engine +const channel = createChannel('http://localhost:39082'); + +// Create the client with the interceptor +export const grpcClient: EngineServiceClient = createClient(EngineServiceDefinition, channel, { + '*': { + interceptors: [loggingAndErrorInterceptor], + }, +}); diff --git a/frontend/src/features/schema-designer/StructureView.test.tsx b/frontend/src/features/schema-designer/StructureView.test.tsx index 8a9b5ce..d74200f 100644 --- a/frontend/src/features/schema-designer/StructureView.test.tsx +++ b/frontend/src/features/schema-designer/StructureView.test.tsx @@ -28,7 +28,7 @@ describe('StructureView Component', () => { }); it('renders columns and indexes correctly', async () => { - (apiClient as any).query.mockImplementation((id, sql) => { + (apiClient as any).query.mockImplementation((id: any, sql: any) => { if (sql.includes('information_schema.columns')) { return Promise.resolve({ success: true, @@ -68,7 +68,7 @@ describe('StructureView Component', () => { }); it('handles index columns returned as Postgres array strings', async () => { - (apiClient as any).query.mockImplementation((id, sql) => { + (apiClient as any).query.mockImplementation((id: any, sql: any) => { if (sql.includes('information_schema.columns')) { return Promise.resolve({ success: true, @@ -139,7 +139,7 @@ describe('StructureView Component', () => { }); it('generates and executes SQL for changes', async () => { - (apiClient as any).query.mockImplementation((id, sql) => { + (apiClient as any).query.mockImplementation((id: any, sql: any) => { if (sql.includes('information_schema.columns')) { return Promise.resolve({ success: true, @@ -210,7 +210,7 @@ describe('StructureView Component', () => { }); it('handles identity columns and comments', async () => { - (apiClient as any).query.mockImplementation((id, sql) => { + (apiClient as any).query.mockImplementation((id: any, sql: any) => { if (sql.includes('information_schema.columns')) { return Promise.resolve({ success: true, diff --git a/frontend/src/features/schema-designer/StructureView.tsx b/frontend/src/features/schema-designer/StructureView.tsx index 4cc1695..0f7d519 100644 --- a/frontend/src/features/schema-designer/StructureView.tsx +++ b/frontend/src/features/schema-designer/StructureView.tsx @@ -25,9 +25,9 @@ export interface ColumnDefinition { id: string; name: string; type: string; - length?: string | number; - precision?: string | number; - scale?: string | number; + length?: number; + precision?: number; + scale?: number; nullable: boolean; defaultValue: any; isPrimaryKey: boolean; @@ -37,7 +37,7 @@ export interface ColumnDefinition { pkConstraintName?: string; isDefaultExpression?: boolean; enumValues?: string[]; - _original?: any; + original?: any; } export interface IndexDefinition { @@ -45,7 +45,7 @@ export interface IndexDefinition { name: string; columns: string[]; isUnique: boolean; - _original?: any; + original?: any; } interface StructureViewProps { @@ -121,7 +121,7 @@ const ColumnContextMenu: React.FC = ({ > Insert After - {column._original && ( + {column.original && (