From baf98ca80e56133d594b8b0f079cd7b4214db884 Mon Sep 17 00:00:00 2001 From: ashisgreat22 Date: Tue, 24 Mar 2026 01:06:49 +0100 Subject: [PATCH] cache: add QueryHash and CachedEngineResponse type Co-Authored-By: Claude Opus 4.6 --- internal/cache/cache.go | 22 ++++++++++++++++++++++ internal/cache/cache_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 4d25b16..79d3c8b 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -208,3 +208,25 @@ func Key(req contracts.SearchRequest) string { return hex.EncodeToString(h.Sum(nil))[:32] } + +// QueryHash computes a deterministic hash from shared request parameters +// (query, pageno, safesearch, language, time_range) for use as a cache key suffix. +// The hash is a truncated SHA-256 (16 hex chars). +func QueryHash(query string, pageno int, safesearch int, language, timeRange string) string { + h := sha256.New() + fmt.Fprintf(h, "q=%s|", query) + fmt.Fprintf(h, "pageno=%d|", pageno) + fmt.Fprintf(h, "safesearch=%d|", safesearch) + fmt.Fprintf(h, "lang=%s|", language) + if timeRange != "" { + fmt.Fprintf(h, "tr=%s|", timeRange) + } + return hex.EncodeToString(h.Sum(nil))[:16] +} + +// CachedEngineResponse wraps an engine's cached response with metadata. +type CachedEngineResponse struct { + Engine string + Response []byte + StoredAt time.Time +} diff --git a/internal/cache/cache_test.go b/internal/cache/cache_test.go index 3986f0f..6857f05 100644 --- a/internal/cache/cache_test.go +++ b/internal/cache/cache_test.go @@ -75,3 +75,35 @@ func TestNew_NopWithoutAddress(t *testing.T) { } func strPtr(s string) *string { return &s } + +func TestQueryHash(t *testing.T) { + // Same params should produce same hash + hash1 := QueryHash("golang", 1, 0, "en", "") + hash2 := QueryHash("golang", 1, 0, "en", "") + if hash1 != hash2 { + t.Errorf("QueryHash: same params should produce same hash, got %s != %s", hash1, hash2) + } + + // Different query should produce different hash + hash3 := QueryHash("rust", 1, 0, "en", "") + if hash1 == hash3 { + t.Errorf("QueryHash: different queries should produce different hash") + } + + // Different pageno should produce different hash + hash4 := QueryHash("golang", 2, 0, "en", "") + if hash1 == hash4 { + t.Errorf("QueryHash: different pageno should produce different hash") + } + + // time_range should affect hash + hash5 := QueryHash("golang", 1, 0, "en", "day") + if hash1 == hash5 { + t.Errorf("QueryHash: different time_range should produce different hash") + } + + // Hash should be 16 characters (truncated SHA-256) + if len(hash1) != 16 { + t.Errorf("QueryHash: expected 16 char hash, got %d", len(hash1)) + } +}