mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-04 05:29:35 +08:00
🐛 fix(tdengine): 补齐超级表元数据查询
- 表列表合并 SHOW TABLES 与 SHOW STABLES 结果 - 返回前统一去重并排序,确保超级表可见 - 增加 TDEngine 表列表回归测试 Fixes #346
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
| #338 | 连接clickhouse不能通过8132端口 | Fixed | Pending |
|
||||
| #342 | 数据同步功能不能用,mysql数据库8.4版本选了结构同步,最后没同步成功 | Fixed | Pending |
|
||||
| #343 | redis删除hash类型中的key报错 | Fixed | Pending |
|
||||
| #346 | TDEngine只显示子表不显示超级表 | Fixed | Pending |
|
||||
| #351 | 为什么没有截断和清空表的功能呀? | Fixed | Pending |
|
||||
|
||||
## Notes
|
||||
@@ -123,6 +124,12 @@
|
||||
- 处理:前端改为传单元素数组;后端再增加一层参数归一化,兼容单字符串、字符串数组和 `[]interface{}` 三种形态,避免旧调用或异常入参再次在绑定层直接失败。
|
||||
- 验证:新增 `internal/app/methods_redis_test.go` 回归测试,覆盖单字符串与字符串数组两种调用形态,并执行 `go test ./internal/app -count=1` 与 `frontend` 下 `npm run build`。
|
||||
|
||||
### #346
|
||||
|
||||
- 根因:`TDengineDB.GetTables` 只查询 `SHOW TABLES`,没有把 `SHOW STABLES` 的超级表结果并入返回列表,导致 Sidebar 和依赖表列表的导出链路都只能看到子表。
|
||||
- 处理:为 TDEngine 表列表查询补充 `SHOW STABLES`,与 `SHOW TABLES` 结果统一去重合并后返回,保证普通表和超级表同时可见。
|
||||
- 验证:新增 `internal/db/tdengine_applychanges_test.go` 回归测试,覆盖 `GetTables` 返回普通表 + 超级表,并执行 `go test -tags gonavi_tdengine_driver ./internal/db -count=1`。
|
||||
|
||||
### #330
|
||||
|
||||
- 根因:查询结果表格已经支持拖拽调整列宽,但 resize handle 没有提供双击自适应逻辑,导致用户只能靠手工拖拽慢慢试宽度。
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -24,9 +26,10 @@ var (
|
||||
)
|
||||
|
||||
type tdengineRecordingState struct {
|
||||
mu sync.Mutex
|
||||
queries []string
|
||||
execErr error
|
||||
mu sync.Mutex
|
||||
queries []string
|
||||
execErr error
|
||||
queryResults map[string]tdengineQueryResult
|
||||
}
|
||||
|
||||
func (s *tdengineRecordingState) snapshotQueries() []string {
|
||||
@@ -37,6 +40,12 @@ func (s *tdengineRecordingState) snapshotQueries() []string {
|
||||
return queries
|
||||
}
|
||||
|
||||
type tdengineQueryResult struct {
|
||||
columns []string
|
||||
rows [][]driver.Value
|
||||
err error
|
||||
}
|
||||
|
||||
type tdengineRecordingDriver struct{}
|
||||
|
||||
func (tdengineRecordingDriver) Open(name string) (driver.Conn, error) {
|
||||
@@ -78,6 +87,50 @@ func (c *tdengineRecordingConn) ExecContext(_ context.Context, query string, arg
|
||||
|
||||
var _ driver.ExecerContext = (*tdengineRecordingConn)(nil)
|
||||
|
||||
func (c *tdengineRecordingConn) QueryContext(_ context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
||||
if len(args) > 0 {
|
||||
return nil, fmt.Errorf("unexpected query args: %d", len(args))
|
||||
}
|
||||
c.state.mu.Lock()
|
||||
defer c.state.mu.Unlock()
|
||||
c.state.queries = append(c.state.queries, query)
|
||||
if result, ok := c.state.queryResults[query]; ok {
|
||||
if result.err != nil {
|
||||
return nil, result.err
|
||||
}
|
||||
return &tdengineRecordingRows{columns: result.columns, rows: result.rows}, nil
|
||||
}
|
||||
return &tdengineRecordingRows{}, nil
|
||||
}
|
||||
|
||||
var _ driver.QueryerContext = (*tdengineRecordingConn)(nil)
|
||||
|
||||
type tdengineRecordingRows struct {
|
||||
columns []string
|
||||
rows [][]driver.Value
|
||||
index int
|
||||
}
|
||||
|
||||
func (r *tdengineRecordingRows) Columns() []string {
|
||||
return append([]string(nil), r.columns...)
|
||||
}
|
||||
|
||||
func (r *tdengineRecordingRows) Close() error { return nil }
|
||||
|
||||
func (r *tdengineRecordingRows) Next(dest []driver.Value) error {
|
||||
if r.index >= len(r.rows) {
|
||||
return io.EOF
|
||||
}
|
||||
row := r.rows[r.index]
|
||||
for idx := range dest {
|
||||
if idx < len(row) {
|
||||
dest[idx] = row[idx]
|
||||
}
|
||||
}
|
||||
r.index++
|
||||
return nil
|
||||
}
|
||||
|
||||
func openTDengineRecordingDB(t *testing.T) (*sql.DB, *tdengineRecordingState) {
|
||||
t.Helper()
|
||||
registerTDengineRecordingDriverOnce.Do(func() {
|
||||
@@ -87,7 +140,7 @@ func openTDengineRecordingDB(t *testing.T) (*sql.DB, *tdengineRecordingState) {
|
||||
tdengineRecordingDriverMu.Lock()
|
||||
tdengineRecordingDriverSeq++
|
||||
dsn := fmt.Sprintf("tdengine-recording-%d", tdengineRecordingDriverSeq)
|
||||
state := &tdengineRecordingState{}
|
||||
state := &tdengineRecordingState{queryResults: map[string]tdengineQueryResult{}}
|
||||
tdengineRecordingDriverStates[dsn] = state
|
||||
tdengineRecordingDriverMu.Unlock()
|
||||
|
||||
@@ -166,3 +219,35 @@ func TestTDengineApplyChanges_RejectsMixedUpdatesWithoutPartialWrite(t *testing.
|
||||
t.Fatalf("期望拒绝 mixed changes 时不执行任何 SQL,实际=%#v", queries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTDengineGetTablesIncludesSuperTables(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dbConn, state := openTDengineRecordingDB(t)
|
||||
state.mu.Lock()
|
||||
state.queryResults["SHOW TABLES FROM `metrics`"] = tdengineQueryResult{
|
||||
columns: []string{"name"},
|
||||
rows: [][]driver.Value{
|
||||
{"d001"},
|
||||
{"d002"},
|
||||
},
|
||||
}
|
||||
state.queryResults["SHOW STABLES FROM `metrics`"] = tdengineQueryResult{
|
||||
columns: []string{"name"},
|
||||
rows: [][]driver.Value{
|
||||
{"meters"},
|
||||
},
|
||||
}
|
||||
state.mu.Unlock()
|
||||
|
||||
td := &TDengineDB{conn: dbConn}
|
||||
tables, err := td.GetTables("metrics")
|
||||
if err != nil {
|
||||
t.Fatalf("GetTables returned error: %v", err)
|
||||
}
|
||||
|
||||
want := []string{"d001", "d002", "meters"}
|
||||
if !reflect.DeepEqual(tables, want) {
|
||||
t.Fatalf("unexpected tables: got=%v want=%v", tables, want)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,13 +202,17 @@ func (t *TDengineDB) GetDatabases() ([]string, error) {
|
||||
}
|
||||
|
||||
func (t *TDengineDB) GetTables(dbName string) ([]string, error) {
|
||||
queries := make([]string, 0, 2)
|
||||
queries := make([]string, 0, 4)
|
||||
if strings.TrimSpace(dbName) != "" {
|
||||
queries = append(queries, fmt.Sprintf("SHOW TABLES FROM `%s`", escapeBacktickIdent(dbName)))
|
||||
queries = append(queries, fmt.Sprintf("SHOW STABLES FROM `%s`", escapeBacktickIdent(dbName)))
|
||||
}
|
||||
queries = append(queries, "SHOW TABLES")
|
||||
queries = append(queries, "SHOW STABLES")
|
||||
|
||||
var lastErr error
|
||||
tableSet := make(map[string]struct{})
|
||||
tables := make([]string, 0)
|
||||
for _, query := range queries {
|
||||
data, _, err := t.Query(query)
|
||||
if err != nil {
|
||||
@@ -216,17 +220,35 @@ func (t *TDengineDB) GetTables(dbName string) ([]string, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
var tables []string
|
||||
for _, row := range data {
|
||||
if val, ok := getValueFromRow(row, "table_name", "tablename", "name", "Table", "table"); ok {
|
||||
tables = append(tables, fmt.Sprintf("%v", val))
|
||||
tableName := strings.TrimSpace(fmt.Sprintf("%v", val))
|
||||
if tableName == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := tableSet[tableName]; exists {
|
||||
continue
|
||||
}
|
||||
tableSet[tableName] = struct{}{}
|
||||
tables = append(tables, tableName)
|
||||
continue
|
||||
}
|
||||
for _, val := range row {
|
||||
tables = append(tables, fmt.Sprintf("%v", val))
|
||||
tableName := strings.TrimSpace(fmt.Sprintf("%v", val))
|
||||
if tableName == "" {
|
||||
break
|
||||
}
|
||||
if _, exists := tableSet[tableName]; exists {
|
||||
break
|
||||
}
|
||||
tableSet[tableName] = struct{}{}
|
||||
tables = append(tables, tableName)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(tables) > 0 {
|
||||
sort.Strings(tables)
|
||||
return tables, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user