221 lines
7.1 KiB
Go
221 lines
7.1 KiB
Go
// monorepo/cloud/maplefile-backend/internal/maplefile/repo/storagedailyusage/get.go
|
|
package storagedailyusage
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/gocql/gocql"
|
|
"go.uber.org/zap"
|
|
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/storagedailyusage"
|
|
)
|
|
|
|
func (impl *storageDailyUsageRepositoryImpl) GetByUserAndDay(ctx context.Context, userID gocql.UUID, usageDay time.Time) (*storagedailyusage.StorageDailyUsage, error) {
|
|
// Ensure usage day is truncated to date only
|
|
usageDay = usageDay.Truncate(24 * time.Hour)
|
|
|
|
var (
|
|
resultUserID gocql.UUID
|
|
resultUsageDay time.Time
|
|
totalBytes int64
|
|
totalAddBytes int64
|
|
totalRemoveBytes int64
|
|
)
|
|
|
|
query := `SELECT user_id, usage_day, total_bytes, total_add_bytes, total_remove_bytes
|
|
FROM maplefile.storage_daily_usage_by_user_id_with_asc_usage_day
|
|
WHERE user_id = ? AND usage_day = ?`
|
|
|
|
err := impl.Session.Query(query, userID, usageDay).WithContext(ctx).Scan(
|
|
&resultUserID, &resultUsageDay, &totalBytes, &totalAddBytes, &totalRemoveBytes)
|
|
|
|
if err == gocql.ErrNotFound {
|
|
return nil, nil
|
|
}
|
|
|
|
if err != nil {
|
|
impl.Logger.Error("failed to get storage daily usage", zap.Error(err))
|
|
return nil, fmt.Errorf("failed to get storage daily usage: %w", err)
|
|
}
|
|
|
|
usage := &storagedailyusage.StorageDailyUsage{
|
|
UserID: resultUserID,
|
|
UsageDay: resultUsageDay,
|
|
TotalBytes: totalBytes,
|
|
TotalAddBytes: totalAddBytes,
|
|
TotalRemoveBytes: totalRemoveBytes,
|
|
}
|
|
|
|
return usage, nil
|
|
}
|
|
|
|
func (impl *storageDailyUsageRepositoryImpl) GetByUserDateRange(ctx context.Context, userID gocql.UUID, startDay, endDay time.Time) ([]*storagedailyusage.StorageDailyUsage, error) {
|
|
// Ensure dates are truncated to date only
|
|
startDay = startDay.Truncate(24 * time.Hour)
|
|
endDay = endDay.Truncate(24 * time.Hour)
|
|
|
|
query := `SELECT user_id, usage_day, total_bytes, total_add_bytes, total_remove_bytes
|
|
FROM maplefile.storage_daily_usage_by_user_id_with_asc_usage_day
|
|
WHERE user_id = ? AND usage_day >= ? AND usage_day <= ?`
|
|
|
|
iter := impl.Session.Query(query, userID, startDay, endDay).WithContext(ctx).Iter()
|
|
|
|
var usages []*storagedailyusage.StorageDailyUsage
|
|
var (
|
|
resultUserID gocql.UUID
|
|
resultUsageDay time.Time
|
|
totalBytes int64
|
|
totalAddBytes int64
|
|
totalRemoveBytes int64
|
|
)
|
|
|
|
for iter.Scan(&resultUserID, &resultUsageDay, &totalBytes, &totalAddBytes, &totalRemoveBytes) {
|
|
usage := &storagedailyusage.StorageDailyUsage{
|
|
UserID: resultUserID,
|
|
UsageDay: resultUsageDay,
|
|
TotalBytes: totalBytes,
|
|
TotalAddBytes: totalAddBytes,
|
|
TotalRemoveBytes: totalRemoveBytes,
|
|
}
|
|
usages = append(usages, usage)
|
|
}
|
|
|
|
if err := iter.Close(); err != nil {
|
|
impl.Logger.Error("failed to get storage daily usage by date range", zap.Error(err))
|
|
return nil, fmt.Errorf("failed to get storage daily usage: %w", err)
|
|
}
|
|
|
|
return usages, nil
|
|
}
|
|
|
|
// GetLast7DaysTrend retrieves the last 7 days of storage usage and calculates trends
|
|
func (impl *storageDailyUsageRepositoryImpl) GetLast7DaysTrend(ctx context.Context, userID gocql.UUID) (*storagedailyusage.StorageUsageTrend, error) {
|
|
endDay := time.Now().Truncate(24 * time.Hour)
|
|
startDay := endDay.Add(-6 * 24 * time.Hour) // 7 days including today
|
|
|
|
usages, err := impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return impl.calculateTrend(userID, startDay, endDay, usages), nil
|
|
}
|
|
|
|
// GetMonthlyTrend retrieves usage trend for a specific month
|
|
func (impl *storageDailyUsageRepositoryImpl) GetMonthlyTrend(ctx context.Context, userID gocql.UUID, year int, month time.Month) (*storagedailyusage.StorageUsageTrend, error) {
|
|
startDay := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
|
|
endDay := startDay.AddDate(0, 1, -1) // Last day of the month
|
|
|
|
usages, err := impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return impl.calculateTrend(userID, startDay, endDay, usages), nil
|
|
}
|
|
|
|
// GetYearlyTrend retrieves usage trend for a specific year
|
|
func (impl *storageDailyUsageRepositoryImpl) GetYearlyTrend(ctx context.Context, userID gocql.UUID, year int) (*storagedailyusage.StorageUsageTrend, 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)
|
|
|
|
usages, err := impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return impl.calculateTrend(userID, startDay, endDay, usages), nil
|
|
}
|
|
|
|
// GetCurrentMonthUsage gets the current month's usage summary
|
|
func (impl *storageDailyUsageRepositoryImpl) GetCurrentMonthUsage(ctx context.Context, userID gocql.UUID) (*storagedailyusage.StorageUsageSummary, error) {
|
|
now := time.Now()
|
|
startDay := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
|
|
endDay := now.Truncate(24 * time.Hour)
|
|
|
|
usages, err := impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return impl.calculateSummary(userID, "month", startDay, endDay, usages), nil
|
|
}
|
|
|
|
// GetCurrentYearUsage gets the current year's usage summary
|
|
func (impl *storageDailyUsageRepositoryImpl) GetCurrentYearUsage(ctx context.Context, userID gocql.UUID) (*storagedailyusage.StorageUsageSummary, error) {
|
|
now := time.Now()
|
|
startDay := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
|
|
endDay := now.Truncate(24 * time.Hour)
|
|
|
|
usages, err := impl.GetByUserDateRange(ctx, userID, startDay, endDay)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return impl.calculateSummary(userID, "year", startDay, endDay, usages), nil
|
|
}
|
|
|
|
// Helper methods
|
|
|
|
func (impl *storageDailyUsageRepositoryImpl) calculateTrend(userID gocql.UUID, startDay, endDay time.Time, usages []*storagedailyusage.StorageDailyUsage) *storagedailyusage.StorageUsageTrend {
|
|
trend := &storagedailyusage.StorageUsageTrend{
|
|
UserID: userID,
|
|
StartDate: startDay,
|
|
EndDate: endDay,
|
|
DailyUsages: usages,
|
|
}
|
|
|
|
if len(usages) == 0 {
|
|
return trend
|
|
}
|
|
|
|
var peakDay time.Time
|
|
var peakBytes int64
|
|
|
|
for _, usage := range usages {
|
|
trend.TotalAdded += usage.TotalAddBytes
|
|
trend.TotalRemoved += usage.TotalRemoveBytes
|
|
|
|
if usage.TotalBytes > peakBytes {
|
|
peakBytes = usage.TotalBytes
|
|
peakDay = usage.UsageDay
|
|
}
|
|
}
|
|
|
|
trend.NetChange = trend.TotalAdded - trend.TotalRemoved
|
|
if len(usages) > 0 {
|
|
trend.AverageDailyAdd = trend.TotalAdded / int64(len(usages))
|
|
trend.PeakUsageDay = &peakDay
|
|
trend.PeakUsageBytes = peakBytes
|
|
}
|
|
|
|
return trend
|
|
}
|
|
|
|
func (impl *storageDailyUsageRepositoryImpl) calculateSummary(userID gocql.UUID, period string, startDay, endDay time.Time, usages []*storagedailyusage.StorageDailyUsage) *storagedailyusage.StorageUsageSummary {
|
|
summary := &storagedailyusage.StorageUsageSummary{
|
|
UserID: userID,
|
|
Period: period,
|
|
StartDate: startDay,
|
|
EndDate: endDay,
|
|
DaysWithData: len(usages),
|
|
}
|
|
|
|
if len(usages) == 0 {
|
|
return summary
|
|
}
|
|
|
|
// Get the most recent usage as current
|
|
summary.CurrentUsage = usages[len(usages)-1].TotalBytes
|
|
|
|
for _, usage := range usages {
|
|
summary.TotalAdded += usage.TotalAddBytes
|
|
summary.TotalRemoved += usage.TotalRemoveBytes
|
|
}
|
|
|
|
summary.NetChange = summary.TotalAdded - summary.TotalRemoved
|
|
|
|
return summary
|
|
}
|