package utils import ( "fmt" "log" "strings" "sync" ) // SchemaMismatch represents a mismatch between expected and actual API response type SchemaMismatch struct { ModelName string MissingFields []string UnknownFields []string UnknownValues map[string]any Endpoint string LibraryVersion string } func (sm *SchemaMismatch) Describe() string { var parts []string parts = append(parts, fmt.Sprintf("Model: %s", sm.ModelName)) if len(sm.MissingFields) > 0 { parts = append(parts, fmt.Sprintf("Missing fields: %v", sm.MissingFields)) } if len(sm.UnknownFields) > 0 { parts = append(parts, fmt.Sprintf("Unknown fields: %v", sm.UnknownFields)) } if len(sm.UnknownValues) > 0 { parts = append(parts, fmt.Sprintf("Unknown field structures: %v", sm.UnknownValues)) } parts = append(parts, fmt.Sprintf("Endpoint: %s", sm.Endpoint)) parts = append(parts, fmt.Sprintf("Library version: %s", sm.LibraryVersion)) return strings.Join(parts, "\n") } // SchemaMismatchHandler is a callback for handling schema mismatches type SchemaMismatchHandler func(*SchemaMismatch) // SchemaMismatchConfig holds configuration for schema mismatch handling type SchemaMismatchConfig struct { ReportUnknownFields bool Strict bool OnSchemaMismatch SchemaMismatchHandler } // DefaultSchemaMismatchConfig returns the default configuration func DefaultSchemaMismatchConfig() SchemaMismatchConfig { return SchemaMismatchConfig{ ReportUnknownFields: false, Strict: false, OnSchemaMismatch: nil, } } // ReportSchemaMismatch reports a schema mismatch according to config func ReportSchemaMismatch(config SchemaMismatchConfig, modelName, endpoint string, missingFields, unknownFields []string, unknownValues map[string]any) error { mismatch := &SchemaMismatch{ ModelName: modelName, MissingFields: missingFields, UnknownFields: unknownFields, UnknownValues: unknownValues, Endpoint: endpoint, LibraryVersion: "go-port-0.1.0", } if config.OnSchemaMismatch != nil { config.OnSchemaMismatch(mismatch) return nil } msg := mismatch.Describe() if config.Strict { return fmt.Errorf("schema mismatch: %s", msg) } log.Printf("WARNING: Schema mismatch for %s:\n%s", modelName, msg) return nil } // SchemaMismatchTracker tracks reported mismatches to avoid duplicates type SchemaMismatchTracker struct { mu sync.Mutex reported map[string]bool } func NewSchemaMismatchTracker() *SchemaMismatchTracker { return &SchemaMismatchTracker{ reported: make(map[string]bool), } } func (t *SchemaMismatchTracker) ShouldReport(modelName string, fields []string) bool { t.mu.Lock() defer t.mu.Unlock() key := modelName + ":" + strings.Join(fields, ",") if t.reported[key] { return false } t.reported[key] = true return true }