198 lines
3.7 KiB
Go
198 lines
3.7 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/maypok86/otter"
|
|
"github.com/mikestefanello/pagoda/config"
|
|
)
|
|
|
|
type (
|
|
// CacheClient is the client that allows you to interact with the cache
|
|
CacheClient struct {
|
|
// cache stores the cache interface
|
|
cache *otter.CacheWithVariableTTL[string, any]
|
|
}
|
|
|
|
// cacheSet handles chaining a set operation
|
|
cacheSet struct {
|
|
client *CacheClient
|
|
key string
|
|
group string
|
|
data any
|
|
expiration time.Duration
|
|
tags []string
|
|
}
|
|
|
|
// cacheGet handles chaining a get operation
|
|
cacheGet struct {
|
|
client *CacheClient
|
|
key string
|
|
group string
|
|
}
|
|
|
|
// cacheFlush handles chaining a flush operation
|
|
cacheFlush struct {
|
|
client *CacheClient
|
|
key string
|
|
group string
|
|
tags []string
|
|
}
|
|
)
|
|
|
|
// NewCacheClient creates a new cache client
|
|
func NewCacheClient(cfg *config.Config) (*CacheClient, error) {
|
|
cache, err := otter.MustBuilder[string, any](10000).
|
|
WithVariableTTL().
|
|
DeletionListener(func(key string, value any, cause otter.DeletionCause) {
|
|
// todo
|
|
}).
|
|
Build()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &CacheClient{cache: &cache}, nil
|
|
}
|
|
|
|
// Close closes the connection to the cache
|
|
func (c *CacheClient) Close() {
|
|
c.cache.Close()
|
|
}
|
|
|
|
// Set creates a cache set operation
|
|
func (c *CacheClient) Set() *cacheSet {
|
|
return &cacheSet{
|
|
client: c,
|
|
}
|
|
}
|
|
|
|
// Get creates a cache get operation
|
|
func (c *CacheClient) Get() *cacheGet {
|
|
return &cacheGet{
|
|
client: c,
|
|
}
|
|
}
|
|
|
|
// Flush creates a cache flush operation
|
|
func (c *CacheClient) Flush() *cacheFlush {
|
|
return &cacheFlush{
|
|
client: c,
|
|
}
|
|
}
|
|
|
|
// cacheKey formats a cache key with an optional group
|
|
func (c *CacheClient) cacheKey(group, key string) string {
|
|
if group != "" {
|
|
return fmt.Sprintf("%s::%s", group, key)
|
|
}
|
|
return key
|
|
}
|
|
|
|
// Key sets the cache key
|
|
func (c *cacheSet) Key(key string) *cacheSet {
|
|
c.key = key
|
|
return c
|
|
}
|
|
|
|
// Group sets the cache group
|
|
func (c *cacheSet) Group(group string) *cacheSet {
|
|
c.group = group
|
|
return c
|
|
}
|
|
|
|
// Data sets the data to cache
|
|
func (c *cacheSet) Data(data any) *cacheSet {
|
|
c.data = data
|
|
return c
|
|
}
|
|
|
|
// Expiration sets the expiration duration of the cached data
|
|
func (c *cacheSet) Expiration(expiration time.Duration) *cacheSet {
|
|
c.expiration = expiration
|
|
return c
|
|
}
|
|
|
|
// Tags sets the cache tags
|
|
func (c *cacheSet) Tags(tags ...string) *cacheSet {
|
|
c.tags = tags
|
|
return c
|
|
}
|
|
|
|
// Save saves the data in the cache
|
|
func (c *cacheSet) Save(ctx context.Context) error {
|
|
if c.key == "" {
|
|
return errors.New("no cache key specified")
|
|
}
|
|
|
|
if c.data == nil {
|
|
return errors.New("no cache data specified")
|
|
}
|
|
|
|
c.client.cache.Set(
|
|
c.client.cacheKey(c.group, c.key),
|
|
c.data,
|
|
c.expiration,
|
|
)
|
|
|
|
// TODO tags
|
|
return nil
|
|
}
|
|
|
|
// Key sets the cache key
|
|
func (c *cacheGet) Key(key string) *cacheGet {
|
|
c.key = key
|
|
return c
|
|
}
|
|
|
|
// Group sets the cache group
|
|
func (c *cacheGet) Group(group string) *cacheGet {
|
|
c.group = group
|
|
return c
|
|
}
|
|
|
|
// Fetch fetches the data from the cache
|
|
func (c *cacheGet) Fetch(ctx context.Context) (any, error) {
|
|
if c.key == "" {
|
|
return nil, errors.New("no cache key specified")
|
|
}
|
|
|
|
v, exists := c.client.cache.Get(c.client.cacheKey(c.group, c.key))
|
|
|
|
if !exists {
|
|
return nil, ErrCacheMiss
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
var ErrCacheMiss = errors.New("cache miss")
|
|
|
|
// Key sets the cache key
|
|
func (c *cacheFlush) Key(key string) *cacheFlush {
|
|
c.key = key
|
|
return c
|
|
}
|
|
|
|
// Group sets the cache group
|
|
func (c *cacheFlush) Group(group string) *cacheFlush {
|
|
c.group = group
|
|
return c
|
|
}
|
|
|
|
// Tags sets the cache tags
|
|
func (c *cacheFlush) Tags(tags ...string) *cacheFlush {
|
|
c.tags = tags
|
|
return c
|
|
}
|
|
|
|
// Execute flushes the data from the cache
|
|
func (c *cacheFlush) Execute(ctx context.Context) {
|
|
// TODO tags
|
|
|
|
c.client.cache.Delete(c.client.cacheKey(c.group, c.key))
|
|
}
|