Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
148
cloud/maplefile-backend/internal/repo/storageusageevent/get.go
Normal file
148
cloud/maplefile-backend/internal/repo/storageusageevent/get.go
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
// monorepo/cloud/maplefile-backend/internal/maplefile/repo/storageusageevent/get.go
|
||||
package storageusageevent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storageusageevent"
|
||||
)
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetByUserAndDay(ctx context.Context, userID gocql.UUID, eventDay time.Time) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
// Ensure event day is truncated to date only
|
||||
eventDay = eventDay.Truncate(24 * time.Hour)
|
||||
|
||||
query := `SELECT user_id, event_day, event_time, file_size, operation
|
||||
FROM maplefile.storage_usage_events_by_user_id_and_event_day_with_asc_event_time
|
||||
WHERE user_id = ? AND event_day = ?`
|
||||
|
||||
iter := impl.Session.Query(query, userID, eventDay).WithContext(ctx).Iter()
|
||||
|
||||
var events []*storageusageevent.StorageUsageEvent
|
||||
var (
|
||||
resultUserID gocql.UUID
|
||||
resultEventDay time.Time
|
||||
eventTime time.Time
|
||||
fileSize int64
|
||||
operation string
|
||||
)
|
||||
|
||||
for iter.Scan(&resultUserID, &resultEventDay, &eventTime, &fileSize, &operation) {
|
||||
event := &storageusageevent.StorageUsageEvent{
|
||||
UserID: resultUserID,
|
||||
EventDay: resultEventDay,
|
||||
EventTime: eventTime,
|
||||
FileSize: fileSize,
|
||||
Operation: operation,
|
||||
}
|
||||
events = append(events, event)
|
||||
}
|
||||
|
||||
if err := iter.Close(); err != nil {
|
||||
impl.Logger.Error("failed to get storage usage events by user and day", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to get storage usage events: %w", err)
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetByUserDateRange(ctx context.Context, userID gocql.UUID, startDay, endDay time.Time) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
// Ensure dates are truncated to date only
|
||||
startDay = startDay.Truncate(24 * time.Hour)
|
||||
endDay = endDay.Truncate(24 * time.Hour)
|
||||
|
||||
// For better performance with large date ranges, we'll query in parallel
|
||||
var allEvents []*storageusageevent.StorageUsageEvent
|
||||
eventsChan := make(chan []*storageusageevent.StorageUsageEvent)
|
||||
errorsChan := make(chan error)
|
||||
|
||||
// Calculate number of days
|
||||
days := int(endDay.Sub(startDay).Hours()/24) + 1
|
||||
|
||||
// Query each day in parallel (limit concurrency to avoid overwhelming Cassandra)
|
||||
concurrency := 10
|
||||
if days < concurrency {
|
||||
concurrency = days
|
||||
}
|
||||
|
||||
semaphore := make(chan struct{}, concurrency)
|
||||
daysProcessed := 0
|
||||
|
||||
for day := startDay; !day.After(endDay); day = day.Add(24 * time.Hour) {
|
||||
semaphore <- struct{}{}
|
||||
daysProcessed++
|
||||
|
||||
go func(queryDay time.Time) {
|
||||
defer func() { <-semaphore }()
|
||||
|
||||
events, err := impl.GetByUserAndDay(ctx, userID, queryDay)
|
||||
if err != nil {
|
||||
errorsChan <- err
|
||||
return
|
||||
}
|
||||
eventsChan <- events
|
||||
}(day)
|
||||
}
|
||||
|
||||
// Collect results
|
||||
var firstError error
|
||||
for i := 0; i < daysProcessed; i++ {
|
||||
select {
|
||||
case events := <-eventsChan:
|
||||
allEvents = append(allEvents, events...)
|
||||
case err := <-errorsChan:
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
if firstError != nil {
|
||||
impl.Logger.Error("failed to get events for date range",
|
||||
zap.Error(firstError),
|
||||
zap.Int("days_requested", days))
|
||||
return allEvents, firstError // Return partial results
|
||||
}
|
||||
|
||||
return allEvents, nil
|
||||
}
|
||||
|
||||
// Convenience methods for trend analysis
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetLast7DaysEvents(ctx context.Context, userID gocql.UUID) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
endDay := time.Now().Truncate(24 * time.Hour)
|
||||
startDay := endDay.Add(-6 * 24 * time.Hour) // 7 days including today
|
||||
|
||||
return impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
||||
}
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetLastNDaysEvents(ctx context.Context, userID gocql.UUID, days int) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
if days <= 0 {
|
||||
return nil, fmt.Errorf("days must be positive")
|
||||
}
|
||||
|
||||
endDay := time.Now().Truncate(24 * time.Hour)
|
||||
startDay := endDay.Add(-time.Duration(days-1) * 24 * time.Hour)
|
||||
|
||||
return impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
||||
}
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetMonthlyEvents(ctx context.Context, userID gocql.UUID, year int, month time.Month) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
startDay := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDay := startDay.AddDate(0, 1, -1) // Last day of the month
|
||||
|
||||
return impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
||||
}
|
||||
|
||||
func (impl *storageUsageEventRepositoryImpl) GetYearlyEvents(ctx context.Context, userID gocql.UUID, year int) ([]*storageusageevent.StorageUsageEvent, error) {
|
||||
startDay := time.Date(year, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
endDay := time.Date(year, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
|
||||
return impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue