tercul-backend/internal/platform/cache/cache.go
google-labs-jules[bot] 53aa4d0344
Security Hardening and GraphQL Caching (#69)
* feat: add security middleware, graphql apq, and improved linting

- Add RateLimit, RequestValidation, and CORS middleware.
- Configure middleware chain in API server.
- Implement Redis cache for GraphQL Automatic Persisted Queries.
- Add .golangci.yml and fix linting issues (shadowing, timeouts).

* feat: security, caching and linting config

- Fix .golangci.yml config for govet shadow check
- (Previous changes: Security middleware, GraphQL APQ, Linting fixes)

* fix: resolve remaining lint errors

- Fix unhandled errors in tests (errcheck)
- Define constants for repeated strings (goconst)
- Suppress high complexity warnings with nolint:gocyclo
- Fix integer overflow warnings (gosec)
- Add package comments
- Split long lines (lll)
- Rename Analyse -> Analyze (misspell)
- Fix naked returns and unused params

---------

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
2025-12-01 00:14:22 +01:00

93 lines
2.7 KiB
Go

package cache
import (
"context"
"encoding/json"
"fmt"
"time"
)
// Cache defines the interface for caching operations
type Cache interface {
// Get retrieves a value from the cache
Get(ctx context.Context, key string, value interface{}) error
// Set stores a value in the cache with an optional expiration
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error
// Delete removes a value from the cache
Delete(ctx context.Context, key string) error
// Clear removes all values from the cache
Clear(ctx context.Context) error
// GetMulti retrieves multiple values from the cache
GetMulti(ctx context.Context, keys []string) (map[string][]byte, error)
// SetMulti stores multiple values in the cache with an optional expiration
SetMulti(ctx context.Context, items map[string]interface{}, expiration time.Duration) error
}
// Item represents a cache item with metadata
type Item struct {
Key string
Value interface{}
Expiration time.Duration
}
// MarshalBinary implements the encoding.BinaryMarshaler interface
func (i *Item) MarshalBinary() ([]byte, error) {
return json.Marshal(i.Value)
}
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
func (i *Item) UnmarshalBinary(data []byte) error {
return json.Unmarshal(data, &i.Value)
}
// KeyGenerator generates cache keys for different types of data
type KeyGenerator interface {
// EntityKey generates a key for an entity by ID
EntityKey(entityType string, id uint) string
// ListKey generates a key for a list of entities
ListKey(entityType string, page, pageSize int) string
// QueryKey generates a key for a custom query
QueryKey(entityType, queryName string, params ...interface{}) string
}
// DefaultKeyGenerator implements the KeyGenerator interface
type DefaultKeyGenerator struct {
Prefix string
}
// NewDefaultKeyGenerator creates a new DefaultKeyGenerator
func NewDefaultKeyGenerator(prefix string) *DefaultKeyGenerator {
if prefix == "" {
prefix = "tercul:"
}
return &DefaultKeyGenerator{
Prefix: prefix,
}
}
// EntityKey generates a key for an entity by ID
func (g *DefaultKeyGenerator) EntityKey(entityType string, id uint) string {
return g.Prefix + entityType + ":id:" + fmt.Sprintf("%d", id)
}
// ListKey generates a key for a list of entities
func (g *DefaultKeyGenerator) ListKey(entityType string, page, pageSize int) string {
return g.Prefix + entityType + ":list:" + fmt.Sprintf("%d:%d", page, pageSize)
}
// QueryKey generates a key for a custom query
func (g *DefaultKeyGenerator) QueryKey(entityType, queryName string, params ...interface{}) string {
key := g.Prefix + entityType + ":" + queryName
for _, param := range params {
key += ":" + fmt.Sprintf("%v", param)
}
return key
}