package service import ( "context" "encoding/json" "time" "go.uber.org/zap" "github.com/dbiz/cdp/data-layer/api/internal/apperr" "github.com/dbiz/cdp/data-layer/api/internal/cache" "github.com/dbiz/cdp/data-layer/api/internal/model" "github.com/dbiz/cdp/data-layer/api/internal/repo" ) type ProfileService struct { profiles *repo.ProfileRepo events *repo.EventRepo cache *cache.Cache profileTTL time.Duration log *zap.Logger } func NewProfileService(p *repo.ProfileRepo, e *repo.EventRepo, c *cache.Cache, profileTTL time.Duration, log *zap.Logger) *ProfileService { return &ProfileService{profiles: p, events: e, cache: c, profileTTL: profileTTL, log: log} } func (s *ProfileService) Get(ctx context.Context, workspaceID, profileID string) (*model.Profile, error) { key, err := cache.Key("profile", workspaceID, profileID) if err != nil { return nil, apperr.Internal(err) } if b, ok := s.cache.Get(ctx, key); ok { var p model.Profile if jerr := json.Unmarshal(b, &p); jerr == nil { return &p, nil } } p, err := s.profiles.GetByID(ctx, workspaceID, profileID) if err != nil { return nil, err } if b, jerr := json.Marshal(p); jerr == nil { if cerr := s.cache.Set(ctx, key, b, s.profileTTL); cerr != nil { s.log.Warn("cache set", zap.String("key", key), zap.Error(cerr)) } } return p, nil } func (s *ProfileService) Timeline(ctx context.Context, workspaceID, profileID string, limit, offset int) (*model.QueryResult, error) { uid, err := s.profiles.GetUserIDForProfile(ctx, workspaceID, profileID) if err != nil { return nil, err } if uid == "" { return nil, apperr.NotFound("profile has no user_id and cannot be timelined") } start := time.Now() res, err := s.events.QueryProfileTimeline(ctx, workspaceID, uid, limit, offset) if err != nil { return nil, apperr.Internal(err) } res.DurationMS = time.Since(start).Milliseconds() return res, nil }