Skip to main content

Local Scan Request Cache Documentation

This code implements a local in-memory cache for attendance scan requests and their approvals, aiming to optimize performance by reducing database reads.

LocalScanRequest struct

type LocalScanRequest struct {
wg sync.WaitGroup
mtx sync.Mutex
dao *daos.Dao

ScanRequest []entity.AttendanceRequestTable
IndexedScanRequest map[string]*entity.AttendanceRequestTable
ScanRequestRead bool

ScanRequestApproval []entity.AttendanceRequestApprovalTable
MapScanRequestApproval map[string][]*entity.AttendanceRequestApprovalTable // key = ScanRequest.ID
ScanRequestApprovalRead bool

StartDate time.Time // for read again
EndDate time.Time // for read again
CompanyID string // for read again
}
  • wg sync.WaitGroup: Manages asynchronous database operations.
  • mtx sync.Mutex: Ensures thread-safe access to the cache.
  • dao *daos.Dao: The PocketBase DAO.
  • ScanRequest []entity.AttendanceRequestTable: Slice of scan requests.
  • IndexedScanRequest map[string]*entity.AttendanceRequestTable: Scan requests indexed by ID.
  • ScanRequestRead bool: Indicates if scan requests have been read from the database.
  • ScanRequestApproval []entity.AttendanceRequestApprovalTable: Slice of scan request approvals.
  • MapScanRequestApproval map[string][]*entity.AttendanceRequestApprovalTable: Approvals mapped by scan request ID.
  • ScanRequestApprovalRead bool: Indicates if scan request approvals have been read.
  • StartDate time.Time: The start date of the cached range.
  • EndDate time.Time: The end date of the cached range.
  • CompanyID string: The company ID for which data is cached.

globalLocalScanRequest Variable

var globalLocalScanRequest = LocalScanRequest{}

A global instance of LocalScanRequest (singleton pattern).

Functions

NewScanRequestCache(dao *daos.Dao, companyID, calcDate string, read bool) *LocalScanRequest

Creates a new LocalScanRequest instance.

  • dao: The PocketBase DAO.
  • companyID: The company ID.
  • calcDate: The calculation date.
  • read: If true, reads data from the database immediately.

GetGlobalScanRequest() *LocalScanRequest

Returns the global LocalScanRequest instance.

SetDao(dao *daos.Dao) *LocalScanRequest

Sets the DAO for the instance.

GetDao() *daos.Dao

Gets the DAO for the instance.

WaitFinishReadDB()

Waits for asynchronous database operations to complete.

ResetMaps(request, approval bool)

Clears the specified cache maps (requests and/or approvals) to avoid memory leaks.

IsCompanyDateInCache(companyID, calcDate string) bool

Checks if the specified company ID and date are within the cached range.

ReadAgain(companyID, calcDate string, force bool) *LocalScanRequest

Reloads data from the database if force is true, if the date is outside the cached range, or if data hasn't been read yet.

ReadAllScanRequests(companyID string, calcDate string)

Reads all scan requests and their approvals for the specified company and date range from the database, populating the cache.

FindScanRequestByUserIDAndDate(userID, calcDate string) []*entity.AttendanceRequestTable

Finds scan requests by user ID and date.

Example Usage

dao := // ... obtain your PocketBase DAO
companyID := "your_company_id"
calcDate := "2024-05-01"

// Create a new ScanRequestCache and immediately read data
scanRequestCache := caching.NewScanRequestCache(dao, companyID, calcDate, true)

// Find scan requests by user ID and date
userScanRequests := scanRequestCache.FindScanRequestByUserIDAndDate("user_id_123", "2024-05-10")

// Force a cache refresh
scanRequestCache.ReadAgain(companyID, calcDate, true)

Improvements and Considerations

  • Error Handling: Improve error handling in functions like ReadAllScanRequests by returning errors instead of just logging them.
  • Cache Invalidation: Implement a proper cache invalidation strategy (time-based or event-driven) to ensure data consistency.
  • Singleton Pattern: Evaluate the use of the singleton pattern (globalLocalScanRequest). Dependency injection offers better testability and flexibility.
  • Code Clarity and Comments: Improve code comments to explain complex logic more clearly.
  • Locking Granularity: Finer-grained locking (e.g., separate mutexes for requests and approvals) could improve concurrency.

This comprehensive documentation provides a detailed understanding of the LocalScanRequest cache and its functionalities. By addressing the suggested improvements, you can create a more robust and maintainable caching solution.