cache

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 16, 2024 License: MIT Imports: 9 Imported by: 1

README

Datasource Cache

build workflow codecov go-report PkgGoDev

Installation

go get github.com/skynet2/datasource-cache

Quickstart

package main

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"github.com/rs/zerolog"
	cache "github.com/skynet2/datasource-cache"
	"strings"
)

func main() {
	redisClient := redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})

	redisCacheProvider := cache.NewRedisCache[TranslatedEntity, string](
		redisClient)

	cacheManager := cache.NewCacheBuilder[TranslatedEntity, string](
		ModelVersion, redisCacheProvider).Build()

	tr := &translateService{cacheManager: cacheManager, dbRepo: &dbRepo{}}

	tr.GetTranslation(context.TODO(), "en", []string{"web:data1", "web:data2", "web:data3"})
}

const ModelVersion = uint16(1)

type dbRepo struct {
}

func (d *dbRepo) GetTokens(ctx context.Context, tokens []string) (map[string]map[string]string, error) {
	// retrieve data from db or any other source
    // for example if we requested 10 tokens, but 8 was in cache, here we`ll have only 2 tokens to request
	return map[string]map[string]string{}, nil
}

type TranslationToken struct {
	TokenKey     string
	Translations map[string]string
}

type TranslatedEntity struct {
	Value        string
	ModelVersion uint16
}

func (t TranslatedEntity) GetCacheModelVersion() uint16 {
	return t.ModelVersion
}

type translateService struct {
	cacheManager *cache.Cache[TranslatedEntity, string]
	dbRepo       *dbRepo
}

func (t *translateService) GetTranslation(
	ctx context.Context,
	language string,
	inputTokens []string,
) (map[string]string, error) {
	cacheTokens := make([]*cache.Key[string], 0)

	for _, token := range inputTokens {
		tok := strings.ToLower(token)

		cacheTokens = append(cacheTokens, &cache.Key[string]{
			OriginalValue: tok,                                 // here it will be as web:data1
			Key:           fmt.Sprintf("%v:%v", language, tok), // en:web:data1
		})
	}

	result, err := t.cacheManager.MGet(ctx, cacheTokens, func(ctx context.Context, keys []*cache.Key[string]) (map[*cache.Key[string]]*TranslatedEntity, error) {
		translations := make(map[*cache.Key[string]]*TranslatedEntity)
		missingTranslations := make(map[string]TranslationToken)

		toRequest := make([]string, 0, len(keys))
		reverseMap := map[string]*cache.Key[string]{}

		for _, k := range keys {
			toRequest = append(toRequest, k.OriginalValue)
			reverseMap[k.OriginalValue] = k
		}

		foundDbTokens, err := t.dbRepo.GetTokens(ctx, toRequest)

		if err != nil {
			return nil, err
		}

		for _, key := range toRequest {
			v, ok := reverseMap[key]

			if !ok {
				zerolog.Ctx(ctx).Warn().Msgf("not found in reverse map key %v", key)
				continue
			}

			if dbKey, ok := foundDbTokens[key]; ok {
				translations[v] = &TranslatedEntity{
					Value:        dbKey["default"], // find proper value
					ModelVersion: ModelVersion,
				}
			} else {
				translations[v] = &TranslatedEntity{
					ModelVersion: ModelVersion,
					Value:        key,
				}
				missingTranslations[key] = TranslationToken{
					TokenKey: key,
					Translations: map[string]string{
						"en": strings.ToLower(key),
					},
				}
			}
		}

		return translations, nil
	})

	if err != nil {
		return nil, err
	}

	final := make(map[string]string)

	for k, v := range result {
		final[k.OriginalValue] = v.Value
	}

	return final, nil
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Builder

type Builder[T, V any] struct {
	// contains filtered or unexported fields
}

func NewCacheBuilder

func NewCacheBuilder[T Entity, V any](
	modelVersion uint16,
	providers ...Provider[T, V],
) *Builder[T, V]

func (*Builder[T, V]) Build

func (b *Builder[T, V]) Build() *Cache[T, V]

func (*Builder[T, V]) WithTtl

func (b *Builder[T, V]) WithTtl(ttl time.Duration) *Builder[T, V]

type Cache

type Cache[T any, V any] struct {
	// contains filtered or unexported fields
}

func (*Cache[T, V]) Get

func (c *Cache[T, V]) Get(ctx context.Context, key *Key[V], fn GetSingleFromSourceFn[T, V]) (*T, error)

func (*Cache[T, V]) MGet

func (c *Cache[T, V]) MGet(ctx context.Context, keys []*Key[V], fn GetFromSourceFn[T, V]) (map[*Key[V]]*T, error)

func (*Cache[T, V]) MSet

func (c *Cache[T, V]) MSet(ctx context.Context, records map[string]*T) error

type Entity

type Entity interface {
	GetCacheModelVersion() uint16
}

type GetFromSourceFn

type GetFromSourceFn[T, V any] func(ctx context.Context, key []*Key[V]) (map[*Key[V]]*T, error)

type GetSingleFromSourceFn

type GetSingleFromSourceFn[T, V any] func(ctx context.Context, key *Key[V]) (*T, error)

type Key

type Key[V any] struct {
	Key           string
	OriginalValue V
}

type Provider

type Provider[T, V any] interface {
	Get(ctx context.Context, key *Key[V], requiredModelVersion uint16) (*T, error)
	MGet(ctx context.Context, keys []*Key[V], requiredModelVersion uint16) (map[*Key[V]]*T, []*Key[V], error)
	MSet(ctx context.Context, values map[string]*T, ttl time.Duration) error
}

func NewRedisCache

func NewRedisCache[T Entity, V any](
	client redis.Cmdable,
) Provider[T, V]

type RedisCache

type RedisCache[T Entity, V any] struct {
	// contains filtered or unexported fields
}

func (*RedisCache[T, V]) Get

func (r *RedisCache[T, V]) Get(ctx context.Context, key *Key[V], requiredModelVersion uint16) (*T, error)

func (*RedisCache[T, V]) MGet

func (r *RedisCache[T, V]) MGet(ctx context.Context, keys []*Key[V], requiredModelVersion uint16) (map[*Key[V]]*T, []*Key[V], error)

func (*RedisCache[T, V]) MSet

func (r *RedisCache[T, V]) MSet(ctx context.Context, values map[string]*T, ttl time.Duration) error

Directories

Path Synopsis
example
simple Module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL