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

137 lines
3.3 KiB
Go

package cachev2
import (
"github.com/fiskerinc/cloud-services/pkg/common"
"github.com/fiskerinc/cloud-services/pkg/db/queries"
"github.com/fiskerinc/cloud-services/pkg/logger"
redis "github.com/fiskerinc/cloud-services/pkg/redisv2"
"github.com/pkg/errors"
)
func NewDriversCache(redisClient redis.ClientInterface, cars queries.CarsInterface) *DriversCache {
return &DriversCache{
redisClient: redisClient,
cars: cars,
}
}
type DriversCache struct {
redisClient redis.ClientInterface
cars queries.CarsInterface
}
func (dc *DriversCache) RedisClientPool() redis.ClientInterface {
return dc.redisClient
}
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 {
// cache driver IDs
if len(drivers) > 0 {
return dc.redisClient.NewSet(key, drivers, redisObjectExpire)
}
// Redis will not take an empty array as an arg
return nil
}
// 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
err := dc.redisClient.GetSet(driverIDsKey, &driverIDs)
if err != nil {
logger.Warn().Err(err).Send()
return []string{}, err
}
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)
dc.redisClient.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)
}