Files
MyGoNavi/internal/sync/sync_context.go
Syngnat c91a1555a4 feat(sync): 完善跨数据源迁移与增量同步内核
- 增加迁移能力矩阵、对象字段映射与安全预检守卫
- 支持批大小、行错误隔离、水位增量和变更事件重放
- 复用 CDC 目标会话并补齐分页、投影与增量同步测试
2026-08-08 19:06:12 +08:00

132 lines
3.4 KiB
Go

package sync
import (
"GoNavi-Wails/internal/connection"
"GoNavi-Wails/internal/db"
"context"
"fmt"
"strings"
)
type syncDriverContextKey struct{}
// markSyncDriverContext keeps RunSync's historical Query/Exec dispatch intact
// while allowing callers that explicitly choose RunSyncContext to opt in to
// the optional context-aware driver methods. This matters for compatibility
// with wrappers that override Query/Exec but inherit unrelated context methods.
func markSyncDriverContext(ctx context.Context) context.Context {
if ctx == nil {
ctx = context.Background()
}
return context.WithValue(ctx, syncDriverContextKey{}, true)
}
func syncDriverContextEnabled(ctx context.Context) bool {
enabled, _ := ctx.Value(syncDriverContextKey{}).(bool)
return enabled
}
type syncQueryContexter interface {
QueryContext(context.Context, string) ([]map[string]interface{}, []string, error)
}
type syncExecContexter interface {
ExecContext(context.Context, string) (int64, error)
}
type syncBatchApplyContexter interface {
ApplyChangesContext(context.Context, string, connection.ChangeSet) error
}
func (s *SyncEngine) context() context.Context {
if s == nil || s.ctx == nil {
return context.Background()
}
return s.ctx
}
func (s *SyncEngine) contextError() error {
return s.context().Err()
}
func querySyncDatabaseContext(ctx context.Context, database db.Database, query string) ([]map[string]interface{}, []string, error) {
if ctx == nil {
ctx = context.Background()
}
if err := ctx.Err(); err != nil {
return nil, nil, err
}
if syncDriverContextEnabled(ctx) {
if contextDatabase, ok := database.(syncQueryContexter); ok {
return contextDatabase.QueryContext(ctx, query)
}
}
rows, columns, err := database.Query(query)
if err != nil {
return rows, columns, err
}
if contextErr := ctx.Err(); contextErr != nil {
return nil, nil, contextErr
}
return rows, columns, nil
}
func execSyncDatabaseContext(ctx context.Context, database db.Database, query string) (int64, error) {
if ctx == nil {
ctx = context.Background()
}
if err := ctx.Err(); err != nil {
return 0, err
}
if syncDriverContextEnabled(ctx) {
if contextDatabase, ok := database.(syncExecContexter); ok {
return contextDatabase.ExecContext(ctx, query)
}
}
affected, err := database.Exec(query)
if err != nil {
return affected, err
}
if contextErr := ctx.Err(); contextErr != nil {
return affected, contextErr
}
return affected, nil
}
func applySyncChangesContext(ctx context.Context, applier db.BatchApplier, tableName string, changes connection.ChangeSet) error {
if ctx == nil {
ctx = context.Background()
}
if err := ctx.Err(); err != nil {
return err
}
if syncDriverContextEnabled(ctx) {
if contextApplier, ok := applier.(syncBatchApplyContexter); ok {
return contextApplier.ApplyChangesContext(ctx, tableName, changes)
}
}
if err := applier.ApplyChanges(tableName, changes); err != nil {
return err
}
return ctx.Err()
}
func executeSyncSQLStatementsContext(ctx context.Context, database db.Database, statements []string) error {
if ctx == nil {
ctx = context.Background()
}
for _, statement := range statements {
statement = strings.TrimSpace(statement)
if statement == "" {
continue
}
if err := ctx.Err(); err != nil {
return err
}
if _, err := execSyncDatabaseContext(ctx, database, statement); err != nil {
return fmt.Errorf("执行 SQL 失败:%s: %w", statement, err)
}
}
return nil
}