package main import ( "fmt" "sync" ) // TextSearchResult represents a single search result item. type TextSearchResult struct { URL string Header string Description string Source string } // CacheKey represents the key used to store search results in the cache. type CacheKey struct { Query string Page int Safe string Lang string } // ResultsCache is a thread-safe map for caching search results by composite keys. type ResultsCache struct { mu sync.Mutex results map[string][]TextSearchResult } // NewResultsCache creates a new ResultsCache. func NewResultsCache() *ResultsCache { return &ResultsCache{ results: make(map[string][]TextSearchResult), } } // Get retrieves the results for a given key from the cache. func (rc *ResultsCache) Get(key CacheKey) ([]TextSearchResult, bool) { rc.mu.Lock() defer rc.mu.Unlock() results, exists := rc.results[rc.keyToString(key)] return results, exists } // Set stores the results for a given key in the cache. func (rc *ResultsCache) Set(key CacheKey, results []TextSearchResult) { rc.mu.Lock() defer rc.mu.Unlock() rc.results[rc.keyToString(key)] = results } // keyToString converts a CacheKey to a string representation. func (rc *ResultsCache) keyToString(key CacheKey) string { return fmt.Sprintf("%s|%d|%s|%s", key.Query, key.Page, key.Safe, key.Lang) }