This repository has been archived by the owner on Jul 8, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from jamesstocktonj1/feature/look-aside-cache
Adding a Cache Driver
- Loading branch information
Showing
7 changed files
with
1,507 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/* | ||
Package cache provides a Hord database driver for a variety of caching strategies. To use this driver, import it as follows: | ||
import ( | ||
"github.com/madflojo/hord" | ||
"github.com/madflojo/hord/cache" | ||
) | ||
# Connecting to the Database | ||
Use the Dial() function to create a new client for interacting with the cache. | ||
// Handle database connection | ||
var database hord.Database | ||
... | ||
// Handle cache connection | ||
var cache hord.Database | ||
... | ||
var db hord.Database | ||
db, err := cache.Dial(cache.Config{ | ||
Database: database, | ||
Cache: cache, | ||
Type: cache.Lookaside, | ||
}) | ||
if err != nil { | ||
// Handle connection error | ||
} | ||
# Initialize database | ||
Hord provides a Setup() function for preparing a database. This function is safe to execute after every Dial(). | ||
err := db.Setup() | ||
if err != nil { | ||
// Handle setup error | ||
} | ||
# Database Operations | ||
Hord provides a simple abstraction for working with the cache, with easy-to-use methods such as Get() and Set() to read and write values. | ||
// Handle database connection | ||
var database hord.Database | ||
database, err := cassandra.Dial(cassandra.Config{}) | ||
if err != nil { | ||
// Handle connection error | ||
} | ||
// Handle cache connection | ||
var cache hord.Database | ||
cache, err := redis.Dial(redis.Config{}) | ||
if err != nil { | ||
// Handle connection error | ||
} | ||
// Connect to the Cache database | ||
db, err := cache.Dial(cache.Config{ | ||
Database: database, | ||
Cache: cache, | ||
Type: cache.Lookaside, | ||
}) | ||
if err != nil { | ||
// Handle connection error | ||
} | ||
err := db.Setup() | ||
if err != nil { | ||
// Handle setup error | ||
} | ||
// Set a value | ||
err = db.Set("key", []byte("value")) | ||
if err != nil { | ||
// Handle error | ||
} | ||
// Retrieve a value | ||
value, err := db.Get("key") | ||
if err != nil { | ||
// Handle error | ||
} | ||
*/ | ||
package cache | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/madflojo/hord" | ||
"github.com/madflojo/hord/drivers/cache/lookaside" | ||
) | ||
|
||
// CacheType is the type of cache to use. | ||
type Type string | ||
|
||
const ( | ||
Lookaside Type = "lookaside" | ||
None Type = "none" | ||
) | ||
|
||
// Config provides the configuration options for the Cache driver. | ||
type Config struct { | ||
Type Type | ||
Database hord.Database | ||
Cache hord.Database | ||
} | ||
|
||
// NilCache is a nil cache driver that returns dial errors. It fixes the issue when the Dial function returns a nil hord.Database this prevents nil pointer errors. | ||
type NilCache struct{} | ||
|
||
var ( | ||
// ErrNoType is returned when the CacheType is invalid. | ||
ErrNoType = errors.New("invalid CacheType") | ||
) | ||
|
||
// Dial will create a new Cache driver using the provided Config. It will return an error if either the Database or Cache values in Config are nil or if a CacheType is not specified. | ||
func Dial(cfg Config) (hord.Database, error) { | ||
if (cfg.Database == nil) || (cfg.Cache == nil) { | ||
return &NilCache{}, hord.ErrInvalidDatabase | ||
} | ||
|
||
switch cfg.Type { | ||
case Lookaside: | ||
return lookaside.Dial(lookaside.Config{ | ||
Database: cfg.Database, | ||
Cache: cfg.Cache, | ||
}) | ||
case None: | ||
return cfg.Database, nil | ||
default: | ||
return &NilCache{}, ErrNoType | ||
} | ||
} | ||
|
||
func (nc *NilCache) Setup() error { | ||
return hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) HealthCheck() error { | ||
return hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) Get(_ string) ([]byte, error) { | ||
return nil, hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) Set(_ string, _ []byte) error { | ||
return hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) Delete(_ string) error { | ||
return hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) Keys() ([]string, error) { | ||
return nil, hord.ErrNoDial | ||
} | ||
|
||
func (nc *NilCache) Close() { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package cache | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"github.com/madflojo/hord" | ||
"github.com/madflojo/hord/drivers/mock" | ||
) | ||
|
||
func TestDial(t *testing.T) { | ||
unitTests := map[string]struct { | ||
config Config | ||
expectedError error | ||
}{ | ||
"No Config": { | ||
config: Config{}, | ||
expectedError: hord.ErrInvalidDatabase, | ||
}, | ||
"No Database": { | ||
config: Config{ | ||
Cache: &mock.Database{}, | ||
}, | ||
expectedError: hord.ErrInvalidDatabase, | ||
}, | ||
"No Cache": { | ||
config: Config{ | ||
Database: &mock.Database{}, | ||
}, | ||
expectedError: hord.ErrInvalidDatabase, | ||
}, | ||
"Invalid Type": { | ||
config: Config{ | ||
Type: "invalid", | ||
Database: &mock.Database{}, | ||
Cache: &mock.Database{}, | ||
}, | ||
expectedError: ErrNoType, | ||
}, | ||
"Type: Lookaside": { | ||
config: Config{ | ||
Type: Lookaside, | ||
Database: &mock.Database{}, | ||
Cache: &mock.Database{}, | ||
}, | ||
expectedError: nil, | ||
}, | ||
"Type: None": { | ||
config: Config{ | ||
Type: None, | ||
Database: &mock.Database{}, | ||
Cache: &mock.Database{}, | ||
}, | ||
expectedError: nil, | ||
}, | ||
} | ||
|
||
for name, test := range unitTests { | ||
t.Run(name, func(t *testing.T) { | ||
_, err := Dial(test.config) | ||
if !errors.Is(err, test.expectedError) { | ||
t.Errorf("Dial(%v) returned error: %s, expected %s", test.config, err, test.expectedError) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestNilCache(t *testing.T) { | ||
nc := &NilCache{} | ||
if err := nc.Setup(); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.Setup() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
if err := nc.HealthCheck(); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.HealthCheck() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
if _, err := nc.Get(""); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.Get() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
if err := nc.Set("", nil); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.Set() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
if err := nc.Delete(""); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.Delete() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
if _, err := nc.Keys(); !errors.Is(err, hord.ErrNoDial) { | ||
t.Errorf("NilCache.Keys() returned error: %s, expected %s", err, hord.ErrNoDial) | ||
} | ||
nc.Close() | ||
} |
Oops, something went wrong.