Local Shifts Cache Documentation
This code implements a local in-memory cache for shifts, rules, breaks, and their relationships, aiming to speed up processing by reducing database reads.
LocalShifts
Struct
type LocalShifts struct {
wg sync.WaitGroup
mtx SafeMutex
dao *daos.Dao
Shifts []entity.ShiftTable
ShiftsRead bool
IndexedShifts map[string]*entity.ShiftTable // key = shiftID
ShiftsMapped bool
ShiftsMapByShortLabel map[string]*entity.ShiftTable // Key = short_label
ShiftsMappedByShortLabel bool
Rules []entity.RuleTable
RulesRead bool
RulesMap map[string]*entity.RuleTable
RulesMapped bool
RuleUses []entity.RuleUseTable
RulesUseRead bool
RuleUsesMap map[string]*entity.RuleUseTable
RuleUsesMapped bool
RuleDetails []entity.RuleDetailTable
RulesDetailsRead bool
RuleDetailsMap map[string]*entity.RuleDetailTable
RulesDetailsMapped bool
RuleDetailsMapByRuleID map[string][]*entity.RuleDetailTable // key = rule_id
RulesDetailsMappedByRuleID bool
ShiftBreaks []entity.ShiftBreakTable
ShiftBreaksRead bool
ShiftBreakMap map[string]*entity.ShiftBreakTable
ShiftBreaksMapped bool
Breaks []entity.BreakTable
BreaksRead bool
BreaksMap map[string]*entity.BreakTable // key = breaks_id
BreaksMapped bool
BreaksMapByShiftID map[string][]*entity.BreakTable // key = shift_id
BreaksMappedByShiftID bool // already mapped
CompanyID string
}
wg sync.WaitGroup
: Waits for asynchronous database operations.mtx SafeMutex
: A mutex for thread-safe access. (Likely adds safety checks beyond a standard mutex.)dao *daos.Dao
: The PocketBase DAO.Shifts []entity.ShiftTable
: Slice of all shifts.ShiftsRead bool
: Flag indicating if shifts have been read.IndexedShifts map[string]*entity.ShiftTable
: Shifts indexed by ID.ShiftsMapped bool
: Flag if shifts have been mapped toIndexedShifts
.ShiftsMapByShortLabel map[string]*entity.ShiftTable
: Shifts indexed by short label.ShiftsMappedByShortLabel bool
: Flag if shifts have been mapped toShiftsMapByShortLabel
.Rules
,RulesRead
,RulesMap
,RulesMapped
: Similar structure for rules.RuleUses
,RulesUseRead
,RuleUsesMap
,RuleUsesMapped
: Similar structure for rule uses.RuleDetails
,RulesDetailsRead
,RuleDetailsMap
,RulesDetailsMapped
,RuleDetailsMapByRuleID
,RulesDetailsMappedByRuleID
: Structure for rule details, including a map by rule ID.ShiftBreaks
,ShiftBreaksRead
,ShiftBreakMap
,ShiftBreaksMapped
: Structure for shift breaks.Breaks
,BreaksRead
,BreaksMap
,BreaksMapped
,BreaksMapByShiftID
,BreaksMappedByShiftID
: Structure for breaks, including a map by shift ID.CompanyID string
: The company ID.
globalLocalShifts
variable
var globalLocalShifts = LocalShifts{}
A global instance of LocalShifts
(singleton pattern).
Functions
NewShiftsCache(dao *daos.Dao, companyID string, read bool) *LocalShifts
Creates a new LocalShifts
instance.
dao
: The PocketBase DAO.companyID
: The company ID.read
: If true, reads data from the database immediately.
GetGlobalLocalShifts() *LocalShifts
Returns the global LocalShifts
instance.
SetDao(dao *daos.Dao) *LocalShifts
Sets the DAO for the LocalShifts
instance.
GetDao() *daos.Dao
Gets the DAO associated with the instance.
WaitFinishReadDB()
Waits for asynchronous database operations to complete.
ReadAgain(companyID string, force bool) *LocalShifts
Reads data from the database again if force
is true or if data hasn't been read yet. Also reads again if the companyID
has changed.
ReadAllShiftsWithRulesAndBreaks(companyID string)
Reads all shift-related data (shifts, rules, breaks, etc.) for the given companyID
from the database and populates the cache. This function performs the database reads asynchronously and maps the relationships between shifts, rules, and breaks.
MapShiftsByShortLabel()
Creates a map of shifts keyed by their short labels if it hasn't already been created.
FindShiftByShortLabel(shortLabel string) *entity.ShiftTable
Finds a shift by its short label. Returns nil
if not found.
GetShiftByID(shiftID string) *entity.ShiftTable
Retrieves a shift by its ID from the cache. Returns nil
if not found.
GetAllShifts() []entity.ShiftTable
Returns all cached shifts. Reads from the database if the cache is empty.
FindShiftByID(shiftID string) *entity.ShiftTable
Finds a shift by its ID. Returns nil
if not found. (This function seems redundant, as GetShiftByID
does the same thing.)
Example Usage
dao := // ... obtain your PocketBase DAO
companyID := "your_company_id"
// Create a new ShiftsCache and read data immediately
shiftsCache := caching.NewShiftsCache(dao, companyID, true)
// Get all shifts
allShifts := shiftsCache.GetAllShifts()
// Find a shift by ID
shift := shiftsCache.GetShiftByID("shift_id_123")
// Find a shift by short label
shift := shiftsCache.FindShiftByShortLabel("SL-A")
// Force a cache refresh
shiftsCache.ReadAgain(companyID, true)
Improvements and Considerations
- Error Handling:
ReadAllShiftsWithRulesAndBreaks
could benefit from returning errors instead of just logging them, allowing calling code to handle errors more gracefully. - Cache Invalidation: The cache currently lacks an invalidation mechanism. Implement time-based or event-driven invalidation to ensure data freshness.
- Singleton Pattern: Evaluate the singleton pattern (
globalLocalShifts
). Dependency injection can provide better testability and flexibility. - Redundant
FindShiftByID
: Remove the seemingly redundantFindShiftByID
function. SafeMutex
: Document the specific safety features provided bySafeMutex
.- Locking Granularity: Consider more granular locking (e.g., separate mutexes for shifts, rules, and breaks) for improved concurrency.
This enhanced documentation provides a detailed overview of the LocalShifts
cache and its functionalities. By understanding its structure and usage, developers can efficiently use the cache to optimize their application. Addressing the suggested improvements will further enhance the cache's robustness and maintainability.