scache

package module
v0.0.0-...-037b08c Latest Latest
Warning

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

Go to latest
Published: Mar 24, 2024 License: MIT Imports: 11 Imported by: 0

README

scache

A cache layer on top of ORM layer

Installation

go get github.com/daqiancode/scache
#for gorm
go get github.com/daqiancode/scache/gormredis
#for mongodb
go get github.com/daqiancode/scache/mongoredis

Idea

2 Types of Cache
  1. Partial cache: load record on demands
  2. Full cache: always load full data from database to cache
Action
  1. Get,List,GetBy,List will use cache(fetch from db if miss)
  2. Create,Delete,Update,Save will clear the cache
2 type Cache content with redis
  1. primary key -> obj, Get,List will use primary redis key, eg. Get: commodity/id/1 -> {id:3,name:"apply",category:1}
  2. index key -> primary keys. eg.ListBy user/category/1 ->[3,4]
Clear cache logic
  1. Get related objects,eg. update(id,v), related objs is old record and new record after updated,[old,new]
  2. Clear cache with id and index rediskey of related objs, clearCache([old,new])

Support

  1. Gorm, including MySQL, PostgreSQL, SQLite, SQL Server
  2. Mongo

Example

import (
	"fmt"
	"log"
	"os"
	"testing"
	"time"

	"github.com/daqiancode/scache"
	"github.com/daqiancode/scache/gormredis"
	"github.com/redis/go-redis/v9"
	"github.com/stretchr/testify/assert"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func GetDBClient() *gorm.DB {
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             time.Second, // Slow SQL threshold
			LogLevel:                  logger.Info, // Log level
			IgnoreErrRecordNotFoundError: true,        // Ignore ErrErrRecordNotFound error for logger
			Colorful:                  false,       // Disable color
		},
	)
	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN: "root:123456@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local",
	}), &gorm.Config{Logger: newLogger})
	if err != nil {
		panic(err)
	}
	return db
}

func getRedisClient() *redis.Client {
	return redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
	})
}

type Commodity struct {
	Id       string
	Name     string
	Category int
}

func (s Commodity) GetID() string {
	return s.Id
}
func (s Commodity) ListIndexes() scache.Indexes {
	return scache.Indexes{}.Add(scache.Index{}.Add("Category", s.Category))
}
func createCache() scache.Cache[Commodity, string] {
	return gormredis.NewGormRedis[Commodity, string]("app", "commodity", "Id", GetDBClient(), getRedisClient(), 10*time.Second)

}
func createCacheFull() *scache.FullRedisCache[Commodity, string] {
	return gormredis.NewGormRedisFull[Commodity, string]("app", "commodity", "Id", GetDBClient(), getRedisClient(), 10*time.Second)

}
func TestGormRedisMain(t *testing.T) {
	id := "1"
	ca := createCache()
	_, err := ca.Delete(id)
	assert.Nil(t, err)
	c, exists, err := ca.Get(id)
	assert.Nil(t, err)
	fmt.Println(exists)
	assert.False(t, exists)
	assert.Equal(t, c.Id, "")
	d := Commodity{Id: id, Name: "tom", Category: 1}
	err = ca.Create(&d)
	assert.Nil(t, err)
	r1, exists, err := ca.GetBy(scache.NewIndex("category", 1))
	assert.Nil(t, err)
	assert.True(t, exists)
	assert.Equal(t, id, r1.Id)
	r2, exists, err := ca.GetBy(scache.NewIndex("category", 100))
	assert.Nil(t, err)
	assert.False(t, exists)
	assert.Equal(t, "", r2.Id)
	r3, err := ca.ListBy(scache.NewIndex("category", 100), nil)
	assert.Nil(t, err)
	assert.Equal(t, 0, len(r3))
	r4, err := ca.List("1", "100")
	assert.Nil(t, err)
	assert.Equal(t, 2, len(r4))
	assert.Equal(t, id, r4[0].Id)
}


Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrRecordNotFound = errors.New("record not exist")
View Source
var RdisOpTimeout = 30 * time.Second

Functions

func IsNullID

func IsNullID[I IDType](id I) bool

func Stringify

func Stringify(value interface{}, null string) string

func StringifyAtom

func StringifyAtom(value interface{}) string

func UniqueStrings

func UniqueStrings(strs []string) []string

Types

type Cache

type Cache[T Table[I], I IDType] interface {
	DBCRUD[T, I]
	//clear cache for objs
	ClearCache(objs ...T) error

	SetCacheKeyPrefix(prefix string)
	GetCacheKeyPrefix() string
	MakeCacheKey(index Index) string
	SetTableName(table string)
	GetTableName() string
	SetIdField(idField string)
	GetIdField() string
}

Cache 1. Primary key cache: eg. {table}/id/{id} -> record 2.1 Index cache: eg1. {table}/uid/{uid}-> [id1,id2] 2.2 Index cache: eg2. {table}/uid/{uid}/type/{type} -> [id1] 3. Index cache clear cache process, on index change 1. given indexes, 2. find related index cache keys,3. delete

type CacheBase

type CacheBase[T Table[I], I IDType] struct {
	// contains filtered or unexported fields
}

func NewCacheBase

func NewCacheBase[T Table[I], I IDType](prefix, table, idField string) *CacheBase[T, I]

func (*CacheBase[T, I]) Close

func (s *CacheBase[T, I]) Close() error

func (*CacheBase[T, I]) GetCacheKeyPrefix

func (s *CacheBase[T, I]) GetCacheKeyPrefix() string

func (*CacheBase[T, I]) GetIdField

func (s *CacheBase[T, I]) GetIdField() string

func (*CacheBase[T, I]) GetTableName

func (s *CacheBase[T, I]) GetTableName() string

func (*CacheBase[T, I]) MakeCacheKey

func (s *CacheBase[T, I]) MakeCacheKey(index Index) string

func (*CacheBase[T, I]) SetCacheKeyPrefix

func (s *CacheBase[T, I]) SetCacheKeyPrefix(prefix string)
func (s *CacheBase[T, I]) SetSerializer(serializer Serializer) {
	s.serializer = serializer
}
func (s *CacheBase[T, I]) GetSerializer() Serializer {
	return s.serializer
}

func (*CacheBase[T, I]) SetIdField

func (s *CacheBase[T, I]) SetIdField(idField string)

func (*CacheBase[T, I]) SetTableName

func (s *CacheBase[T, I]) SetTableName(table string)

type DBCRUD

type DBCRUD[T Table[I], I IDType] interface {
	//Creat create new record into dababase
	Create(obj *T) error
	//Save update if id exists or create new record
	Save(obj *T) error
	//Delete return (effectedrows,error)
	Delete(ids ...I) (int64, error)
	// values can be struct or map[string]interface{}, return (effectedrows,error)
	Update(id I, values interface{}) (int64, error)
	//get obj by id
	Get(id I) (T, error)
	//list objs by ids
	List(ids ...I) ([]T, error)
	//get obj by index
	GetBy(index Index) (T, error)
	//list objs by indexes
	ListBy(index Index, initOrders OrderBys) ([]T, error)
	//close lower clients
	Close() error
	//ListByUniqueInts list objs by unique index field in values
	ListByUniqueInts(field string, values []int64) ([]T, error)
	//ListByUniqueStrs list objs by unique index field in values
	ListByUniqueStrs(field string, values []string) ([]T, error)
}

type FullCache

type FullCache[T Table[I], I IDType] interface {
	DBCRUD[T, I]
	ClearCache(objs ...T) error

	// //get obj by id
	// Get(id I) (T, bool, error)
	// //list objs by ids
	// List(ids ...I) ([]T, error)
	// //get obj by index
	// GetBy(index Index) (T, bool, error)
	// //list objs by indexes
	// ListBy(index Index, orderBys OrderBys) ([]T, error)
	//list all objs from db
	ListAll() ([]T, error)

	//close lower clients
	Close() error

	//for extending
	// SetCtx(ctx context.Context)
	// GetCtx() context.Context
	SetCacheKeyPrefix(prefix string)
	GetCacheKeyPrefix() string
	MakeCacheKey(index Index) string
	SetTableName(table string)
	GetTableName() string
	SetIdField(idField string)
	GetIdField() string
}

type FullDBCache

type FullDBCache[T Table[I], I IDType] interface {
	DBCRUD[T, I]
	// Create(r *T) error
	// Save(r *T) error
	// Update(id I, values interface{}) (int64, error)
	// Delete(ids ...I) (int64, error)
	// Get(id I) (T, bool, error)
	// List(ids ...I) ([]T, error)
	ListAll() ([]T, error)
}

type FullRedisCache

type FullRedisCache[T Table[I], I IDType] struct {
	*CacheBase[T, I]
	// contains filtered or unexported fields
}

func NewFullRedisCache

func NewFullRedisCache[T Table[I], I IDType](prefix, table, idField string, db FullDBCache[T, I], red *redis.Client, ttl time.Duration) *FullRedisCache[T, I]

func (*FullRedisCache[T, I]) CacheKey

func (s *FullRedisCache[T, I]) CacheKey() string

func (*FullRedisCache[T, I]) ClearCache

func (s *FullRedisCache[T, I]) ClearCache(objs ...T) error

func (*FullRedisCache[T, I]) Create

func (s *FullRedisCache[T, I]) Create(r *T) error

func (*FullRedisCache[T, I]) Delete

func (s *FullRedisCache[T, I]) Delete(ids ...I) (int64, error)

func (*FullRedisCache[T, I]) Get

func (s *FullRedisCache[T, I]) Get(id I) (T, error)

func (*FullRedisCache[T, I]) GetBy

func (s *FullRedisCache[T, I]) GetBy(index Index) (T, error)

func (*FullRedisCache[T, I]) List

func (s *FullRedisCache[T, I]) List(id ...I) ([]T, error)

func (*FullRedisCache[T, I]) ListAll

func (s *FullRedisCache[T, I]) ListAll() ([]T, error)

func (*FullRedisCache[T, I]) ListBy

func (s *FullRedisCache[T, I]) ListBy(index Index, orderBys OrderBys) ([]T, error)

func (*FullRedisCache[T, I]) ListByUniqueInts

func (s *FullRedisCache[T, I]) ListByUniqueInts(field string, values []int64) ([]T, error)

ListIn list objs by index field in values

func (*FullRedisCache[T, I]) ListByUniqueStrs

func (s *FullRedisCache[T, I]) ListByUniqueStrs(field string, values []string) ([]T, error)

ListIn list objs by index field in values

func (*FullRedisCache[T, I]) Load

func (s *FullRedisCache[T, I]) Load() error

func (*FullRedisCache[T, I]) Save

func (s *FullRedisCache[T, I]) Save(r *T) error

func (*FullRedisCache[T, I]) Update

func (s *FullRedisCache[T, I]) Update(id I, values interface{}) (int64, error)

type IDInt

type IDInt interface {
	~int | ~int16 | ~int32 | ~int64 | ~uint | ~uint16 | ~uint32 | ~uint64
}

type IDType

type IDType interface {
	IDInt | ~string
}

type Index

type Index map[string]interface{}

func NewIndex

func NewIndex(field string, value interface{}) Index

func (Index) Add

func (s Index) Add(field string, value interface{}) Index

func (Index) Fields

func (s Index) Fields() []string

type Indexes

type Indexes []Index

func (Indexes) Add

func (s Indexes) Add(index Index) Indexes

func (Indexes) Merge

func (s Indexes) Merge(indexes Indexes) Indexes

type JsonSerializer

type JsonSerializer struct {
}

func (*JsonSerializer) Marshal

func (s *JsonSerializer) Marshal(obj interface{}) (string, error)

func (*JsonSerializer) Unmarshal

func (s *JsonSerializer) Unmarshal(data string, objRef interface{}) error

type OrderBy

type OrderBy struct {
	Field string
	Asc   bool
}

func (OrderBy) String

func (s OrderBy) String() string

type OrderBys

type OrderBys []OrderBy

type Indexes []Index

func NewOrderBys

func NewOrderBys(field string, asc bool) OrderBys

func (OrderBys) Add

func (s OrderBys) Add(field string, asc bool) OrderBys

func (OrderBys) String

func (s OrderBys) String() string

type RedisCache

type RedisCache[T Table[I], I IDType] struct {
	*CacheBase[T, I]
	// contains filtered or unexported fields
}

func NewRedisCache

func NewRedisCache[T Table[I], I IDType](prefix, table, idField string, db DBCRUD[T, I], red *redis.Client, ttl time.Duration) *RedisCache[T, I]

func (*RedisCache[T, I]) ClearCache

func (s *RedisCache[T, I]) ClearCache(objs ...T) error

func (*RedisCache[T, I]) Close

func (s *RedisCache[T, I]) Close() error

func (*RedisCache[T, I]) Create

func (s *RedisCache[T, I]) Create(obj *T) error

func (*RedisCache[T, I]) Delete

func (s *RedisCache[T, I]) Delete(ids ...I) (int64, error)

func (*RedisCache[T, I]) Get

func (s *RedisCache[T, I]) Get(id I) (T, error)

func (*RedisCache[T, I]) GetBy

func (s *RedisCache[T, I]) GetBy(index Index) (T, error)

func (*RedisCache[T, I]) GetDB

func (s *RedisCache[T, I]) GetDB() DBCRUD[T, I]

func (*RedisCache[T, I]) List

func (s *RedisCache[T, I]) List(ids ...I) ([]T, error)

List list records by ids, order & empty records keeped

func (*RedisCache[T, I]) ListBy

func (s *RedisCache[T, I]) ListBy(index Index, orderBys OrderBys) ([]T, error)

func (*RedisCache[T, I]) ListByUniqueInts

func (s *RedisCache[T, I]) ListByUniqueInts(field string, values []int64) ([]T, error)

ListIn list objs by index field in values

func (*RedisCache[T, I]) ListByUniqueStrs

func (s *RedisCache[T, I]) ListByUniqueStrs(field string, values []string) ([]T, error)

ListIn list objs by index field in values

func (*RedisCache[T, I]) Save

func (s *RedisCache[T, I]) Save(obj *T) error

func (*RedisCache[T, I]) Update

func (s *RedisCache[T, I]) Update(id I, values interface{}) (int64, error)

Update values can be struct or map[string]interface{}

type RedisHashJson

type RedisHashJson[T Table[I], I IDType] struct {
	*RedisJson[T]
	*redis.Client
	// contains filtered or unexported fields
}

func NewRedisHashJson

func NewRedisHashJson[T Table[I], I IDType](client *redis.Client, ttl time.Duration) *RedisHashJson[T, I]

func (*RedisHashJson[T, I]) HDelJson

func (s *RedisHashJson[T, I]) HDelJson(key string, ids ...I) error

func (*RedisHashJson[T, I]) HGetAllJson

func (s *RedisHashJson[T, I]) HGetAllJson(key string) ([]T, error)

func (*RedisHashJson[T, I]) HGetJson

func (s *RedisHashJson[T, I]) HGetJson(key string, id I) (T, error)

func (*RedisHashJson[T, I]) HMGetJson

func (s *RedisHashJson[T, I]) HMGetJson(key string, ids ...I) ([]T, error)

func (*RedisHashJson[T, I]) HSetJson

func (s *RedisHashJson[T, I]) HSetJson(key string, objs ...T) error

type RedisJson

type RedisJson[T any] struct {
	*redis.Client
	// contains filtered or unexported fields
}

func NewRedisJson

func NewRedisJson[T any](client *redis.Client, ttl time.Duration) *RedisJson[T]

func (*RedisJson[T]) Expires

func (s *RedisJson[T]) Expires(keys ...string) error

func (*RedisJson[T]) GetJson

func (s *RedisJson[T]) GetJson(key string) (T, error)

func (*RedisJson[T]) MGetJson

func (s *RedisJson[T]) MGetJson(keys []string) ([]T, []int, error)

func (*RedisJson[T]) MSetJson

func (s *RedisJson[T]) MSetJson(objMap map[string]interface{}) error

func (*RedisJson[T]) MSetNull

func (s *RedisJson[T]) MSetNull(keys []string) error

func (*RedisJson[T]) SetJson

func (s *RedisJson[T]) SetJson(key string, obj T) error

func (*RedisJson[T]) SetNull

func (s *RedisJson[T]) SetNull(key string) error

type Serializer

type Serializer interface {
	Marshal(obj interface{}) (string, error)
	Unmarshal(data string, objRef interface{}) error
}

type Table

type Table[I IDType] interface {
	//GetID return id field name & id value
	GetID() I
	ListIndexes() Indexes
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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