Files
cloud-services/pkg/cache/drivers.go

142 lines
3.4 KiB
Go

package cache
import (
"fiskerinc.com/modules/common"
"fiskerinc.com/modules/db/queries"
"fiskerinc.com/modules/logger"
"fiskerinc.com/modules/redis"
"github.com/pkg/errors"
)
func NewDriversCache(redisClient redis.ClientPoolInterface, cars queries.CarsInterface) *DriversCache {
return &DriversCache{
redisClientPool: redisClient,
cars: cars,
}
}
type DriversCache struct {
redisClientPool redis.ClientPoolInterface
cars queries.CarsInterface
}
func (dc *DriversCache) RedisClientPool() redis.ClientPoolInterface {
return dc.redisClientPool
}
func (dc *DriversCache) Cars() queries.CarsInterface {
return dc.cars
}
func (dc *DriversCache) hasCachedNoDrivers(drivers []string) bool {
// Redis will return []string{""} for no drivers
return len(drivers) == 1 && len(drivers[0]) == 0
}
func (dc *DriversCache) cacheDrivers(key string, drivers []string) error {
client := dc.redisClientPool.GetFromPool()
defer client.Close()
// cache driver IDs
if len(drivers) > 0 {
return client.NewSet(key, drivers, redisObjectExpire)
}
// Redis will not take an empty array as an arg
return client.NewSet(key, nil, redisObjectExpire)
}
// RetrieveDriverIDs retrieves IDs from redis or from DB and proceeds to cache both the drivers and IDs
// redis keys:
//
// car:<VIN>:drivers
func (dc *DriversCache) RetrieveDriverIDs(vin string) ([]string, error) {
var driverIDs []string
driverIDsKey := redis.CarToAllDriversKey(vin)
// retrieve IDs from redis
client := dc.redisClientPool.GetFromPool()
err := client.GetSet(driverIDsKey, &driverIDs)
if err != nil {
logger.Warn().Err(err).Send()
}
client.Close()
if dc.hasCachedNoDrivers(driverIDs) {
return []string{}, nil
}
if len(driverIDs) > 0 {
return driverIDs, nil
}
// if IDs not present in redis perform DB lookup
var drivers []common.CarToDriver
drivers, err = dc.cars.GetDrivers(vin)
if err != nil {
return nil, err
}
for _, driver := range drivers {
driverIDs = append(driverIDs, driver.DriverID)
}
err = dc.cacheDrivers(driverIDsKey, driverIDs)
if err != nil {
return driverIDs, err
}
return driverIDs, nil
}
// RetrieveDriverIDsAsSet retrieves IDs from redis or from DB and proceeds to cache both the drivers and IDs
// redis keys:
//
// car:<VIN>:drivers
func (dc *DriversCache) RetrieveDriverIDsAsSet(vin string) (map[string]struct{}, error) {
driverIDs, err := dc.RetrieveDriverIDs(vin)
if err != nil {
return nil, err
}
var dIDsSet = make(map[string]struct{})
for _, did := range driverIDs {
dIDsSet[did] = struct{}{}
}
return dIDsSet, nil
}
func (dc *DriversCache) IsDriverOfVIN(vin string, driverid string) (bool, error) {
ids, err := dc.RetrieveDriverIDs(vin)
if err != nil {
return false, err
}
for _, id := range ids {
if id == driverid {
return true, nil
}
}
return false, dc.NotDriverError(vin, driverid)
}
// Add driver to database and cache
func (dc *DriversCache) AddDriver(car *common.Car, driver *common.Driver, role string) (*common.CarToDriver, error) {
relation, err := dc.cars.AddDriver(car, driver, role)
if err != nil {
return nil, err
}
driverIDsKey := redis.CarToAllDriversKey(car.VIN)
client := dc.redisClientPool.GetFromPool()
defer client.Close()
client.AddToSet(driverIDsKey, driver.ID, redisObjectExpire)
return relation, nil
}
func (dc DriversCache) NotDriverError(vin string, driverid string) error {
return errors.Errorf("id %s is not a driver for vin %v", driverid, vin)
}