refactor: scanAndCount - use channel to synchronize data with the main goroutine
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dawid Wysokiński 2022-12-24 09:10:04 +01:00
parent f636d6ac94
commit def3161957
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892

View File

@ -46,44 +46,60 @@ func sortDirectionToString(sd domain.SortDirection) (string, error) {
return "", fmt.Errorf("%w: %d", domain.ErrUnsupportedSortDirection, sd)
}
type scanAndCountResult struct {
count int
err error
}
func scanAndCount(
ctx context.Context,
countQ *bun.SelectQuery,
scanQ *bun.SelectQuery,
) (int, error) {
var wg sync.WaitGroup
var mu sync.Mutex
ch := make(chan scanAndCountResult)
wg.Add(1)
go func() {
defer wg.Done()
count, err := countQ.Count(ctx)
if err != nil {
ch <- scanAndCountResult{err: err}
return
}
ch <- scanAndCountResult{count: count}
}()
wg.Add(1)
go func() {
defer wg.Done()
if err := scanQ.Scan(ctx); err != nil {
ch <- scanAndCountResult{err: err}
}
}()
go func() {
wg.Wait()
close(ch)
}()
var count int
var err error
var firstErr error
wg.Add(1)
go func() {
defer wg.Done()
var countErr error
if count, countErr = countQ.Count(ctx); countErr != nil {
mu.Lock()
if err == nil {
err = countErr
}
mu.Unlock()
for res := range ch {
if firstErr == nil && res.err != nil {
firstErr = res.err
continue
}
}()
wg.Add(1)
go func() {
defer wg.Done()
count = res.count
}
if scanErr := scanQ.Scan(ctx); scanErr == nil {
mu.Lock()
if err == nil {
err = scanErr
}
mu.Unlock()
}
}()
if firstErr != nil {
return 0, firstErr
}
wg.Wait()
return count, err
return count, nil
}